Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602/* * ReactOS kernel * Copyright (C) 2017 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *//* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: sdk/lib/drivers/rdbsslib/rdbss.c * PURPOSE: RDBSS library * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org) */
/* INCLUDES *****************************************************************/
#include <rx.h>#include <pseh/pseh2.h>#include <limits.h>#include <dfs.h>#include <copysup.h>
#define NDEBUG#include <debug.h>
#define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
typedefNTSTATUS(NTAPI *PRX_FSD_DISPATCH) ( PRX_CONTEXT Context);
typedef struct _RX_FSD_DISPATCH_VECTOR{ PRX_FSD_DISPATCH CommonRoutine;} RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
VOIDNTAPIRxAcquireFileForNtCreateSection( PFILE_OBJECT FileObject);
NTSTATUSNTAPIRxAcquireForCcFlush( PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject);
VOIDRxAddToTopLevelIrpAllocatedContextsList( PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
VOIDRxAssert( PVOID Assert, PVOID File, ULONG Line, PVOID Message);
NTSTATUSNTAPIRxCommonCleanup( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonClose( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonCreate( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDevFCBCleanup( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDevFCBClose( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDevFCBFsCtl( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDevFCBIoCtl( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDevFCBQueryVolInfo( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDeviceControl( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDirectoryControl( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonDispatchProblem( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonFileSystemControl( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonFlushBuffers( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonLockControl( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonQueryEa( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonQueryInformation( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonQueryQuotaInformation( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonQuerySecurity( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonQueryVolumeInformation( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonRead( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonSetEa( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonSetInformation( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonSetQuotaInformation( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonSetSecurity( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonSetVolumeInformation( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonUnimplemented( PRX_CONTEXT Context);
NTSTATUSNTAPIRxCommonWrite( PRX_CONTEXT Context);
VOIDRxCopyCreateParameters( IN PRX_CONTEXT RxContext);
NTSTATUSRxCreateFromNetRoot( PRX_CONTEXT Context, PUNICODE_STRING NetRootName);
NTSTATUSRxCreateTreeConnect( IN PRX_CONTEXT RxContext);
BOOLEANNTAPIRxFastIoCheckIfPossible( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, BOOLEAN CheckForReadOperation, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject);
BOOLEANNTAPIRxFastIoDeviceControl( PFILE_OBJECT FileObject, BOOLEAN Wait, PVOID InputBuffer OPTIONAL, ULONG InputBufferLength, PVOID OutputBuffer OPTIONAL, ULONG OutputBufferLength, ULONG IoControlCode, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject);
BOOLEANNTAPIRxFastIoRead( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject);
BOOLEANNTAPIRxFastIoWrite( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject);
NTSTATUSRxFindOrCreateFcb( PRX_CONTEXT RxContext, PUNICODE_STRING NetRootName);
NTSTATUSRxFirstCanonicalize( PRX_CONTEXT RxContext, PUNICODE_STRING FileName, PUNICODE_STRING CanonicalName, PNET_ROOT_TYPE NetRootType);
VOIDRxFreeCanonicalNameBuffer( PRX_CONTEXT Context);
VOIDNTAPIRxFspDispatch( IN PVOID Context);
VOIDNTAPIRxGetRegistryParameters( IN PUNICODE_STRING RegistryPath);
NTSTATUSNTAPIRxGetStringRegistryParameter( IN HANDLE KeyHandle, IN PCWSTR KeyName, OUT PUNICODE_STRING OutString, IN PUCHAR Buffer, IN ULONG BufferLength, IN BOOLEAN LogFailure);
VOIDNTAPIRxInitializeDebugSupport( VOID);
VOIDNTAPIRxInitializeDispatchVectors( PDRIVER_OBJECT DriverObject);
NTSTATUSNTAPIRxInitializeRegistrationStructures( VOID);
VOIDNTAPIRxInitializeTopLevelIrpPackage( VOID);
VOIDNTAPIRxInitUnwind( PDRIVER_OBJECT DriverObject, USHORT State);
BOOLEANRxIsThisAnRdbssTopLevelContext( PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
NTSTATUSNTAPIRxLowIoIoCtlShellCompletion( PRX_CONTEXT RxContext);
NTSTATUSRxLowIoReadShell( PRX_CONTEXT RxContext);
NTSTATUSNTAPIRxLowIoReadShellCompletion( PRX_CONTEXT RxContext);
NTSTATUSRxLowIoWriteShell( IN PRX_CONTEXT RxContext);
NTSTATUSNTAPIRxLowIoWriteShellCompletion( PRX_CONTEXT RxContext);
PVOIDRxNewMapUserBuffer( PRX_CONTEXT RxContext);
NTSTATUSRxNotifyChangeDirectory( PRX_CONTEXT RxContext);
VOIDNTAPIRxpCancelRoutine( PVOID Context);
NTSTATUSRxpQueryInfoMiniRdr( PRX_CONTEXT RxContext, FILE_INFORMATION_CLASS FileInfoClass, PVOID Buffer);
VOIDRxPurgeNetFcb( PFCB Fcb, PRX_CONTEXT LocalContext);
NTSTATUSRxQueryAlternateNameInfo( PRX_CONTEXT RxContext, PFILE_NAME_INFORMATION AltNameInfo);
NTSTATUSRxQueryBasicInfo( PRX_CONTEXT RxContext, PFILE_BASIC_INFORMATION BasicInfo);
NTSTATUSRxQueryCompressedInfo( PRX_CONTEXT RxContext, PFILE_COMPRESSION_INFORMATION CompressionInfo);
NTSTATUSRxQueryDirectory( PRX_CONTEXT RxContext);
NTSTATUSRxQueryEaInfo( PRX_CONTEXT RxContext, PFILE_EA_INFORMATION EaInfo);
NTSTATUSRxQueryInternalInfo( PRX_CONTEXT RxContext, PFILE_INTERNAL_INFORMATION InternalInfo);
NTSTATUSRxQueryNameInfo( PRX_CONTEXT RxContext, PFILE_NAME_INFORMATION NameInfo);
NTSTATUSRxQueryPipeInfo( PRX_CONTEXT RxContext, PFILE_PIPE_INFORMATION PipeInfo);
NTSTATUSRxQueryPositionInfo( PRX_CONTEXT RxContext, PFILE_POSITION_INFORMATION PositionInfo);
NTSTATUSRxQueryStandardInfo( PRX_CONTEXT RxContext, PFILE_STANDARD_INFORMATION StandardInfo);
VOIDNTAPIRxReadRegistryParameters( VOID);
VOIDNTAPIRxReleaseFileForNtCreateSection( PFILE_OBJECT FileObject);
NTSTATUSNTAPIRxReleaseForCcFlush( PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject);
PRX_CONTEXTRxRemoveOverflowEntry( PRDBSS_DEVICE_OBJECT DeviceObject, WORK_QUEUE_TYPE Queue);
NTSTATUSRxSearchForCollapsibleOpen( PRX_CONTEXT RxContext, ACCESS_MASK DesiredAccess, ULONG ShareAccess);
NTSTATUSRxSetAllocationInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetBasicInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetDispositionInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetEndOfFileInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetPipeInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetPositionInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetRenameInfo( PRX_CONTEXT RxContext);
NTSTATUSRxSetSimpleInfo( PRX_CONTEXT RxContext);
VOIDRxSetupNetFileObject( PRX_CONTEXT RxContext);
NTSTATUSRxSystemControl( IN PRDBSS_DEVICE_OBJECT RxDeviceObject, IN PIRP Irp);
VOIDRxUninitializeCacheMap( PRX_CONTEXT RxContext, PFILE_OBJECT FileObject, PLARGE_INTEGER TruncateSize);
VOIDRxUnstart( PRX_CONTEXT Context, PRDBSS_DEVICE_OBJECT DeviceObject);
NTSTATUSRxXXXControlFileCallthru( PRX_CONTEXT Context);
PVOIDNTAPI_RxAllocatePoolWithTag( _In_ POOL_TYPE PoolType, _In_ SIZE_T NumberOfBytes, _In_ ULONG Tag);
VOIDNTAPI_RxFreePool( _In_ PVOID Buffer);
VOIDNTAPI_RxFreePoolWithTag( _In_ PVOID Buffer, _In_ ULONG Tag);
WCHAR RxStarForTemplate = '*';WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;BOOLEAN DisableFlushOnCleanup = FALSE;ULONG ReadAheadGranularity = 1 << PAGE_SHIFT;LIST_ENTRY RxActiveContexts;NPAGED_LOOKASIDE_LIST RxContextLookasideList;RDBSS_DATA RxData;FCB RxDeviceFCB;BOOLEAN RxLoudLowIoOpsEnabled = FALSE;RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] ={ { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDevFCBClose }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDevFCBQueryVolInfo }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDevFCBFsCtl }, { RxCommonDevFCBIoCtl }, { RxCommonDevFCBIoCtl }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDevFCBCleanup }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonDispatchProblem }, { RxCommonUnimplemented }, { RxCommonUnimplemented }, { RxCommonUnimplemented }, { RxCommonUnimplemented }, { RxCommonUnimplemented }, { RxCommonUnimplemented },};RDBSS_EXPORTS RxExports;FAST_IO_DISPATCH RxFastIoDispatch;PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] ={ { RxCommonCreate }, { RxCommonUnimplemented }, { RxCommonClose }, { RxCommonRead }, { RxCommonWrite }, { RxCommonQueryInformation }, { RxCommonSetInformation }, { RxCommonQueryEa }, { RxCommonSetEa }, { RxCommonFlushBuffers }, { RxCommonQueryVolumeInformation }, { RxCommonSetVolumeInformation }, { RxCommonDirectoryControl }, { RxCommonFileSystemControl }, { RxCommonDeviceControl }, { RxCommonDeviceControl }, { RxCommonUnimplemented }, { RxCommonLockControl }, { RxCommonCleanup }, { RxCommonUnimplemented }, { RxCommonQuerySecurity }, { RxCommonSetSecurity }, { RxCommonUnimplemented }, { RxCommonUnimplemented }, { RxCommonUnimplemented }, { RxCommonQueryQuotaInformation }, { RxCommonSetQuotaInformation }, { RxCommonUnimplemented },};ULONG RxFsdEntryCount;LIST_ENTRY RxIrpsList;KSPIN_LOCK RxIrpsListSpinLock;KMUTEX RxScavengerMutex;KMUTEX RxSerializationMutex;UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];KSPIN_LOCK TopLevelIrpSpinLock;LIST_ENTRY TopLevelIrpAllocatedContextsList;BOOLEAN RxForceQFIPassThrough = FALSE;BOOLEAN RxNoAsync = FALSE;
DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
#if RDBSS_ASSERTS#ifdef ASSERT#undef ASSERT#endif
#define ASSERT(exp) \ if (!(exp)) \ { \ RxAssert(#exp, __FILE__, __LINE__, NULL); \ }#endif
#if RX_POOL_WRAPPER#undef RxAllocatePool#undef RxAllocatePoolWithTag#undef RxFreePool
#define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)#define RxAllocatePoolWithTag _RxAllocatePoolWithTag#define RxFreePool _RxFreePool#define RxFreePoolWithTag _RxFreePoolWithTag#endif
/* FUNCTIONS ****************************************************************/
/* * @implemented */VOIDCheckForLoudOperations( PRX_CONTEXT RxContext){ RxCaptureFcb;
PAGED_CODE();
#define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
/* Are loud operations enabled? */ if (RxLoudLowIoOpsEnabled) { /* If so, the operation will be loud only if filename ends with all.scr */ if (RtlCompareMemory(Add2Ptr(capFcb->PrivateAlreadyPrefixedName.Buffer, (capFcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)), L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH) { SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS); } }#undef ALLSCR_LENGTH}
/* * @implemented */VOID__RxInitializeTopLevelIrpContext( IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext, IN PIRP Irp, IN PRDBSS_DEVICE_OBJECT RxDeviceObject, IN ULONG Flags){ DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT)); TopLevelContext->Irp = Irp; TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0); TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE; TopLevelContext->RxDeviceObject = RxDeviceObject; TopLevelContext->Previous = IoGetTopLevelIrp(); TopLevelContext->Thread = PsGetCurrentThread();
/* We cannot add to list something that'd come from stack */ if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL)) { RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext); }}
/* * @implemented */VOID__RxWriteReleaseResources( PRX_CONTEXT RxContext, BOOLEAN ResourceOwnerSet, ULONG LineNumber, PCSTR FileName, ULONG SerialNumber){ RxCaptureFcb;
PAGED_CODE();
ASSERT(RxContext != NULL); ASSERT(capFcb != NULL);
/* If FCB resource was acquired, release it */ if (RxContext->FcbResourceAcquired) { /* Taking care of owner */ if (ResourceOwnerSet) { RxReleaseFcbForThread(RxContext, capFcb, RxContext->LowIoContext.ResourceThreadId); } else { RxReleaseFcb(RxContext, capFcb); }
RxContext->FcbResourceAcquired = FALSE; }
/* If FCB paging resource was acquired, release it */ if (RxContext->FcbPagingIoResourceAcquired) { /* Taking care of owner */ if (ResourceOwnerSet) { RxReleasePagingIoResourceForThread(RxContext, capFcb, RxContext->LowIoContext.ResourceThreadId); } else { RxReleasePagingIoResource(RxContext, capFcb); }
/* No need to release boolean here, RxReleasePagingIoResource() takes care of it */ }}
/* * @implemented */VOIDRxAddToTopLevelIrpAllocatedContextsList( PRX_TOPLEVELIRP_CONTEXT TopLevelContext){ KIRQL OldIrql;
DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE); ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql); InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry); KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);}
/* * @implemented */VOIDNTAPIRxAddToWorkque( IN PRX_CONTEXT RxContext, IN PIRP Irp){ ULONG Queued; KIRQL OldIrql; WORK_QUEUE_TYPE Queue;
RxCaptureParamBlock;
RxContext->PostRequest = FALSE;
/* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */ if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL && capPARAMS->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH) { Queue = DelayedWorkQueue; SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE); } else { Queue = CriticalWorkQueue; SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE); }
/* Check for overflow */ if (capPARAMS->FileObject != NULL) { KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]); /* In case of an overflow, add the new queued call to the overflow list */ if (Queued > 1) { InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]); InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry); ++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql); return; }
KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql); }
ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext); ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);}
/* * @implemented */VOIDRxAdjustFileTimesAndSize( PRX_CONTEXT RxContext){ NTSTATUS Status; LARGE_INTEGER CurrentTime; FILE_BASIC_INFORMATION FileBasicInfo; FILE_END_OF_FILE_INFORMATION FileEOFInfo; BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject;
PAGED_CODE();
/* If Cc isn't initialized, the file was not read nor written, nothing to do */ if (capFileObject->PrivateCacheMap == NULL) { return; }
/* Get now */ KeQuerySystemTime(&CurrentTime);
/* Was the file modified? */ FileModified = BooleanFlagOn(capFileObject->Flags, FO_FILE_MODIFIED); /* We'll set last write if it was modified and user didn't update yet */ SetLastWrite = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE); /* File was accessed if: written or read (fastio), we'll update last access if user didn't */ SetLastAccess = SetLastWrite || (BooleanFlagOn(capFileObject->Flags, FO_FILE_FAST_IO_READ) && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS)); /* We'll set last change if it was modified and user didn't update yet */ SetLastChange = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
/* Nothing to update? Job done */ if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange) { return; }
/* By default, we won't issue any MRxSetFileInfoAtCleanup call */ NeedUpdate = FALSE; RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
/* Update lastwrite time if required */ if (SetLastWrite) { NeedUpdate = TRUE; capFcb->LastWriteTime.QuadPart = CurrentTime.QuadPart; FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart; }
/* Update lastaccess time if required */ if (SetLastAccess) { NeedUpdate = TRUE; capFcb->LastAccessTime.QuadPart = CurrentTime.QuadPart; FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart; }
/* Update lastchange time if required */ if (SetLastChange) { NeedUpdate = TRUE; capFcb->LastChangeTime.QuadPart = CurrentTime.QuadPart; FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart; }
/* If one of the date was modified, issue a call to mini-rdr */ if (NeedUpdate) { RxContext->Info.FileInformationClass = FileBasicInformation; RxContext->Info.Buffer = &FileBasicInfo; RxContext->Info.Length = sizeof(FileBasicInfo);
MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext)); (void)Status; }
/* If the file was modified, update its EOF */ if (FileModified) { FileEOFInfo.EndOfFile.QuadPart = capFcb->Header.FileSize.QuadPart;
RxContext->Info.FileInformationClass = FileEndOfFileInformation; RxContext->Info.Buffer = &FileEOFInfo; RxContext->Info.Length = sizeof(FileEOFInfo);
MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext)); (void)Status; }}
/* * @implemented */NTSTATUSRxAllocateCanonicalNameBuffer( PRX_CONTEXT RxContext, PUNICODE_STRING CanonicalName, USHORT CanonicalLength){ PAGED_CODE();
DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
/* Context must be free of any already allocated name */ ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
/* Validate string length */ if (CanonicalLength > USHRT_MAX - 1) { CanonicalName->Buffer = NULL; return STATUS_OBJECT_PATH_INVALID; }
CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG); if (CanonicalName->Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
CanonicalName->Length = 0; CanonicalName->MaximumLength = CanonicalLength;
/* Set the two places - they must always be identical */ RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer; RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
return STATUS_SUCCESS;}
/* * @implemented */VOIDRxCancelNotifyChangeDirectoryRequestsForFobx( PFOBX Fobx){ KIRQL OldIrql; PLIST_ENTRY Entry; PRX_CONTEXT Context; LIST_ENTRY ContextsToCancel;
/* Init a list for the contexts to cancel */ InitializeListHead(&ContextsToCancel);
/* Lock our list lock */ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
/* Now, browse all the active contexts, to find the associated ones */ Entry = RxActiveContexts.Flink; while (Entry != &RxActiveContexts) { Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry); Entry = Entry->Flink;
/* Not the IRP we're looking for, ignore */ if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL || Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY) { continue; }
/* Not the FOBX we're looking for, ignore */ if ((PFOBX)Context->pFobx != Fobx) { continue; }
/* No cancel routine (can't be cancel, then), ignore */ if (Context->MRxCancelRoutine == NULL) { continue; }
/* Mark our context as cancelled */ SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
/* Move it to our list */ RemoveEntryList(&Context->ContextListEntry); InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
InterlockedIncrement((volatile long *)&Context->ReferenceCount); }
/* Done with the contexts */ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
/* Now, handle all our "extracted" contexts */ while (!IsListEmpty(&ContextsToCancel)) { Entry = RemoveHeadList(&ContextsToCancel); Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
/* If they had an associated IRP (should be always true) */ if (Context->CurrentIrp != NULL) { /* Then, call cancel routine */ ASSERT(Context->MRxCancelRoutine != NULL); DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine); Context->MRxCancelRoutine(Context); }
/* And delete the context */ RxDereferenceAndDeleteRxContext(Context); }}
/* * @implemented */NTSTATUSRxCancelNotifyChangeDirectoryRequestsForVNetRoot( PV_NET_ROOT VNetRoot, BOOLEAN ForceFilesClosed){ KIRQL OldIrql; NTSTATUS Status; PLIST_ENTRY Entry; PRX_CONTEXT Context; LIST_ENTRY ContextsToCancel;
/* Init a list for the contexts to cancel */ InitializeListHead(&ContextsToCancel);
/* Lock our list lock */ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
/* Assume success */ Status = STATUS_SUCCESS;
/* Now, browse all the active contexts, to find the associated ones */ Entry = RxActiveContexts.Flink; while (Entry != &RxActiveContexts) { Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry); Entry = Entry->Flink;
/* Not the IRP we're looking for, ignore */ if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL || Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY) { continue; }
/* Not the VNetRoot we're looking for, ignore */ if (Context->pFcb == NULL || (PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot) { continue; }
/* No cancel routine (can't be cancel, then), ignore */ if (Context->MRxCancelRoutine == NULL) { continue; }
/* At that point, we found a matching context * If we're not asked to force close, then fail - it's still open */ if (!ForceFilesClosed) { Status = STATUS_FILES_OPEN; break; }
/* Mark our context as cancelled */ SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
/* Move it to our list */ RemoveEntryList(&Context->ContextListEntry); InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
InterlockedIncrement((volatile long *)&Context->ReferenceCount); }
/* Done with the contexts */ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
if (Status != STATUS_SUCCESS) { return Status; }
/* Now, handle all our "extracted" contexts */ while (!IsListEmpty(&ContextsToCancel)) { Entry = RemoveHeadList(&ContextsToCancel); Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
/* If they had an associated IRP (should be always true) */ if (Context->CurrentIrp != NULL) { /* Then, call cancel routine */ ASSERT(Context->MRxCancelRoutine != NULL); DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine); Context->MRxCancelRoutine(Context); }
/* And delete the context */ RxDereferenceAndDeleteRxContext(Context); }
return Status;}
/* * @implemented */BOOLEANRxCancelOperationInOverflowQueue( PRX_CONTEXT RxContext){ KIRQL OldIrql; BOOLEAN OperationToCancel;
/* By default, nothing cancelled */ OperationToCancel = FALSE;
/* Acquire the overflow spinlock */ KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
/* Is our context in any queue? */ if (BooleanFlagOn(RxContext->Flags, (RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE))) { /* Make sure flag is consistent with facts... */ if (RxContext->OverflowListEntry.Flink != NULL) { /* Remove it from the list */ RemoveEntryList(&RxContext->OverflowListEntry); RxContext->OverflowListEntry.Flink = NULL;
/* Decrement appropriate count */ if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE)) { --RxFileSystemDeviceObject->OverflowQueueCount[CriticalWorkQueue]; } else { --RxFileSystemDeviceObject->OverflowQueueCount[DelayedWorkQueue]; }
/* Clear the flag */ ClearFlag(RxContext->Flags, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
/* Time to cancel! */ OperationToCancel = TRUE; } }
KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
/* We have something to cancel & complete */ if (OperationToCancel) { RxRemoveOperationFromBlockingQueue(RxContext); RxCompleteRequest(RxContext, STATUS_CANCELLED); }
return OperationToCancel;}
/* * @implemented */VOIDNTAPIRxCancelRoutine( PDEVICE_OBJECT DeviceObject, PIRP Irp){ KIRQL OldIrql; PLIST_ENTRY Entry; PRX_CONTEXT RxContext;
/* Lock our contexts list */ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
/* Now, find a context that matches the cancelled IRP */ Entry = RxActiveContexts.Flink; while (Entry != &RxActiveContexts) { RxContext = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry); Entry = Entry->Flink;
/* Found! */ if (RxContext->CurrentIrp == Irp) { break; } }
/* If we reached the end of the list, we didn't find any context, so zero the buffer * If the context is already under cancellation, forget about it too */ if (Entry == &RxActiveContexts || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED)) { RxContext = NULL; } else { /* Otherwise, reference it and mark it cancelled */ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED); InterlockedIncrement((volatile long *)&RxContext->ReferenceCount); }
/* Done with the contexts list */ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
/* And done with the cancellation, we'll do it now */ IoReleaseCancelSpinLock(Irp->CancelIrql);
/* If we have a context to cancel */ if (RxContext != NULL) { /* We cannot executed at dispatch, so queue a deferred cancel */ if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue, RxpCancelRoutine, RxContext); } /* Cancel now! */ else { RxpCancelRoutine(RxContext); } }}
/* * @implemented */NTSTATUSRxCanonicalizeFileNameByServerSpecs( PRX_CONTEXT RxContext, PUNICODE_STRING NetRootName){ USHORT NextChar, CurChar; USHORT MaxChars;
PAGED_CODE();
/* Validate file name is not empty */ MaxChars = NetRootName->Length / sizeof(WCHAR); if (MaxChars == 0) { return STATUS_MORE_PROCESSING_REQUIRED; }
/* Validate name is correct */ for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1) { USHORT i;
for (i = NextChar + 1; i < MaxChars; ++i) { if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':') { break; } }
CurChar = i - 1; if (CurChar == NextChar) { if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.') { continue; }
if (CurChar != 0) { if (CurChar >= MaxChars - 1) { continue; }
if (NetRootName->Buffer[CurChar + 1] != ':') { return STATUS_OBJECT_PATH_SYNTAX_BAD; } } else { if (NetRootName->Buffer[1] != ':') { return STATUS_OBJECT_PATH_SYNTAX_BAD; } } } else { if ((CurChar - NextChar) == 1) { if (NetRootName->Buffer[NextChar + 2] != '.') { continue; }
if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.') { return STATUS_OBJECT_PATH_SYNTAX_BAD; } } else { if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NetRootName->Buffer[NextChar + 1] != '.') { continue; }
if (NetRootName->Buffer[NextChar + 2] == '.') { return STATUS_OBJECT_PATH_SYNTAX_BAD; } } } }
return STATUS_MORE_PROCESSING_REQUIRED;}
NTSTATUSRxCanonicalizeNameAndObtainNetRoot( PRX_CONTEXT RxContext, PUNICODE_STRING FileName, PUNICODE_STRING NetRootName){ NTSTATUS Status; NET_ROOT_TYPE NetRootType; UNICODE_STRING CanonicalName;
RxCaptureParamBlock; RxCaptureFileObject;
PAGED_CODE();
NetRootType = NET_ROOT_WILD;
RtlInitEmptyUnicodeString(NetRootName, NULL, 0); RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
/* if not relative opening, just handle the passed name */ if (capFileObject->RelatedFileObject == NULL) { Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType); if (!NT_SUCCESS(Status)) { return Status; } } else { PFCB Fcb;
/* Make sure we have a valid FCB and a FOBX */ Fcb = capFileObject->RelatedFileObject->FsContext; if (Fcb == NULL || capFileObject->RelatedFileObject->FsContext2 == NULL) { return STATUS_INVALID_PARAMETER; }
if (!NodeTypeIsFcb(Fcb)) { return STATUS_INVALID_PARAMETER; }
UNIMPLEMENTED; }
/* Get/Create the associated VNetRoot for opening */ Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName); if (!NT_SUCCESS(Status) && Status != STATUS_PENDING && BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE)) { ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
RxFreeCanonicalNameBuffer(RxContext); Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType); if (NT_SUCCESS(Status)) { Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName); } }
/* Filename cannot contain wildcards */ if (FsRtlDoesNameContainWildCards(NetRootName)) { Status = STATUS_OBJECT_NAME_INVALID; }
/* Make sure file name is correct */ if (NT_SUCCESS(Status)) { Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName); }
/* Give the mini-redirector a chance to prepare the name */ if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED) { if (RxContext->Create.pNetRoot != NULL) { NTSTATUS IgnoredStatus;
MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch, MRxPreparseName, (RxContext, NetRootName)); (void)IgnoredStatus; } }
return Status;}
/* * @implemented */VOIDNTAPIRxCheckFcbStructuresForAlignment( VOID){ PAGED_CODE();}
#if DBGNTSTATUSRxCheckShareAccess( _In_ ACCESS_MASK DesiredAccess, _In_ ULONG DesiredShareAccess, _Inout_ PFILE_OBJECT FileObject, _Inout_ PSHARE_ACCESS ShareAccess, _In_ BOOLEAN Update, _In_ PSZ where, _In_ PSZ wherelogtag){ PAGED_CODE();
RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess); RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);}#endif
/* * @implemented */NTSTATUSRxCheckShareAccessPerSrvOpens( IN PFCB Fcb, IN ACCESS_MASK DesiredAccess, IN ULONG DesiredShareAccess){ BOOLEAN ReadAccess; BOOLEAN WriteAccess; BOOLEAN DeleteAccess; PSHARE_ACCESS ShareAccess;
PAGED_CODE();
ShareAccess = &Fcb->ShareAccessPerSrvOpens;
RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess); RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
/* Check if any access wanted */ ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0; WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0; DeleteAccess = (DesiredAccess & DELETE) != 0;
if (ReadAccess || WriteAccess || DeleteAccess) { BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0; BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0; BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
/* Check whether there's a violation */ if ((ReadAccess && (ShareAccess->SharedRead < ShareAccess->OpenCount)) || (WriteAccess && (ShareAccess->SharedWrite < ShareAccess->OpenCount)) || (DeleteAccess && (ShareAccess->SharedDelete < ShareAccess->OpenCount)) || ((ShareAccess->Readers != 0) && !SharedRead) || ((ShareAccess->Writers != 0) && !SharedWrite) || ((ShareAccess->Deleters != 0) && !SharedDelete)) { return STATUS_SHARING_VIOLATION; } }
return STATUS_SUCCESS;}
VOIDRxCleanupPipeQueues( PRX_CONTEXT Context){ UNIMPLEMENTED;}
/* * @implemented */NTSTATUSRxCloseAssociatedSrvOpen( IN PFOBX Fobx, IN PRX_CONTEXT RxContext OPTIONAL){ PFCB Fcb; NTSTATUS Status; PSRV_OPEN SrvOpen; BOOLEAN CloseSrvOpen; PRX_CONTEXT LocalContext;
PAGED_CODE();
/* Assume SRV_OPEN is already closed */ CloseSrvOpen = FALSE; /* If we have a FOBX, we'll have to close it */ if (Fobx != NULL) { /* If the FOBX isn't closed yet */ if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED)) { SrvOpen = Fobx->SrvOpen; Fcb = (PFCB)SrvOpen->pFcb; /* Check whether we've to close SRV_OPEN first */ if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED)) { CloseSrvOpen = TRUE; } else { ASSERT(RxIsFcbAcquiredExclusive(Fcb));
/* Not much to do */ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
if (SrvOpen->OpenCount > 0) { --SrvOpen->OpenCount; } } }
/* No need to close SRV_OPEN, so close FOBX */ if (!CloseSrvOpen) { RxMarkFobxOnClose(Fobx);
return STATUS_SUCCESS; } } else { /* No FOBX? No RX_CONTEXT, ok, job done! */ if (RxContext == NULL) { return STATUS_SUCCESS; }
/* Get the FCB from RX_CONTEXT */ Fcb = (PFCB)RxContext->pFcb; SrvOpen = NULL; }
/* If we don't have RX_CONTEXT, allocte one, we'll need it */ if (RxContext == NULL) { ASSERT(Fobx != NULL);
LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT); if (LocalContext == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
LocalContext->MajorFunction = 2; LocalContext->pFcb = RX_GET_MRX_FCB(Fcb); LocalContext->pFobx = (PMRX_FOBX)Fobx; LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen; } else { LocalContext = RxContext; }
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
/* Now, close the FOBX */ if (Fobx != NULL) { RxMarkFobxOnClose(Fobx); } else { InterlockedDecrement((volatile long *)&Fcb->OpenCount); }
/* If not a "standard" file, SRV_OPEN can be null */ if (SrvOpen == NULL) { ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)); RxDereferenceNetFcb(Fcb);
if (LocalContext != RxContext) { RxDereferenceAndDeleteRxContext(LocalContext); }
return STATUS_SUCCESS; }
/* If SRV_OPEN isn't in a good condition, nothing to close */ if (SrvOpen->Condition != Condition_Good) { if (LocalContext != RxContext) { RxDereferenceAndDeleteRxContext(LocalContext); }
return STATUS_SUCCESS; }
/* Decrease open count */ if (SrvOpen->OpenCount > 0) { --SrvOpen->OpenCount; }
/* If we're the only one left, is there a FOBX handled by Scavenger? */ if (SrvOpen->OpenCount == 1) { if (!IsListEmpty(&SrvOpen->FobxList)) { if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList)) { SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED); } } }
/* Nothing left, purge FCB */ if (SrvOpen->OpenCount == 0 && RxContext == NULL) { RxPurgeNetFcb(Fcb, LocalContext); }
/* Already closed? Job done! */ SrvOpen = Fobx->SrvOpen; if (SrvOpen == NULL || (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) || BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED)) { SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED); if (LocalContext != RxContext) { RxDereferenceAndDeleteRxContext(LocalContext); }
return STATUS_SUCCESS; }
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
/* Inform mini-rdr about closing */ MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext)); DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ", Status, RxContext, Fobx, Fcb, SrvOpen);
/* And mark as such */ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED); SrvOpen->Key = (PVOID)-1;
/* If we were delayed, we're not! */ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED)) { InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles); }
/* Clear access */ RxRemoveShareAccessPerSrvOpens(SrvOpen); RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
/* Dereference */ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
/* Mark the FOBX closed as well */ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
if (LocalContext != RxContext) { RxDereferenceAndDeleteRxContext(LocalContext); }
return Status;}
/* * @implemented */NTSTATUSRxCollapseOrCreateSrvOpen( PRX_CONTEXT RxContext){ NTSTATUS Status; ULONG Disposition; PSRV_OPEN SrvOpen; USHORT ShareAccess; ACCESS_MASK DesiredAccess; RX_BLOCK_CONDITION FcbCondition;
RxCaptureFcb; RxCaptureParamBlock;
PAGED_CODE();
DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
ASSERT(RxIsFcbAcquiredExclusive(capFcb)); ++capFcb->UncleanCount;
DesiredAccess = capPARAMS->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS; ShareAccess = capPARAMS->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
Disposition = RxContext->Create.NtCreateParameters.Disposition;
/* Try to find a reusable SRV_OPEN */ Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess); if (Status == STATUS_NOT_FOUND) { /* If none found, create one */ SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, capFcb); if (SrvOpen == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { SrvOpen->DesiredAccess = DesiredAccess; SrvOpen->ShareAccess = ShareAccess; Status = STATUS_SUCCESS; }
RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
if (Status != STATUS_SUCCESS) { FcbCondition = Condition_Bad; } else { RxInitiateSrvOpenKeyAssociation(SrvOpen);
/* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */ RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF; /* Inform the mini-rdr we're handling a create */ MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCreate, (RxContext)); ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
DPRINT("MRxCreate returned: %x\n", Status); if (Status == STATUS_SUCCESS) { /* In case of overwrite, reset file size */ if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF) { RxAcquirePagingIoResource(RxContext, capFcb); capFcb->Header.AllocationSize.QuadPart = 0LL; capFcb->Header.FileSize.QuadPart = 0LL; capFcb->Header.ValidDataLength.QuadPart = 0LL; RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers; CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize); RxReleasePagingIoResource(RxContext, capFcb); } else { /* Otherwise, adjust sizes */ RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers; if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject)) { RxAdjustAllocationSizeforCC(capFcb); } CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize); } }
/* Set the IoStatus with information returned by mini-rdr */ RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
SrvOpen->OpenStatus = Status; /* Set SRV_OPEN state - good or bad - depending on whether create succeed */ RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
ASSERT(RxIsFcbAcquiredExclusive(capFcb));
RxCompleteSrvOpenKeyAssociation(SrvOpen);
if (Status == STATUS_SUCCESS) { if (BooleanFlagOn(capPARAMS->Parameters.Create.Options, FILE_DELETE_ON_CLOSE)) { ClearFlag(capFcb->FcbState, FCB_STATE_COLLAPSING_ENABLED); } SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions; FcbCondition = Condition_Good; } else { FcbCondition = Condition_Bad; RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld); RxContext->pRelevantSrvOpen = NULL;
if (RxContext->pFobx != NULL) { RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld); RxContext->pFobx = NULL; } } }
/* Set FCB state - good or bad - depending on whether create succeed */ DPRINT("Transitioning FCB %p to condition %lx\n", capFcb, capFcb->Condition); RxTransitionNetFcb(capFcb, FcbCondition); } else if (Status == STATUS_SUCCESS) { BOOLEAN IsGood, ExtraOpen;
/* A reusable SRV_OPEN was found */ RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED; ExtraOpen = FALSE;
SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
IsGood = (SrvOpen->Condition == Condition_Good); /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */ if (!StableCondition(SrvOpen->Condition)) { RxReferenceSrvOpen(SrvOpen); ++SrvOpen->OpenCount; ExtraOpen = TRUE;
RxReleaseFcb(RxContext, capFcb); RxContext->Create.FcbAcquired = FALSE;
RxWaitForStableSrvOpen(SrvOpen, RxContext);
if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, capFcb))) { RxContext->Create.FcbAcquired = TRUE; }
IsGood = (SrvOpen->Condition == Condition_Good); }
/* Inform the mini-rdr we do an opening with a reused SRV_OPEN */ if (IsGood) { MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCollapseOpen, (RxContext));
ASSERT(RxIsFcbAcquiredExclusive(capFcb)); } else { Status = SrvOpen->OpenStatus; }
if (ExtraOpen) { --SrvOpen->OpenCount; RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld); } }
--capFcb->UncleanCount;
DPRINT("Status: %x\n", Status); return Status;}
/* * @implemented */NTSTATUSNTAPIRxCommonCleanup( PRX_CONTEXT Context){#define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP PFCB Fcb; PFOBX Fobx; ULONG OpenCount; NTSTATUS Status; PNET_ROOT NetRoot; PFILE_OBJECT FileObject; LARGE_INTEGER TruncateSize; PLARGE_INTEGER TruncateSizePtr; BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb; Fobx = (PFOBX)Context->pFobx; DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
/* File system closing, it's OK */ if (Fobx == NULL) { if (Fcb->UncleanCount > 0) { InterlockedDecrement((volatile long *)&Fcb->UncleanCount); }
return STATUS_SUCCESS; }
/* Check we have a correct FCB type */ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN && NodeType(Fcb) != RDBSS_NTC_SPOOLFILE) { DPRINT1("Invalid Fcb type for %p\n", Fcb); RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0); }
FileObject = Context->CurrentIrpSp->FileObject; ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
RxMarkFobxOnCleanup(Fobx, &NeedPurge);
Status = RxAcquireExclusiveFcb(Context, Fcb); if (!NT_SUCCESS(Status)) { return Status; }
FcbAcquired = TRUE;
Fobx->AssociatedFileObject = NULL;
/* In case it was already orphaned */ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED)) { ASSERT(Fcb->UncleanCount != 0); InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { --Fcb->UncachedUncleanCount; }
/* Inform mini-rdr */ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0); --Fobx->SrvOpen->UncleanFobxCount;
RxUninitializeCacheMap(Context, FileObject, NULL);
RxReleaseFcb(Context, Fcb);
return STATUS_SUCCESS; }
/* Report the fact that file could be set as delete on close */ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE)) { SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE); }
/* Cancel any pending notification */ RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
/* Backup open count before we start playing with it */ OpenCount = Fcb->ShareAccess.OpenCount;
NetRoot = (PNET_ROOT)Fcb->pNetRoot; FcbTableAcquired = FALSE; LeftForDelete = FALSE; OneLeft = (Fcb->UncleanCount == 1);
_SEH2_TRY { /* Unclean count and delete on close? Verify whether we're the one */ if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) { if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE)) { FcbTableAcquired = TRUE; } else { RxReleaseFcb(Context, Fcb);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
Status = RxAcquireExclusiveFcb(Context, Fcb); if (Status != STATUS_SUCCESS) { RxReleaseFcbTableLock(&NetRoot->FcbTable); return Status; }
FcbTableAcquired = TRUE; }
/* That means we'll perform the delete on close! */ if (Fcb->UncleanCount == 1) { LeftForDelete = TRUE; } else { RxReleaseFcbTableLock(&NetRoot->FcbTable); FcbTableAcquired = FALSE; } }
IsFile = FALSE; TruncateSizePtr = NULL; /* Handle cleanup for pipes and printers */ if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT) { RxCleanupPipeQueues(Context); } /* Handle cleanup for files */ else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD) { Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS; if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE) { /* First, unlock */ FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
/* If there are still locks to release, proceed */ if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL) { RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE); Context->LowIoContext.ParamsFor.Locks.Flags = 0; Status = RxLowIoLockControlShell(Context); }
/* Fix times and size */ RxAdjustFileTimesAndSize(Context);
/* If we're the only one left... */ if (OneLeft) { /* And if we're supposed to delete on close */ if (LeftForDelete) { /* Update the sizes */ RxAcquirePagingIoResource(Context, Fcb); Fcb->Header.FileSize.QuadPart = 0; Fcb->Header.ValidDataLength.QuadPart = 0; RxReleasePagingIoResource(Context, Fcb); } /* Otherwise, call the mini-rdr to adjust sizes */ else { /* File got grown up, fill with zeroes */ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) && (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart)) { MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context)); Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; }
/* File was truncated, let mini-rdr proceed */ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE)) { MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context)); ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
/* Keep track of file change for Cc uninit */ TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart; TruncateSizePtr = &TruncateSize; } } }
/* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */ if (NeedPurge) { if (!OneLeft) { NeedPurge = FALSE; } } /* Otherwise, try to see whether we can purge */ else { NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))); }
IsFile = TRUE; } }
/* We have to still be there! */ ASSERT(Fcb->UncleanCount != 0); InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { --Fcb->UncachedUncleanCount; }
/* Inform mini-rdr about ongoing cleanup */ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0); --Fobx->SrvOpen->UncleanFobxCount;
/* Flush cache */ if (DisableFlushOnCleanup) { /* Only if we're the last standing */ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL && Fcb->UncleanCount == Fcb->UncachedUncleanCount) { DPRINT("Flushing %p due to last cached handle cleanup\n", Context); RxFlushFcbInSystemCache(Fcb, TRUE); } } else { /* Always */ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) { DPRINT("Flushing %p on cleanup\n", Context); RxFlushFcbInSystemCache(Fcb, TRUE); } }
/* If only remaining uncached & unclean, then flush and purge */ if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { if (Fcb->UncachedUncleanCount != 0) { if (Fcb->UncachedUncleanCount == Fcb->UncleanCount && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) { DPRINT("Flushing FCB in system cache for %p\n", Context); RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE); } } }
/* If purge required, and not about to delete, flush */ if (!LeftForDelete && NeedPurge) { DPRINT("Flushing FCB in system cache for %p\n", Context); RxFlushFcbInSystemCache(Fcb, TRUE); }
/* If it was a file, drop cache */ if (IsFile) { DPRINT("Uninit cache map for file\n"); RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr); }
/* If that's the one left for deletion, or if it needs purge, flush */ if (LeftForDelete || NeedPurge) { RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete); /* If that's for deletion, also remove from FCB table */ if (LeftForDelete) { RxRemoveNameNetFcb(Fcb); RxReleaseFcbTableLock(&NetRoot->FcbTable); FcbTableAcquired = FALSE; } }
/* Remove any share access */ if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK) { RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr"); }
/* In case there's caching, on a file, and we were asked to drop collapsing, handle it */ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) && RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen)) { NTSTATUS InternalStatus; PRX_CONTEXT InternalContext;
/* If we can properly set EOF, there's no need to drop collapsing, try to do it */ InternalStatus = STATUS_UNSUCCESSFUL; InternalContext = RxCreateRxContext(Context->CurrentIrp, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING); if (InternalContext != NULL) { FILE_END_OF_FILE_INFORMATION FileEOF;
InternalStatus = STATUS_SUCCESS;
/* Initialize the context for file information set */ InternalContext->pFcb = RX_GET_MRX_FCB(Fcb); InternalContext->pFobx = (PMRX_FOBX)Fobx; InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
/* Get EOF from the FCB */ FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart; InternalContext->Info.FileInformationClass = FileEndOfFileInformation; InternalContext->Info.Buffer = &FileEOF; InternalContext->Info.Length = sizeof(FileEOF);
/* Call the mini-rdr */ MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
/* We're done */ RxDereferenceAndDeleteRxContext(InternalContext); }
/* We tried, so, clean the FOBX flag */ ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING); /* If it failed, then, disable collapsing on the FCB */ if (!NT_SUCCESS(InternalStatus)) { ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED); } }
/* We're clean! */ SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
FcbAcquired = FALSE; RxReleaseFcb(Context, Fcb); } _SEH2_FINALLY { if (FcbAcquired) { RxReleaseFcb(Context, Fcb); }
if (FcbTableAcquired) { RxReleaseFcbTableLock(&NetRoot->FcbTable); } } _SEH2_END;
return Status;#undef BugCheckFileId}
NTSTATUSNTAPIRxCommonClose( PRX_CONTEXT Context){#define BugCheckFileId RDBSS_BUG_CHECK_CLOSE PFCB Fcb; PFOBX Fobx; NTSTATUS Status; PFILE_OBJECT FileObject; BOOLEAN DereferenceFobx, AcquiredFcb;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb; Fobx = (PFOBX)Context->pFobx; FileObject = Context->CurrentIrpSp->FileObject; DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
Status = RxAcquireExclusiveFcb(Context, Fcb); if (!NT_SUCCESS(Status)) { return Status; }
AcquiredFcb = TRUE; _SEH2_TRY { BOOLEAN Freed;
/* Check our FCB type is expected */ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN && (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE && (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB)))) { RxBugCheck(NodeType(Fcb), 0, 0); }
RxReferenceNetFcb(Fcb);
DereferenceFobx = FALSE; /* If we're not closing FS */ if (Fobx != NULL) { PSRV_OPEN SrvOpen; PSRV_CALL SrvCall;
SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen; SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall; /* Handle delayed close */ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) { if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED)) { if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)) { DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED)) { if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles) { InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles); } else { DereferenceFobx = TRUE; SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED); } } } } }
/* If we reach maximum of delayed close/or if there are no delayed close */ if (!DereferenceFobx) { PNET_ROOT NetRoot;
NetRoot = (PNET_ROOT)Fcb->pNetRoot; if (NetRoot->Type != NET_ROOT_PRINT) { /* Delete if asked */ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE)) { RxScavengeRelatedFobxs(Fcb); RxSynchronizeWithScavenger(Context);
RxReleaseFcb(Context, Fcb);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE); RxOrphanThisFcb(Fcb); RxReleaseFcbTableLock(&NetRoot->FcbTable);
Status = RxAcquireExclusiveFcb(Context, Fcb); ASSERT(NT_SUCCESS(Status)); } } }
RxMarkFobxOnClose(Fobx); }
if (DereferenceFobx) { ASSERT(Fobx != NULL); RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld); } else { RxCloseAssociatedSrvOpen(Fobx, Context); if (Fobx != NULL) { RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld); } }
Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE); AcquiredFcb = !Freed;
FileObject->FsContext = (PVOID)-1;
if (Freed) { RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0); } else { RxReleaseFcb(Context, Fcb); AcquiredFcb = FALSE; } } _SEH2_FINALLY { if (_SEH2_AbnormalTermination()) { if (AcquiredFcb) { RxReleaseFcb(Context, Fcb); } } else { ASSERT(!AcquiredFcb); } } _SEH2_END;
DPRINT("Status: %x\n", Status); return Status;#undef BugCheckFileId}
/* * @implemented */NTSTATUSNTAPIRxCommonCreate( PRX_CONTEXT Context){ PIRP Irp; NTSTATUS Status; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack;
PAGED_CODE();
DPRINT("RxCommonCreate(%p)\n", Context);
Irp = Context->CurrentIrp; Stack = Context->CurrentIrpSp; FileObject = Stack->FileObject;
/* Check whether that's a device opening */ if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL) { FileObject->FsContext = &RxDeviceFCB; FileObject->FsContext2 = NULL;
++RxDeviceFCB.NodeReferenceCount; ++RxDeviceFCB.OpenCount;
Irp->IoStatus.Information = FILE_OPENED; DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
Status = STATUS_SUCCESS; } else { PFCB RelatedFcb = NULL;
/* Make sure caller is consistent */ if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) == (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE)) { DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options); return STATUS_INVALID_PARAMETER; }
DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n", Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes, Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess); DPRINT("FileName: %wZ\n", &FileObject->FileName);
if (FileObject->RelatedFileObject != NULL) { RelatedFcb = FileObject->RelatedFileObject->FsContext; DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path); }
/* Going to rename? */ if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY)) { DPRINT("TargetDir!\n"); }
/* Copy create parameters to the context */ RxCopyCreateParameters(Context);
/* If the caller wants to establish a connection, go ahead */ if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION)) { Status = RxCreateTreeConnect(Context); } else { /* Validate file name */ if (FileObject->FileName.Length > sizeof(WCHAR) && FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR && FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { FileObject->FileName.Length -= sizeof(WCHAR); RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1], FileObject->FileName.Length);
if (FileObject->FileName.Length > sizeof(WCHAR) && FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR && FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { return STATUS_OBJECT_NAME_INVALID; } }
/* Attempt to open the file */ do { UNICODE_STRING NetRootName;
/* Strip last \ if required */ if (FileObject->FileName.Length != 0 && FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) { if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE)) { return STATUS_OBJECT_NAME_INVALID; }
FileObject->FileName.Length -= sizeof(WCHAR); Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH; }
if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH)) { FileObject->Flags |= FO_WRITE_THROUGH; }
/* Get the associated net root to opening */ Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName); if (Status != STATUS_MORE_PROCESSING_REQUIRED) { break; }
/* And attempt to open */ Status = RxCreateFromNetRoot(Context, &NetRootName); if (Status == STATUS_SHARING_VIOLATION) { ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
/* If that happens for file creation, fail for real */ if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE) { Status = STATUS_OBJECT_NAME_COLLISION; } else { /* Otherwise, if possible, attempt to scavenger current FOBX * to check whether a dormant FOBX is the reason for sharing violation */ if (Context->Create.TryForScavengingOnSharingViolation && !Context->Create.ScavengingAlreadyTried) { /* Only doable with a VNetRoot */ if (Context->Create.pVNetRoot != NULL) { PV_NET_ROOT VNetRoot; NT_CREATE_PARAMETERS SavedParameters;
/* Save create parameters */ RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
/* Reference the VNetRoot for the scavenging time */ VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot; RxReferenceVNetRoot(VNetRoot);
/* Prepare the RX_CONTEXT for reuse */ RxpPrepareCreateContextForReuse(Context); RxReinitializeContext(Context);
/* Copy what we saved */ RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
/* And recopy what can be */ RxCopyCreateParameters(Context);
/* And start purging, then scavenging FOBX */ RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context, DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL); RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot, NULL, TRUE);
/* Ask for a second round */ Status = STATUS_MORE_PROCESSING_REQUIRED;
/* Keep track we already scavenged */ Context->Create.ScavengingAlreadyTried = TRUE;
/* Reference our SRV_CALL for CBS handling */ RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall); RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
/* Drop our extra reference */ RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld); } } } } else if (Status == STATUS_REPARSE) { Context->CurrentIrp->IoStatus.Information = 0; } else { ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE)); } } while (Status == STATUS_MORE_PROCESSING_REQUIRED); }
if (Status == STATUS_RETRY) { RxpPrepareCreateContextForReuse(Context); } ASSERT(Status != STATUS_PENDING); }
DPRINT("Status: %lx\n", Status); return Status;}
/* * @implemented */NTSTATUSNTAPIRxCommonDevFCBCleanup( PRX_CONTEXT Context){ PMRX_FCB Fcb; NTSTATUS Status;
PAGED_CODE();
DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
Fcb = Context->pFcb; Status = STATUS_SUCCESS; ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
/* Our FOBX if set, has to be a VNetRoot */ if (Context->pFobx != NULL) { RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE); if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT) { Status = STATUS_INVALID_DEVICE_REQUEST; } RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable); } else { --Fcb->UncleanCount; }
return Status;}
/* * @implemented */NTSTATUSNTAPIRxCommonDevFCBClose( PRX_CONTEXT Context){ PMRX_FCB Fcb; NTSTATUS Status; PMRX_V_NET_ROOT NetRoot;
PAGED_CODE();
DPRINT("RxCommonDevFCBClose(%p)\n", Context);
Fcb = Context->pFcb; NetRoot = (PMRX_V_NET_ROOT)Context->pFobx; Status = STATUS_SUCCESS; ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
/* Our FOBX if set, has to be a VNetRoot */ if (NetRoot != NULL) { RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE); if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT) { --NetRoot->NumberOfOpens; RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld); } else { Status = STATUS_NOT_IMPLEMENTED; } RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable); } else { --Fcb->OpenCount; }
return Status;}
NTSTATUSNTAPIRxCommonDevFCBFsCtl( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxCommonDevFCBIoCtl( PRX_CONTEXT Context){ NTSTATUS Status;
PAGED_CODE();
DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
if (Context->pFobx != NULL) { return STATUS_INVALID_HANDLE; }
/* Is that a prefix claim from MUP? */ if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH) { return RxPrefixClaim(Context); }
/* Otherwise, pass through the mini-rdr */ Status = RxXXXControlFileCallthru(Context); if (Status != STATUS_PENDING) { if (Context->PostRequest) { Context->ResumeRoutine = RxCommonDevFCBIoCtl; Status = RxFsdPostRequest(Context); } }
DPRINT("Status: %lx\n", Status); return Status;}
NTSTATUSNTAPIRxCommonDevFCBQueryVolInfo( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxCommonDeviceControl( PRX_CONTEXT Context){ NTSTATUS Status;
PAGED_CODE();
/* Prefix claim is only allowed for device, not files */ if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH) { return STATUS_INVALID_DEVICE_REQUEST; }
/* Submit to mini-rdr */ RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL); Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion); if (Status == STATUS_PENDING) { RxDereferenceAndDeleteRxContext_Real(Context); }
return Status;}
/* * @implemented */NTSTATUSNTAPIRxCommonDirectoryControl( PRX_CONTEXT Context){ PFCB Fcb; PFOBX Fobx; NTSTATUS Status; PIO_STACK_LOCATION Stack;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb; Fobx = (PFOBX)Context->pFobx; Stack = Context->CurrentIrpSp; DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
/* Call the appropriate helper */ if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY) { Status = RxQueryDirectory(Context); } else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) { Status = RxNotifyChangeDirectory(Context); if (Status == STATUS_PENDING) { RxDereferenceAndDeleteRxContext_Real(Context); } } else { Status = STATUS_INVALID_DEVICE_REQUEST; }
return Status;}
NTSTATUSNTAPIRxCommonDispatchProblem( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonFileSystemControl( PRX_CONTEXT Context){ PIRP Irp; ULONG ControlCode; PIO_STACK_LOCATION Stack;
PAGED_CODE();
Irp = Context->CurrentIrp; Stack = Context->CurrentIrpSp; ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonFlushBuffers( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonLockControl( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonQueryEa( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxCommonQueryInformation( PRX_CONTEXT Context){#define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \ Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \ Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
PFCB Fcb; PIRP Irp; PFOBX Fobx; BOOLEAN Locked; NTSTATUS Status; PIO_STACK_LOCATION Stack; FILE_INFORMATION_CLASS FileInfoClass;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb; Fobx = (PFOBX)Context->pFobx; DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
Irp = Context->CurrentIrp; Stack = Context->CurrentIrpSp; DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
Context->Info.Length = Stack->Parameters.QueryFile.Length; FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
Locked = FALSE; _SEH2_TRY { PVOID Buffer;
/* Get a writable buffer */ Buffer = RxMapSystemBuffer(Context); if (Buffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } /* Zero it */ RtlZeroMemory(Buffer, Context->Info.Length);
/* Validate file type */ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN) { if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE) { if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT) { Status = STATUS_NOT_IMPLEMENTED; } else { Status = STATUS_INVALID_PARAMETER; }
_SEH2_LEAVE; } }
/* Acquire the right lock */ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) && FileInfoClass != FileNameInformation) { if (FileInfoClass == FileCompressionInformation) { Status = RxAcquireExclusiveFcb(Context, Fcb); } else { Status = RxAcquireSharedFcb(Context, Fcb); }
if (Status == STATUS_LOCK_NOT_GRANTED) { Status = STATUS_PENDING; _SEH2_LEAVE; } else if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; }
Locked = TRUE; }
/* Dispatch to the right helper */ switch (FileInfoClass) { case FileBasicInformation: Status = RxQueryBasicInfo(Context, Buffer); break;
case FileStandardInformation: Status = RxQueryStandardInfo(Context, Buffer); break;
case FileInternalInformation: Status = RxQueryInternalInfo(Context, Buffer); break;
case FileEaInformation: Status = RxQueryEaInfo(Context, Buffer); break;
case FileNameInformation: Status = RxQueryNameInfo(Context, Buffer); break;
case FileAllInformation: SET_SIZE_AND_QUERY(0, RxQueryBasicInfo); if (!NT_SUCCESS(Status)) { break; }
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo); if (!NT_SUCCESS(Status)) { break; }
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) + sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo); if (!NT_SUCCESS(Status)) { break; }
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) + sizeof(FILE_STANDARD_INFORMATION) + sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo); if (!NT_SUCCESS(Status)) { break; }
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) + sizeof(FILE_STANDARD_INFORMATION) + sizeof(FILE_INTERNAL_INFORMATION) + sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo); if (!NT_SUCCESS(Status)) { break; }
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) + sizeof(FILE_STANDARD_INFORMATION) + sizeof(FILE_INTERNAL_INFORMATION) + sizeof(FILE_EA_INFORMATION) + sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo); break;
case FileAlternateNameInformation: Status = RxQueryAlternateNameInfo(Context, Buffer); break;
case FilePipeInformation: case FilePipeLocalInformation: case FilePipeRemoteInformation: Status = RxQueryPipeInfo(Context, Buffer); break;
case FileCompressionInformation: Status = RxQueryCompressedInfo(Context, Buffer); break;
default: Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer); Status = Context->IoStatusBlock.Status; break; }
if (Context->Info.Length < 0) { Status = STATUS_BUFFER_OVERFLOW; Context->Info.Length = Stack->Parameters.QueryFile.Length; }
Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length; } _SEH2_FINALLY { if (Locked) { RxReleaseFcb(Context, Fcb); } } _SEH2_END;
DPRINT("Status: %x\n", Status); return Status;
#undef SET_SIZE_AND_QUERY}
NTSTATUSNTAPIRxCommonQueryQuotaInformation( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonQuerySecurity( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxCommonQueryVolumeInformation( PRX_CONTEXT Context){ PIRP Irp; PFCB Fcb; PFOBX Fobx; NTSTATUS Status; PIO_STACK_LOCATION Stack;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb; Fobx = (PFOBX)Context->pFobx;
DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
Irp = Context->CurrentIrp; Stack = Context->CurrentIrpSp; DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length, Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass; Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer; Context->Info.Length = Stack->Parameters.QueryVolume.Length;
/* Forward to mini-rdr */ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
/* Post request if mini-rdr asked to */ if (Context->PostRequest) { Status = RxFsdPostRequest(Context); } else { Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length; }
DPRINT("Status: %x\n", Status); return Status;}
NTSTATUSNTAPIRxCommonRead( PRX_CONTEXT RxContext){ PFCB Fcb; PIRP Irp; PFOBX Fobx; NTSTATUS Status; PNET_ROOT NetRoot; PVOID SystemBuffer; PFILE_OBJECT FileObject; LARGE_INTEGER ByteOffset; PIO_STACK_LOCATION Stack; PLOWIO_CONTEXT LowIoContext; PRDBSS_DEVICE_OBJECT RxDeviceObject; ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber; BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
PAGED_CODE();
Fcb = (PFCB)RxContext->pFcb; Fobx = (PFOBX)RxContext->pFobx; DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
/* Get some parameters */ Irp = RxContext->CurrentIrp; Stack = RxContext->CurrentIrpSp; CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE); Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP); ReadLength = Stack->Parameters.Read.Length; ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart; DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart, (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
RxItsTheSameContext();
Irp->IoStatus.Information = 0;
/* Should the read be loud - so far, it's just ignored on ReactOS: * s/DPRINT/DPRINT1/g will make it loud */ LowIoContext = &RxContext->LowIoContext; CheckForLoudOperations(RxContext); if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS)) { DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n", ByteOffset, ReadLength, Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize); }
RxDeviceObject = RxContext->RxDeviceObject; /* Update stats */ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK) { InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset) { InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations); } Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
if (PagingIo) { ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength); } else if (NoCache) { ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength); } else { ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength); } }
/* A pagefile cannot be a pipe */ IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE; if (IsPipe && PagingIo) { return STATUS_INVALID_DEVICE_REQUEST; }
/* Null-length read is no-op */ if (ReadLength == 0) { return STATUS_SUCCESS; }
/* Validate FCB type */ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB) { return STATUS_INVALID_DEVICE_REQUEST; }
/* Init the lowio context for possible forward */ RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
PostRequest = FALSE; ReadCachingDisabled = FALSE; OwnerSet = FALSE; ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED); FileObject = Stack->FileObject; NetRoot = (PNET_ROOT)Fcb->pNetRoot; _SEH2_TRY { LONGLONG FileSize;
/* If no caching, make sure current Cc data have been flushed */ if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL) { Status = RxAcquireExclusiveFcb(RxContext, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { PostRequest = TRUE; _SEH2_LEAVE; } else if (Status != STATUS_SUCCESS) { _SEH2_LEAVE; }
ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE); CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus); RxReleasePagingIoResource(RxContext, Fcb);
if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; _SEH2_LEAVE; }
RxAcquirePagingIoResource(RxContext, Fcb); RxReleasePagingIoResource(RxContext, Fcb); }
/* Acquire the appropriate lock */ if (PagingIo && !ReadCachingEnabled) { ASSERT(!IsPipe);
if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait)) { PostRequest = TRUE; _SEH2_LEAVE; }
if (!CanWait) { LowIoContext->Resource = Fcb->Header.PagingIoResource; } } else { if (!ReadCachingEnabled) { if (!CanWait && NoCache) { Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { DPRINT1("RdAsyLNG %x\n", RxContext); PostRequest = TRUE; _SEH2_LEAVE; } if (Status != STATUS_SUCCESS) { DPRINT1("RdAsyOthr %x\n", RxContext); _SEH2_LEAVE; }
if (RxIsFcbAcquiredShared(Fcb) <= 0xF000) { LowIoContext->Resource = Fcb->Header.Resource; } else { PostRequest = TRUE; _SEH2_LEAVE; } } else { Status = RxAcquireSharedFcb(RxContext, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { PostRequest = TRUE; _SEH2_LEAVE; } else if (Status != STATUS_SUCCESS) { _SEH2_LEAVE; } } } }
RxItsTheSameContext();
ReadCachingDisabled = (ReadCachingEnabled == FALSE); if (IsPipe) { UNIMPLEMENTED; }
RxGetFileSizeWithLock(Fcb, &FileSize);
/* Make sure FLOCK doesn't conflict */ if (!PagingIo) { if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; _SEH2_LEAVE; } }
/* Validate byteoffset vs length */ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED)) { if (ByteOffset.QuadPart >= FileSize) { Status = STATUS_END_OF_FILE; _SEH2_LEAVE; }
if (ReadLength > FileSize - ByteOffset.QuadPart) { ReadLength = FileSize - ByteOffset.QuadPart; } }
/* Read with Cc! */ if (!PagingIo && !NoCache && ReadCachingEnabled && !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING)) { /* File was not cached yet, do it */ if (FileObject->PrivateCacheMap == NULL) { if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { Status = STATUS_FILE_CLOSED; _SEH2_LEAVE; }
RxAdjustAllocationSizeforCC(Fcb);
CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, FALSE, &RxData.CacheManagerCallbacks, Fcb);
if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD)) { CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE); } else { CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE); SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED); }
CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity); }
/* This should never happen - fix your RDR */ if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL)) { ASSERT(FALSE); ASSERT(CanWait);
CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; ASSERT(NT_SUCCESS(Status)); } else { /* Map buffer */ SystemBuffer = RxNewMapUserBuffer(RxContext); if (SystemBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; }
SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
RxItsTheSameContext();
/* Perform the read */ if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus)) { if (!ReadCachingEnabled) { ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED); }
RxItsTheSameContext();
PostRequest = TRUE; _SEH2_LEAVE; }
if (!ReadCachingEnabled) { ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED); }
Status = Irp->IoStatus.Status; ASSERT(NT_SUCCESS(Status)); } } else { /* Validate the reading */ if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) && ByteOffset.QuadPart >= 4096) { CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE); ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED); }
/* If it's consistent, forward to mini-rdr */ if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) || ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart) { LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength; LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
RxItsTheSameContext();
if (InFsp && ReadCachingDisabled) { ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource), (PVOID)((ULONG_PTR)RxContext | 3)); OwnerSet = TRUE; }
Status = RxLowIoReadShell(RxContext);
RxItsTheSameContext(); } else { if (ByteOffset.QuadPart > FileSize) { ReadLength = 0; Irp->IoStatus.Information = ReadLength; _SEH2_LEAVE; }
if (ByteOffset.QuadPart + ReadLength > FileSize) { ReadLength = FileSize - ByteOffset.QuadPart; }
SystemBuffer = RxNewMapUserBuffer(RxContext); RtlZeroMemory(SystemBuffer, ReadLength); Irp->IoStatus.Information = ReadLength; } } } _SEH2_FINALLY { RxItsTheSameContext();
/* Post if required */ if (PostRequest) { InterlockedIncrement((volatile long *)&RxContext->ReferenceCount); Status = RxFsdPostRequest(RxContext); } else { /* Update FO in case of sync IO */ if (!IsPipe && !PagingIo) { if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } } }
/* Set FastIo if read was a success */ if (NT_SUCCESS(Status) && Status != STATUS_PENDING) { if (!IsPipe && !PagingIo) { SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ); } }
/* In case we're done (not expected any further processing */ if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest) { /* Release everything that can be */ if (ReadCachingDisabled) { if (PagingIo) { if (OwnerSet) { RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId); } else { RxReleasePagingIoResource(RxContext, Fcb); } } else { if (OwnerSet) { RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId); } else { RxReleaseFcb(RxContext, Fcb); } } }
/* Dereference/Delete context */ if (PostRequest) { RxDereferenceAndDeleteRxContext(RxContext); } else { if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) { RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue); } }
/* We cannot return more than asked */ if (Status == STATUS_SUCCESS) { ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length); } } else { ASSERT(!Sync);
RxDereferenceAndDeleteRxContext(RxContext); } } _SEH2_END;
return Status;}
NTSTATUSNTAPIRxCommonSetEa( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxCommonSetInformation( PRX_CONTEXT Context){ PIRP Irp; PFCB Fcb; PFOBX Fobx; NTSTATUS Status; PNET_ROOT NetRoot; PIO_STACK_LOCATION Stack; FILE_INFORMATION_CLASS Class; BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb; Fobx = (PFOBX)Context->pFobx; DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
Irp = Context->CurrentIrp; Stack = Context->CurrentIrpSp; Class = Stack->Parameters.SetFile.FileInformationClass; DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n", Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length, Class, Stack->Parameters.SetFile.ReplaceIfExists);
Status = STATUS_SUCCESS; CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT); FcbTableAcquired = FALSE; FcbAcquired = FALSE; NetRoot = (PNET_ROOT)Fcb->pNetRoot;
#define _SEH2_TRY_RETURN(S) S; goto try_exit
_SEH2_TRY { /* Valide the node type first */ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) { if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE) { if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) { Status = STATUS_SUCCESS; } } else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE) { if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT) { _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED); } else { DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb)); _SEH2_TRY_RETURN(Status = STATUS_INVALID_PARAMETER); } } }
/* We don't autorize advance operation */ if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly) { DPRINT1("Not allowed\n");
_SEH2_TRY_RETURN(Status = STATUS_SUCCESS); }
/* For these to classes, we'll have to deal with the FCB table (removal) * We thus need the exclusive FCB table lock */ if (Class == FileDispositionInformation || Class == FileRenameInformation) { RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb); RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait)) { Context->PostRequest = TRUE; _SEH2_TRY_RETURN(Status = STATUS_PENDING); }
FcbTableAcquired = TRUE; }
/* Finally, if not paging file, we need exclusive FCB lock */ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) { Status = RxAcquireExclusiveFcb(Context, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { Context->PostRequest = TRUE; _SEH2_TRY_RETURN(Status = STATUS_SUCCESS); } else if (Status != STATUS_SUCCESS) { _SEH2_LEAVE; }
FcbAcquired = TRUE; }
Status = STATUS_SUCCESS;
/* And now, perform the job! */ switch (Class) { case FileBasicInformation: Status = RxSetBasicInfo(Context); break;
case FileDispositionInformation: { PFILE_DISPOSITION_INFORMATION FDI;
/* Check whether user wants deletion */ FDI = Irp->AssociatedIrp.SystemBuffer; if (FDI->DeleteFile) { /* If so, check whether it's doable */ if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete)) { Status = STATUS_CANNOT_DELETE; }
/* And if doable, already remove from FCB table */ if (Status == STATUS_SUCCESS) { ASSERT(FcbAcquired && FcbTableAcquired); RxRemoveNameNetFcb(Fcb);
RxReleaseFcbTableLock(&NetRoot->FcbTable); FcbTableAcquired = FALSE; } }
/* If it succeed, perform the operation */ if (Status == STATUS_SUCCESS) { Status = RxSetDispositionInfo(Context); }
break; }
case FilePositionInformation: Status = RxSetPositionInfo(Context); break;
case FileAllocationInformation: Status = RxSetAllocationInfo(Context); break;
case FileEndOfFileInformation: Status = RxSetEndOfFileInfo(Context); break;
case FilePipeInformation: case FilePipeLocalInformation: case FilePipeRemoteInformation: Status = RxSetPipeInfo(Context); break;
case FileRenameInformation: case FileLinkInformation: case FileMoveClusterInformation: /* If we can wait, try to perform the operation right now */ if (CanWait) { /* Of course, collapsing is not doable anymore, file is * in an inbetween state */ ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
/* Set the information */ Status = RxSetRenameInfo(Context); /* If it succeed, drop the current entry from FCB table */ if (Status == STATUS_SUCCESS && Class == FileRenameInformation) { ASSERT(FcbAcquired && FcbTableAcquired); RxRemoveNameNetFcb(Fcb); } _SEH2_TRY_RETURN(Status); } /* Can't wait? Post for async retry */ else { Status = RxFsdPostRequest(Context); _SEH2_TRY_RETURN(Status); } break;
case FileValidDataLengthInformation: if (!MmCanFileBeTruncated(&Fcb->NonPaged->SectionObjectPointers, NULL)) { Status = STATUS_USER_MAPPED_FILE; } break;
case FileShortNameInformation: Status = RxSetSimpleInfo(Context); break;
default: DPRINT1("Insupported class: %x\n", Class); Status = STATUS_INVALID_PARAMETER;
break; }
try_exit: NOTHING; /* If mini-rdr was OK and wants a re-post on this, do it */ if (Status == STATUS_SUCCESS) { if (Context->PostRequest) { Status = RxFsdPostRequest(Context); } } } _SEH2_FINALLY { /* Release any acquired lock */ if (FcbAcquired) { RxReleaseFcb(Context, Fcb); }
if (FcbTableAcquired) { RxReleaseFcbTableLock(&NetRoot->FcbTable); } } _SEH2_END;
#undef _SEH2_TRY_RETURN
return Status;}
NTSTATUSNTAPIRxCommonSetQuotaInformation( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonSetSecurity( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonSetVolumeInformation( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonUnimplemented( PRX_CONTEXT Context){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIRxCommonWrite( PRX_CONTEXT RxContext){ PIRP Irp; PFCB Fcb; PFOBX Fobx; NTSTATUS Status; PNET_ROOT NetRoot; PSRV_OPEN SrvOpen; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; LARGE_INTEGER ByteOffset; NODE_TYPE_CODE NodeTypeCode; PLOWIO_CONTEXT LowIoContext; PRDBSS_DEVICE_OBJECT RxDeviceObject; ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber; LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength; BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
PAGED_CODE();
Fcb = (PFCB)RxContext->pFcb; NodeTypeCode = NodeType(Fcb); /* Validate FCB type */ if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB && NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT) { return STATUS_INVALID_DEVICE_REQUEST; }
/* We'll write to file, keep track of it */ Fcb->IsFileWritten = TRUE;
Stack = RxContext->CurrentIrpSp; /* Set write through if asked */ if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH)) { SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH); }
Fobx = (PFOBX)RxContext->pFobx; DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
/* Get some parameters */ Irp = RxContext->CurrentIrp; NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED); InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP); CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE); Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); WriteLength = Stack->Parameters.Write.Length; ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart; DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart, (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
RxItsTheSameContext();
RxContext->FcbResourceAcquired = FALSE; RxContext->FcbPagingIoResourceAcquired = FALSE;
LowIoContext = &RxContext->LowIoContext; CheckForLoudOperations(RxContext); if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS)) { DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n", ByteOffset, WriteLength, Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize); }
RxDeviceObject = RxContext->RxDeviceObject; /* Update stats */ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK) { InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset) { InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations); } Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
if (PagingIo) { ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingWriteBytesRequested, WriteLength); } else if (NoCache) { ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingWriteBytesRequested, WriteLength); } else { ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheWriteBytesRequested, WriteLength); } }
NetRoot = (PNET_ROOT)Fcb->NetRoot; IsPipe = (NetRoot->Type == NET_ROOT_PIPE); /* Keep track for normal writes */ if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD) { NormalFile = TRUE; } else { NormalFile = FALSE; }
/* Zero-length write is immediate success */ if (NormalFile && WriteLength == 0) { return STATUS_SUCCESS; }
/* Check whether we have input data */ if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL) { return STATUS_INVALID_PARAMETER; }
/* Are we writing to EOF? */ WriteToEof = ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == -1)); /* FIXME: validate length/offset */
/* Get our SRV_OPEN in case of normal write */ if (Fobx != NULL) { SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen; } else { SrvOpen = NULL; }
FileObject = Stack->FileObject;
/* If we have caching enabled, check whether we have to defer write */ if (!NoCache) { if (RxWriteCacheingAllowed(Fcb, SrvOpen)) { if (!CcCanIWrite(FileObject, WriteLength, (CanWait && !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)), BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE))) { BOOLEAN Retrying;
Retrying = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
RxPrePostIrp(RxContext, Irp);
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)RxAddToWorkque, RxContext, Irp, WriteLength, Retrying);
return STATUS_PENDING; } } }
/* Initialize the low IO context for write */ RxInitializeLowIoContext(LowIoContext, LOWIO_OP_WRITE);
/* Initialize our (many) booleans */ RecursiveWriteThrough = FALSE; CalledByLazyWriter = FALSE; SwitchBackToAsync = FALSE; ExtendingFile = FALSE; ExtendingValidData = FALSE; UnwindOutstandingAsync = FALSE; ResourceOwnerSet = FALSE; PostIrp = FALSE; ContextReferenced = FALSE;
#define _SEH2_TRY_RETURN(S) S; goto try_exit
_SEH2_TRY { /* No volume FCB here! */ ASSERT((NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE) || (NodeTypeCode == RDBSS_NTC_SPOOLFILE) || (NodeTypeCode == RDBSS_NTC_MAILSLOT));
/* Writing to EOF on a paging file is non sense */ ASSERT(!(WriteToEof && PagingIo));
RxItsTheSameContext();
/* Start locking stuff */ if (!PagingIo && !NoPreposting) { /* If it's already acquired, all fine */ if (RxContext->FcbResourceAcquired) { ASSERT(!IsPipe); } else { /* Otherwise, try to acquire shared (excepted for pipes) */ if (IsPipe) { Status = RxAcquireExclusiveFcb(RxContext, Fcb); } else if (CanWait || (!NoCache && RxWriteCacheingAllowed(Fcb, SrvOpen))) { Status = RxAcquireSharedFcb(RxContext, Fcb); } else { Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb); }
/* We'll post IRP to retry */ if (Status == STATUS_LOCK_NOT_GRANTED) { PostIrp = TRUE; DPRINT1("Failed to acquire lock!\n"); _SEH2_TRY_RETURN(Status); }
/* We'll just fail */ if (Status != STATUS_SUCCESS) { _SEH2_TRY_RETURN(Status); }
/* Resource acquired */ RxContext->FcbResourceAcquired = TRUE; }
/* At that point, resource is acquired */ if (IsPipe) { ASSERT(RxContext->FcbResourceAcquired); } else { BOOLEAN IsDormant;
/* Now, check whether we have to promote shared lock */ if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL) { IsDormant = BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT); } else { IsDormant = FALSE; }
/* We're writing beyond VDL, we'll need an exclusive lock if not dormant */ if (RxIsFcbAcquiredShared(Fcb) && ByteOffset.QuadPart + WriteLength > Fcb->Header.ValidDataLength.QuadPart) { if (!IsDormant) { RxReleaseFcb(RxContext, Fcb); RxContext->FcbResourceAcquired = FALSE;
Status = RxAcquireExclusiveFcb(RxContext, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { PostIrp = TRUE; DPRINT1("Failed to acquire lock!\n"); _SEH2_TRY_RETURN(Status); }
if (Status != STATUS_SUCCESS) { _SEH2_TRY_RETURN(Status); }
RxContext->FcbResourceAcquired = TRUE; } }
/* If we're writing in VDL, or if we're dormant, shared lock is enough */ if (ByteOffset.QuadPart + WriteLength <= Fcb->Header.ValidDataLength.QuadPart || IsDormant) { if (RxIsFcbAcquiredExclusive(Fcb)) { RxConvertToSharedFcb(RxContext, Fcb); } } else { /* We're extending file, disable collapsing */ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
DPRINT("Disabling collapsing\n");
if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL) { SetFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING); } }
ASSERT(RxContext->FcbResourceAcquired); }
/* Keep track of the acquired resource */ LowIoContext->Resource = Fcb->Header.Resource; } else { /* Paging IO */ ASSERT(!IsPipe);
/* Lock the paging resource */ RxAcquirePagingIoResourceShared(RxContext, Fcb, TRUE);
/* Keep track of the acquired resource */ LowIoContext->Resource = Fcb->Header.PagingIoResource; }
if (IsPipe) { UNIMPLEMENTED; _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED); }
/* If it's a non cached write, or if caching is disallowed */ if (NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen)) { /* If cache was previously enabled, we'll have to flush before writing */ if (!PagingIo && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) { LARGE_INTEGER FlushOffset;
/* FCB is lock */ ASSERT(RxIsFcbAcquiredExclusive(Fcb) || RxIsFcbAcquiredShared(Fcb));
/* If shared, we'll have to relock exclusive */ if (!RxIsFcbAcquiredExclusive(Fcb)) { /* Release and retry exclusive */ RxReleaseFcb(RxContext, Fcb); RxContext->FcbResourceAcquired = FALSE;
Status = RxAcquireExclusiveFcb(RxContext, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { PostIrp = TRUE; DPRINT1("Failed to acquire lock for flush!\n"); _SEH2_TRY_RETURN(Status); }
if (Status != STATUS_SUCCESS) { _SEH2_TRY_RETURN(Status); }
RxContext->FcbResourceAcquired = TRUE; }
/* Get the length to flush */ if (WriteToEof) { RxGetFileSizeWithLock(Fcb, &FlushOffset.QuadPart); } else { FlushOffset.QuadPart = ByteOffset.QuadPart; }
/* Perform the flushing */ RxAcquirePagingIoResource(RxContext, Fcb); CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, &FlushOffset, WriteLength, &Irp->IoStatus); RxReleasePagingIoResource(RxContext, Fcb);
/* Cannot continue if flushing failed */ if (!NT_SUCCESS(Irp->IoStatus.Status)) { _SEH2_TRY_RETURN(Status = Irp->IoStatus.Status); }
/* Synchronize */ RxAcquirePagingIoResource(RxContext, Fcb); RxReleasePagingIoResource(RxContext, Fcb);
/* And purge */ CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, &FlushOffset, WriteLength, FALSE); } }
/* If not paging IO, check if write is allowed */ if (!PagingIo) { if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp)) { _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT); } }
/* Get file sizes */ ValidDataLength = Fcb->Header.ValidDataLength.QuadPart; RxGetFileSizeWithLock(Fcb, &FileSize); ASSERT(ValidDataLength <= FileSize);
/* If paging IO, we cannot write past file size * so fix write length if needed */ if (PagingIo) { if (ByteOffset.QuadPart >= FileSize) { _SEH2_TRY_RETURN(Status = STATUS_SUCCESS); }
if (WriteLength > FileSize - ByteOffset.QuadPart) { WriteLength = FileSize - ByteOffset.QuadPart; } }
/* If we're being called by the lazywrite */ if (Fcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread()) { CalledByLazyWriter = TRUE;
/* Fail if we're beyong VDL */ if (BooleanFlagOn(Fcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE)) { if ((ByteOffset.QuadPart + WriteLength > ValidDataLength) && (ByteOffset.QuadPart < FileSize)) { if (ByteOffset.QuadPart + WriteLength > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT); } } } }
/* If that's a recursive synchronous page write */ if (BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL)) { PIRP TopIrp;
/* Check the top level IRP on the FastIO path */ TopIrp = RxGetTopIrpIfRdbssIrp(); if (TopIrp != NULL && (ULONG_PTR)TopIrp > FSRTL_FAST_IO_TOP_LEVEL_IRP) { PIO_STACK_LOCATION IrpStack;
ASSERT(NodeType(TopIrp) == IO_TYPE_IRP);
/* If the top level IRP was a cached write for this file, keep track */ IrpStack = IoGetCurrentIrpStackLocation(TopIrp); if (IrpStack->MajorFunction == IRP_MJ_WRITE && IrpStack->FileObject->FsContext == FileObject->FsContext) { RecursiveWriteThrough = TRUE; SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH); } } }
/* Now, deal with file size and VDL */ if (!CalledByLazyWriter && !RecursiveWriteThrough && (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength)) { /* Not sync? Let's make it sync, just the time we extended */ if (!Sync) { CanWait = TRUE; SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); Sync = TRUE;
/* Keep track we'll have to switch back to async */ if (NoCache) { SwitchBackToAsync = TRUE; } }
/* Release all the locks */ RxWriteReleaseResources(RxContext, 0);
/* Acquire exclusive */ Status = RxAcquireExclusiveFcb(RxContext, Fcb); if (Status == STATUS_LOCK_NOT_GRANTED) { PostIrp = TRUE; DPRINT1("Failed to acquire lock for extension!\n"); _SEH2_TRY_RETURN(Status); }
if (Status != STATUS_SUCCESS) { _SEH2_TRY_RETURN(Status); }
RxContext->FcbResourceAcquired = TRUE;
RxItsTheSameContext();
/* Get the sizes again, to be sure they didn't change in the meantime */ ValidDataLength = Fcb->Header.ValidDataLength.QuadPart; RxGetFileSizeWithLock(Fcb, &FileSize); ASSERT(ValidDataLength <= FileSize);
/* Check we can switch back to async? */ if ((SwitchBackToAsync && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) || (ByteOffset.QuadPart + WriteLength > FileSize) || RxNoAsync) { SwitchBackToAsync = FALSE; }
/* If paging IO, check we don't try to extend the file */ if (PagingIo) { if (ByteOffset.QuadPart >= FileSize) { _SEH2_TRY_RETURN(Status = STATUS_SUCCESS); }
if (WriteLength > FileSize - ByteOffset.QuadPart) { WriteLength = FileSize - ByteOffset.QuadPart; } } }
/* Save our initial sizes for potential rollback */ InitialFileSize = FileSize; InitialValidDataLength = ValidDataLength; /* If writing to EOF, update byte offset with file size */ if (WriteToEof) { ByteOffset.QuadPart = FileSize; }
/* Check again whether we're allowed to write */ if (!PagingIo) { if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp )) { _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT); }
/* Do we have to extend? */ if (NormalFile && (ByteOffset.QuadPart + WriteLength > FileSize)) { DPRINT("Need to extend file\n"); ExtendingFile = TRUE; SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE); } }
/* Let's start to extend */ if (ExtendingFile) { /* If we're past allocating, inform mini-rdr */ FileSize = ByteOffset.QuadPart + WriteLength; if (FileSize > Fcb->Header.AllocationSize.QuadPart) { LARGE_INTEGER NewAllocationSize;
DPRINT("Extending %p\n", RxContext);
if (NoCache) { C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER)); MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForNonCache, (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize)); } else { C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER)); MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForCache, (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize)); }
if (!NT_SUCCESS(Status)) { _SEH2_TRY_RETURN(Status); }
if (FileSize > NewAllocationSize.QuadPart) { NewAllocationSize.QuadPart = FileSize; }
/* And update FCB */ Fcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart; }
/* Set the new sizes */ RxSetFileSizeWithLock(Fcb, &FileSize); RxAdjustAllocationSizeforCC(Fcb);
/* And inform Cc */ if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); } }
/* Do we have to extend VDL? */ if (!CalledByLazyWriter && !RecursiveWriteThrough) { if (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength) { ExtendingValidData = TRUE; SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL); } }
/* If none cached write */ if (PagingIo || NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen)) { /* Switch back to async, if asked to */ if (SwitchBackToAsync) { CanWait = FALSE; Sync = FALSE;
ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); }
/* If not synchronous, keep track of writes to be finished */ if (!Sync) { if (Fcb->NonPaged->OutstandingAsyncEvent == NULL) { Fcb->NonPaged->OutstandingAsyncEvent = &Fcb->NonPaged->TheActualEvent; KeInitializeEvent(Fcb->NonPaged->OutstandingAsyncEvent, NotificationEvent, FALSE); }
if (ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites, 1, &RxStrucSupSpinLock) == 0) { KeClearEvent(Fcb->NonPaged->OutstandingAsyncEvent); }
UnwindOutstandingAsync = TRUE; LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged; }
/* Set our LOWIO_CONTEXT information */ LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart; LowIoContext->ParamsFor.ReadWrite.ByteCount = WriteLength;
RxItsTheSameContext();
/* We have to be locked */ ASSERT(RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired);
/* Update thread ID if we're in FSP */ if (InFsp) { LowIoContext->ResourceThreadId = (ULONG_PTR)RxContext | 3;
if (RxContext->FcbResourceAcquired) { ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)((ULONG_PTR)RxContext | 3)); }
if (RxContext->FcbPagingIoResourceAcquired) { ExSetResourceOwnerPointer(Fcb->Header.PagingIoResource, (PVOID)((ULONG_PTR)RxContext | 3)); }
ResourceOwnerSet = TRUE; }
/* And perform the write */ Status = RxLowIoWriteShell(RxContext);
RxItsTheSameContext();
/* Not outstanding write anymore */ if (UnwindOutstandingAsync && Status == STATUS_PENDING) { UnwindOutstandingAsync = FALSE; } } /* Cached write */ else { /* If cache wasn't enabled yet, do it */ if (FileObject->PrivateCacheMap == NULL) { if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { _SEH2_TRY_RETURN(Status = STATUS_FILE_CLOSED); }
RxAdjustAllocationSizeforCC(Fcb);
CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, FALSE, &RxData.CacheManagerCallbacks, Fcb);
CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity); }
/* If that's a MDL backed write */ if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL)) { /* Shouldn't happen */ ASSERT(FALSE); ASSERT(CanWait);
/* Perform it, though */ CcPrepareMdlWrite(FileObject, &ByteOffset, WriteLength, &Irp->MdlAddress, &Irp->IoStatus);
Status = Irp->IoStatus.Status; } else { PVOID SystemBuffer; ULONG BreakpointsSave;
/* Map the user buffer */ SystemBuffer = RxNewMapUserBuffer(RxContext); if (SystemBuffer == NULL) { _SEH2_TRY_RETURN(Status = STATUS_INSUFFICIENT_RESOURCES); }
RxSaveAndSetExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
RxItsTheSameContext();
/* And deal with Cc */ if (!CcCopyWrite(FileObject, &ByteOffset, WriteLength, CanWait, SystemBuffer)) { RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
RxItsTheSameContext();
DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n", FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
PostIrp = TRUE; } else { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = WriteLength;
RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
RxItsTheSameContext();
DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n", FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status); } } }
try_exit: NOTHING;
/* If we've to post the IRP */ if (PostIrp) { /* Reset the file size if required */ if (ExtendingFile && !IsPipe) { ASSERT(RxWriteCacheingAllowed(Fcb, SrvOpen)); ASSERT(Fcb->Header.PagingIoResource != NULL);
RxAcquirePagingIoResource(RxContext, Fcb); RxSetFileSizeWithLock(Fcb, &InitialFileSize); RxReleasePagingIoResource(RxContext, Fcb);
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) { *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize; } }
InterlockedIncrement((volatile long *)&RxContext->ReferenceCount); ContextReferenced = TRUE;
/* Release locks */ ASSERT(!ResourceOwnerSet); RxWriteReleaseResources(RxContext, ResourceOwnerSet);
#ifdef RDBSS_TRACKER ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);#endif
/* And post the request */ Status = RxFsdPostRequest(RxContext); } else { if (!IsPipe) { /* Update FILE_OBJECT if synchronous write succeed */ if (!PagingIo) { if (NT_SUCCESS(Status) && BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } }
/* If write succeed, ,also update FILE_OBJECT flags */ if (NT_SUCCESS(Status) && Status != STATUS_PENDING) { /* File was modified */ if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); }
/* If was even extended */ if (ExtendingFile) { SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); }
/* If VDL was extended, update FCB and inform Cc */ if (ExtendingValidData) { LONGLONG LastOffset;
LastOffset = ByteOffset.QuadPart + Irp->IoStatus.Information; if (FileSize < LastOffset) { LastOffset = FileSize; }
Fcb->Header.ValidDataLength.QuadPart = LastOffset;
if (NoCache && CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); } } } } } } _SEH2_FINALLY { /* Finally, if we failed while extension was required */ if (_SEH2_AbnormalTermination() && (ExtendingFile || ExtendingValidData)) { /* Rollback! */ if (!IsPipe) { ASSERT(Fcb->Header.PagingIoResource != NULL);
RxAcquirePagingIoResource(RxContext, Fcb); RxSetFileSizeWithLock(Fcb, &InitialFileSize); Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength; RxReleasePagingIoResource(RxContext, Fcb);
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) { *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize; } } }
/* One async write less */ if (UnwindOutstandingAsync) { ASSERT(!IsPipe);
ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites, -1, &RxStrucSupSpinLock); KeSetEvent(Fcb->NonPaged->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE); }
/* And now, cleanup everything */ if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostIrp) { /* If we didn't post, release every lock (for posting, it's already done) */ if (!PostIrp) { RxWriteReleaseResources(RxContext, ResourceOwnerSet); }
/* If the context was referenced - posting, dereference it */ if (ContextReferenced) { RxDereferenceAndDeleteRxContext(RxContext); }
/* If that's a pipe operation, resume any blocked one */ if (!PostIrp) { if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) { RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue); } }
/* Sanity check for write */ if (Status == STATUS_SUCCESS) { ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length); } } /* Just dereference our context */ else { ASSERT(!Sync); RxDereferenceAndDeleteRxContext(RxContext); } } _SEH2_END;
#undef _SEH2_TRY_RETURN
return Status;}
/* * @implemented */NTSTATUSNTAPIRxCompleteMdl( IN PRX_CONTEXT RxContext){ PIRP Irp; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack;
#define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
PAGED_CODE();
Irp = RxContext->CurrentIrp; Stack = RxContext->CurrentIrpSp; FileObject = Stack->FileObject;
/* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */ switch (RxContext->MajorFunction) { /* Call the Cc function */ case IRP_MJ_READ: CcMdlReadComplete(FileObject, Irp->MdlAddress); break;
case IRP_MJ_WRITE: /* If here, we can wait */ ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
/* Call the Cc function */ CcMdlWriteComplete(FileObject, &Stack->Parameters.Write.ByteOffset, Irp->MdlAddress);
Irp->IoStatus.Status = STATUS_SUCCESS; break;
default: DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext->MajorFunction); RxBugCheck(RxContext->MajorFunction, 0, 0); break; }
/* MDL was freed */ Irp->MdlAddress = NULL;
/* And complete the IRP */ RxCompleteRequest(RxContext, STATUS_SUCCESS);
#undef BugCheckFileId
return STATUS_SUCCESS;}
/* * @implemented */VOIDRxConjureOriginalName( PFCB Fcb, PFOBX Fobx, PULONG ActualNameLength, PWCHAR OriginalName, PLONG LengthRemaining, RX_NAME_CONJURING_METHODS NameConjuringMethod){ PWSTR Prefix, Name; PV_NET_ROOT VNetRoot; USHORT PrefixLength, NameLength, ToCopy;
PAGED_CODE();
VNetRoot = Fcb->VNetRoot; /* We will use the prefix contained in NET_ROOT, if we don't have * a V_NET_ROOT, or if it wasn't null deviced or if we already have * a UNC path */ if (VNetRoot == NULL || VNetRoot->PrefixEntry.Prefix.Buffer[1] != L';' || BooleanFlagOn(Fobx->Flags, FOBX_FLAG_UNC_NAME)) { Prefix = ((PNET_ROOT)Fcb->pNetRoot)->PrefixEntry.Prefix.Buffer; PrefixLength = ((PNET_ROOT)Fcb->pNetRoot)->PrefixEntry.Prefix.Length; NameLength = 0;
/* In that case, keep track that we will have a prefix as buffer */ NameConjuringMethod = VNetRoot_As_Prefix; } else { ASSERT(NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
/* Otherwise, return the prefix from our V_NET_ROOT */ Prefix = VNetRoot->PrefixEntry.Prefix.Buffer; PrefixLength = VNetRoot->PrefixEntry.Prefix.Length; NameLength = VNetRoot->NamePrefix.Length;
/* If we want a UNC path, skip potential device */ if (NameConjuringMethod == VNetRoot_As_UNC_Name) { do { ++Prefix; PrefixLength -= sizeof(WCHAR); } while (PrefixLength > 0 && Prefix[0] != L'\\'); } }
/* If we added an extra backslash, skip it */ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ADDEDBACKSLASH)) { NameLength += sizeof(WCHAR); }
/* If we're asked for a drive letter, skip the prefix */ if (NameConjuringMethod == VNetRoot_As_DriveLetter) { PrefixLength = 0;
/* And make sure we arrive at a backslash */ if (Fcb->FcbTableEntry.Path.Length > NameLength && Fcb->FcbTableEntry.Path.Buffer[NameLength / sizeof(WCHAR)] != L'\\') { NameLength -= sizeof(WCHAR); } } else { /* Prepare to copy the prefix, make sure not to overflow */ if (*LengthRemaining >= PrefixLength) { /* Copy everything */ ToCopy = PrefixLength; *LengthRemaining = *LengthRemaining - PrefixLength; } else { /* Copy as much as we can */ ToCopy = *LengthRemaining; /* And return failure */ *LengthRemaining = -1; }
/* Copy the prefix */ RtlCopyMemory(OriginalName, Prefix, ToCopy); }
/* Do we have a name to copy now? */ if (Fcb->FcbTableEntry.Path.Length > NameLength) { ToCopy = Fcb->FcbTableEntry.Path.Length - NameLength; Name = Fcb->FcbTableEntry.Path.Buffer; } else { /* Just use slash for now */ ToCopy = sizeof(WCHAR); NameLength = 0; Name = L"\\"; }
/* Total length we will have in the output buffer (if everything is alright) */ *ActualNameLength = ToCopy + PrefixLength; /* If we still have room to write data */ if (*LengthRemaining != -1) { /* If we can copy everything, it's fine! */ if (*LengthRemaining > ToCopy) { *LengthRemaining = *LengthRemaining - ToCopy; } /* Otherwise, copy as much as possible, and return failure */ else { ToCopy = *LengthRemaining; *LengthRemaining = -1; }
/* Copy name after the prefix */ RtlCopyMemory(Add2Ptr(OriginalName, PrefixLength), Add2Ptr(Name, NameLength), ToCopy); }}
/* * @implemented */VOIDRxCopyCreateParameters( IN PRX_CONTEXT RxContext){ PIRP Irp; PVOID DfsContext; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; PDFS_NAME_CONTEXT DfsNameContext; PIO_SECURITY_CONTEXT SecurityContext;
Irp = RxContext->CurrentIrp; Stack = RxContext->CurrentIrpSp; FileObject = Stack->FileObject; SecurityContext = Stack->Parameters.Create.SecurityContext;
RxContext->Create.NtCreateParameters.SecurityContext = SecurityContext; if (SecurityContext->AccessState != NULL && SecurityContext->AccessState->SecurityDescriptor != NULL) { RxContext->Create.SdLength = RtlLengthSecurityDescriptor(SecurityContext->AccessState->SecurityDescriptor); DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext->Create.NtCreateParameters.SecurityContext, RxContext->Create.SdLength); } if (SecurityContext->SecurityQos != NULL) { RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityContext->SecurityQos->ImpersonationLevel; } else { RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityImpersonation; } RxContext->Create.NtCreateParameters.DesiredAccess = SecurityContext->DesiredAccess;
RxContext->Create.NtCreateParameters.AllocationSize.QuadPart = Irp->Overlay.AllocationSize.QuadPart; RxContext->Create.NtCreateParameters.FileAttributes = Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS; RxContext->Create.NtCreateParameters.ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS; RxContext->Create.NtCreateParameters.Disposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF; RxContext->Create.NtCreateParameters.CreateOptions = Stack->Parameters.Create.Options & 0xFFFFFF;
DfsContext = FileObject->FsContext2; DfsNameContext = FileObject->FsContext; RxContext->Create.NtCreateParameters.DfsContext = DfsContext; RxContext->Create.NtCreateParameters.DfsNameContext = DfsNameContext; ASSERT(DfsContext == NULL || DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) || DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) || DfsContext == UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT) || DfsContext == UIntToPtr(DFS_USER_NAME_CONTEXT)); ASSERT(DfsNameContext == NULL || DfsNameContext->NameContextType == DFS_OPEN_CONTEXT || DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT || DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT || DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT); FileObject->FsContext2 = NULL; FileObject->FsContext = NULL;
RxContext->pFcb = NULL; RxContext->Create.ReturnedCreateInformation = 0;
/* if we stripped last \, it has to be a directory! */ if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH)) { SetFlag(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DIRECTORY_FILE); }
RxContext->Create.EaLength = Stack->Parameters.Create.EaLength; if (RxContext->Create.EaLength == 0) { RxContext->Create.EaBuffer = NULL; } else { RxContext->Create.EaBuffer = Irp->AssociatedIrp.SystemBuffer; DPRINT("EA Buffer: %p, Length: %lx\n", Irp->AssociatedIrp.SystemBuffer, RxContext->Create.EaLength); }}
NTSTATUSRxCreateFromNetRoot( PRX_CONTEXT Context, PUNICODE_STRING NetRootName){ PFCB Fcb; NTSTATUS Status; PNET_ROOT NetRoot; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; ACCESS_MASK DesiredAccess; USHORT DesiredShareAccess;
PAGED_CODE();
/* Validate that the context is consistent */ if (Context->Create.pNetRoot == NULL) { return STATUS_BAD_NETWORK_PATH; }
NetRoot = (PNET_ROOT)Context->Create.pNetRoot; if (Context->RxDeviceObject != NetRoot->pSrvCall->RxDeviceObject) { return STATUS_BAD_NETWORK_PATH; }
if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) && !BooleanFlagOn(NetRoot->pSrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER)) { return STATUS_DFS_UNAVAILABLE; }
if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) && BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT)) { return STATUS_OBJECT_TYPE_MISMATCH; }
Stack = Context->CurrentIrpSp; DesiredShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS; if (NetRoot->Type == NET_ROOT_PRINT) { DesiredShareAccess = FILE_SHARE_VALID_FLAGS; }
DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
/* Get file object */ FileObject = Stack->FileObject;
/* Do we have to open target directory for renaming? */ if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY)) { DPRINT("Opening target directory\n");
/* If we have been asked for delete, try to purge first */ if (BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, DELETE)) { RxPurgeRelatedFobxs((PNET_ROOT)Context->Create.pVNetRoot->pNetRoot, Context, ATTEMPT_FINALIZE_ON_PURGE, NULL); }
/* Create the FCB */ Fcb = RxCreateNetFcb(Context, (PV_NET_ROOT)Context->Create.pVNetRoot, NetRootName); if (Fcb == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* Fake it: it will be used only renaming */ NodeType(Fcb) = RDBSS_NTC_OPENTARGETDIR_FCB; Context->Create.FcbAcquired = FALSE; Context->Create.NetNamePrefixEntry = NULL;
/* Assign it to the FO */ FileObject->FsContext = Fcb;
/* If we have a FOBX already, check whether it's for DFS opening */ if (Context->pFobx != NULL) { /* If so, reflect this in the FOBX */ if (FileObject->FsContext2 == UIntToPtr(DFS_OPEN_CONTEXT)) { SetFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN); } else { ClearFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN); } }
/* Acquire the FCB */ Status = RxAcquireExclusiveFcb(Context, Fcb); if (Status != STATUS_SUCCESS) { return Status; }
/* Reference the FCB and release */ RxReferenceNetFcb(Fcb); RxReleaseFcb(Context, Fcb);
/* We're done! */ return STATUS_SUCCESS; }
/* Try to find (or create) the FCB for the file */ Status = RxFindOrCreateFcb(Context, NetRootName); Fcb = (PFCB)Context->pFcb; if (Fcb == NULL) { ASSERT(!NT_SUCCESS(Status)); } if (!NT_SUCCESS(Status) || Fcb == NULL) { return Status; }
if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT)) { Fcb->Header.NodeTypeCode = RDBSS_NTC_MAILSLOT; } else { Status = STATUS_MORE_PROCESSING_REQUIRED; }
/* If finding FCB worked (mailslot case), mark the FCB as good and quit */ if (NT_SUCCESS(Status)) { RxTransitionNetFcb(Fcb, Condition_Good); DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb, Fcb->Condition); ++Fcb->OpenCount; RxSetupNetFileObject(Context); return STATUS_SUCCESS; }
/* Not mailslot! */ /* Check SA for conflict */ if (Fcb->OpenCount > 0) { Status = RxCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, &Fcb->ShareAccess, FALSE, "early check per useropens", "EarlyPerUO"); if (!NT_SUCCESS(Status)) { RxDereferenceNetFcb(Fcb); return Status; } }
if (BooleanFlagOn(Context->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE) && !BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, ~SYNCHRONIZE)) { UNIMPLEMENTED; }
_SEH2_TRY { /* Find a SRV_OPEN that suits the opening */ Status = RxCollapseOrCreateSrvOpen(Context); if (Status == STATUS_SUCCESS) { PFOBX Fobx; PSRV_OPEN SrvOpen;
SrvOpen = (PSRV_OPEN)Context->pRelevantSrvOpen; Fobx = (PFOBX)Context->pFobx; /* There are already opens, check for conflict */ if (Fcb->OpenCount != 0) { if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, &Fcb->ShareAccess, FALSE, "second check per useropens", "2ndAccPerUO"))) { ++SrvOpen->UncleanFobxCount; RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
_SEH2_LEAVE; } } else { if (NetRoot->Type != NET_ROOT_PIPE) { RxSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, &Fcb->ShareAccess, "initial shareaccess setup", "InitShrAcc"); } }
RxSetupNetFileObject(Context);
/* No conflict? Set up SA */ if (Fcb->OpenCount != 0 && NetRoot->Type != NET_ROOT_PIPE) { RxUpdateShareAccess(FileObject, &Fcb->ShareAccess, "update share access", "UpdShrAcc"); }
++Fcb->UncleanCount; if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { ++Fcb->UncachedUncleanCount; }
if (SrvOpen->UncleanFobxCount == 0 && Fcb->UncleanCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE)) { RxChangeBufferingState(SrvOpen, NULL, FALSE); }
/* No pending close, we're active */ ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
++Fcb->OpenCount; ++SrvOpen->UncleanFobxCount; ++SrvOpen->OpenCount; SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING)) { SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING); SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING);
ClearFlag(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED); ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE); }
/* Now, update SA for the SRV_OPEN */ RxUpdateShareAccessPerSrvOpens(SrvOpen);
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE)) { SetFlag(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE); }
/* Update the FOBX info */ if (Fobx != NULL) { if (Context->Create.pNetRoot->Type == NET_ROOT_PIPE) { SetFlag(FileObject->Flags, FO_NAMED_PIPE); }
if (Context->Create.pNetRoot->Type == NET_ROOT_PRINT || Context->Create.pNetRoot->Type == NET_ROOT_PIPE) { Fobx->PipeHandleInformation = &Fobx->Specific.NamedPipe.PipeHandleInformation;
Fobx->Specific.NamedPipe.CollectDataTime.QuadPart = 0; Fobx->Specific.NamedPipe.CollectDataSize = Context->Create.pNetRoot->NamedPipeParameters.DataCollectionSize;
Fobx->Specific.NamedPipe.PipeHandleInformation.TypeOfPipe = Context->Create.PipeType; Fobx->Specific.NamedPipe.PipeHandleInformation.ReadMode = Context->Create.PipeReadMode; Fobx->Specific.NamedPipe.PipeHandleInformation.CompletionMode = Context->Create.PipeCompletionMode;
InitializeListHead(&Fobx->Specific.NamedPipe.ReadSerializationQueue); InitializeListHead(&Fobx->Specific.NamedPipe.WriteSerializationQueue); } }
Status = STATUS_SUCCESS; } } _SEH2_FINALLY { if (Fcb->OpenCount == 0) { if (Context->Create.FcbAcquired) { Context->Create.FcbAcquired = (RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE) == 0); if (!Context->Create.FcbAcquired) { RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0); } } } else { RxDereferenceNetFcb(Fcb); } } _SEH2_END;
return Status;}
/* * @implemented */NTSTATUSRxCreateTreeConnect( IN PRX_CONTEXT RxContext){ NTSTATUS Status; PV_NET_ROOT VNetRoot; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; NET_ROOT_TYPE NetRootType; UNICODE_STRING CanonicalName, RemainingName;
PAGED_CODE();
Stack = RxContext->CurrentIrpSp; FileObject = Stack->FileObject;
RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0); /* As long as we don't know connection type, mark it wild */ NetRootType = NET_ROOT_WILD; /* Get the type by parsing the name */ Status = RxFirstCanonicalize(RxContext, &FileObject->FileName, &CanonicalName, &NetRootType); if (!NT_SUCCESS(Status)) { return Status; }
RxContext->Create.ThisIsATreeConnectOpen = TRUE; RxContext->Create.TreeConnectOpenDeferred = FALSE; RtlInitEmptyUnicodeString(&RxContext->Create.TransportName, NULL, 0); RtlInitEmptyUnicodeString(&RxContext->Create.UserName, NULL, 0); RtlInitEmptyUnicodeString(&RxContext->Create.Password, NULL, 0); RtlInitEmptyUnicodeString(&RxContext->Create.UserDomainName, NULL, 0);
/* We don't handle EA - they come from DFS, don't care */ if (Stack->Parameters.Create.EaLength > 0) { UNIMPLEMENTED; }
/* Mount if required */ Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName); if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT) { RxScavengeVNetRoots(RxContext->RxDeviceObject); Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName); }
if (!NT_SUCCESS(Status)) { return Status; }
/* Validate the rest of the name with mini-rdr */ if (RemainingName.Length > 0) { MINIRDR_CALL(Status, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch, MRxIsValidDirectory, (RxContext, &RemainingName)); }
if (!NT_SUCCESS(Status)) { return Status; }
VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot; RxReferenceVNetRoot(VNetRoot); if (InterlockedCompareExchange(&VNetRoot->AdditionalReferenceForDeleteFsctlTaken, 1, 0) != 0) { RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld); }
FileObject->FsContext = &RxDeviceFCB; FileObject->FsContext2 = VNetRoot;
VNetRoot->ConstructionStatus = STATUS_SUCCESS; ++VNetRoot->NumberOfOpens;
/* Create is over - clear context */ RxContext->Create.pSrvCall = NULL; RxContext->Create.pNetRoot = NULL; RxContext->Create.pVNetRoot = NULL;
return Status;}
VOIDNTAPIRxDebugControlCommand( _In_ PSTR ControlString){ UNIMPLEMENTED;}
NTSTATUSNTAPIRxDriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ NTSTATUS Status; USHORT i, State = 0;
DPRINT("RxDriverEntry(%p, %p)\n", DriverObject, RegistryPath);
_SEH2_TRY { RxCheckFcbStructuresForAlignment();
RtlZeroMemory(&RxData, sizeof(RxData)); RxData.NodeTypeCode = RDBSS_NTC_DATA_HEADER; RxData.NodeByteSize = sizeof(RxData); RxData.DriverObject = DriverObject;
RtlZeroMemory(&RxDeviceFCB, sizeof(RxDeviceFCB)); RxDeviceFCB.spacer.NodeTypeCode = RDBSS_NTC_DEVICE_FCB; RxDeviceFCB.spacer.NodeByteSize = sizeof(RxDeviceFCB);
KeInitializeSpinLock(&RxStrucSupSpinLock); RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
RxInitializeDebugSupport();
RxFileSystemDeviceObject = (PRDBSS_DEVICE_OBJECT)&RxSpaceForTheWrappersDeviceObject; RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject, sizeof(RxSpaceForTheWrappersDeviceObject));
RxInitializeLog(); State = 2;
RxGetRegistryParameters(RegistryPath); RxReadRegistryParameters();
Status = RxInitializeRegistrationStructures(); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } State = 1;
RxInitializeDispatcher();
ExInitializeNPagedLookasideList(&RxContextLookasideList, RxAllocatePoolWithTag, RxFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
InitializeListHead(&RxIrpsList); KeInitializeSpinLock(&RxIrpsListSpinLock);
InitializeListHead(&RxActiveContexts); InitializeListHead(&RxSrvCalldownList);
ExInitializeFastMutex(&RxContextPerFileSerializationMutex); ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex); KeInitializeMutex(&RxScavengerMutex, 1); KeInitializeMutex(&RxSerializationMutex, 1);
for (i = 0; i < RxMaximumWorkQueue; ++i) { RxFileSystemDeviceObject->PostedRequestCount[i] = 0; RxFileSystemDeviceObject->OverflowQueueCount[i] = 0; InitializeListHead(&RxFileSystemDeviceObject->OverflowQueue[i]); }
KeInitializeSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock);
RxInitializeDispatchVectors(DriverObject);
ExInitializeResourceLite(&RxData.Resource); RxData.OurProcess = IoGetCurrentProcess();
RxInitializeRxTimer(); } _SEH2_FINALLY { if (!NT_SUCCESS(Status)) { RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BC4, Status); RxInitUnwind(DriverObject, State); } } _SEH2_END;
/* There are still bits to init - be consider it's fine for now */#if 0 UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;#else return STATUS_SUCCESS;#endif}
#if DBG/* * @implemented */VOIDRxDumpCurrentAccess( _In_ PSZ where1, _In_ PSZ where2, _In_ PSZ wherelogtag, _In_ PSHARE_ACCESS ShareAccess){ PAGED_CODE();}
/* * @implemented */VOIDRxDumpWantedAccess( _In_ PSZ where1, _In_ PSZ where2, _In_ PSZ wherelogtag, _In_ ACCESS_MASK DesiredAccess, _In_ ULONG DesiredShareAccess){ PAGED_CODE();}#endif
/* * @implemented */BOOLEANNTAPIRxFastIoCheckIfPossible( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, BOOLEAN CheckForReadOperation, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){ PFCB Fcb; PSRV_OPEN SrvOpen; LARGE_INTEGER LargeLength;
PAGED_CODE();
/* Get the FCB to validate it */ Fcb = FileObject->FsContext; if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) { DPRINT1("Not a file, FastIO not possible!\n"); return FALSE; }
if (FileObject->DeletePending) { DPRINT1("File delete pending\n"); return FALSE; }
/* If there's a pending write operation, deny fast operation */ if (Fcb->NonPaged->OutstandingAsyncWrites != 0) { DPRINT1("Write operations to be completed\n"); return FALSE; }
/* Deny read on orphaned node */ SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen; if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED)) { DPRINT1("SRV_OPEN orphaned\n"); return FALSE; }
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED)) { DPRINT1("FCB orphaned\n"); return FALSE; }
/* If there's a buffering state change pending, deny fast operation (it might change * cache status) */ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) { DPRINT1("Buffering change pending\n"); return FALSE; }
/* File got renamed/deleted, deny operation */ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) || BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED)) { DPRINT1("File renamed/deleted\n"); return FALSE; }
/* Process pending change buffering state operations */ FsRtlEnterFileSystem(); RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen); FsRtlExitFileSystem();
LargeLength.QuadPart = Length;
/* If operation to come is a read operation */ if (CheckForReadOperation) { /* Check that read cache is enabled */ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED)) { DPRINT1("Read caching disabled\n"); return FALSE; }
/* Check whether there's a lock conflict */ if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock, FileOffset, &LargeLength, LockKey, FileObject, PsGetCurrentProcess())) { DPRINT1("FsRtlFastCheckLockForRead failed\n"); return FALSE; }
return TRUE; }
/* Check that write cache is enabled */ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED)) { DPRINT1("Write caching disabled\n"); return FALSE; }
/* Check whether there's a lock conflict */ if (!FsRtlFastCheckLockForWrite(&Fcb->Specific.Fcb.FileLock, FileOffset, &LargeLength, LockKey, FileObject, PsGetCurrentProcess())) { DPRINT1("FsRtlFastCheckLockForWrite failed\n"); return FALSE; }
return TRUE;}
BOOLEANNTAPIRxFastIoDeviceControl( PFILE_OBJECT FileObject, BOOLEAN Wait, PVOID InputBuffer OPTIONAL, ULONG InputBufferLength, PVOID OutputBuffer OPTIONAL, ULONG OutputBufferLength, ULONG IoControlCode, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){ /* Only supported IOCTL */ if (IoControlCode == IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER) { UNIMPLEMENTED; return FALSE; } else { return FALSE; }}
/* * @implemented */BOOLEANNTAPIRxFastIoRead( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){ BOOLEAN Ret; RX_TOPLEVELIRP_CONTEXT TopLevelContext;
PAGED_CODE();
DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext, FileObject->FsContext2); DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
/* Prepare a TLI context */ ASSERT(RxIsThisTheTopLevelIrp(NULL)); RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP, (PRDBSS_DEVICE_OBJECT)DeviceObject);
Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject, &TopLevelContext); if (Ret) { DPRINT("Read OK\n"); } else { DPRINT1("Read failed!\n"); }
return Ret;}
/* * @implemented */BOOLEANNTAPIRxFastIoWrite( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){ PFOBX Fobx; BOOLEAN Ret; RX_TOPLEVELIRP_CONTEXT TopLevelContext;
PAGED_CODE();
Fobx = (PFOBX)FileObject->FsContext2; if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_BAD_HANDLE)) { return FALSE; }
DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject, FileObject->FsContext, FileObject->FsContext2); DPRINT("Writing %ld at %I64x\n", Length, FileOffset->QuadPart);
/* Prepare a TLI context */ ASSERT(RxIsThisTheTopLevelIrp(NULL)); RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP, (PRDBSS_DEVICE_OBJECT)DeviceObject);
Ret = FsRtlCopyWrite2(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject, &TopLevelContext); if (Ret) { DPRINT("Write OK\n"); } else { DPRINT1("Write failed!\n"); }
return Ret;}
NTSTATUSRxFindOrCreateFcb( PRX_CONTEXT RxContext, PUNICODE_STRING NetRootName){ PFCB Fcb; ULONG Version; NTSTATUS Status; PNET_ROOT NetRoot; PV_NET_ROOT VNetRoot; BOOLEAN TableAcquired, AcquiredExclusive;
PAGED_CODE();
NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot; VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot; ASSERT(NetRoot == VNetRoot->NetRoot);
Status = STATUS_SUCCESS; AcquiredExclusive = FALSE;
RxAcquireFcbTableLockShared(&NetRoot->FcbTable, TRUE); TableAcquired = TRUE; Version = NetRoot->FcbTable.Version;
/* Look for a cached FCB */ Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName); if (Fcb == NULL) { DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName); } else { DPRINT("FCB found for %wZ\n", &Fcb->FcbTableEntry.Path); /* If FCB was to be orphaned, consider it as not suitable */ if (Fcb->fShouldBeOrphaned) { RxDereferenceNetFcb(Fcb); RxReleaseFcbTableLock(&NetRoot->FcbTable);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE); TableAcquired = TRUE; AcquiredExclusive = TRUE;
Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName); if (Fcb != NULL && Fcb->fShouldBeOrphaned) { RxOrphanThisFcb(Fcb); RxDereferenceNetFcb(Fcb); Fcb = NULL; } } }
/* If FCB was not found or is not covering full path, prepare for more work */ if (Fcb == NULL || Fcb->FcbTableEntry.Path.Length != NetRootName->Length) { if (Fcb != NULL) { DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb->FcbTableEntry.Path, NetRootName); }
if (!AcquiredExclusive) { RxReleaseFcbTableLock(&NetRoot->FcbTable); RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE); TableAcquired = TRUE; }
/* If FCB table was updated in between, re-attempt a lookup */ if (NetRoot->FcbTable.Version != Version) { Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName); if (Fcb != NULL && Fcb->FcbTableEntry.Path.Length != NetRootName->Length) { Fcb = NULL; } } }
/* Allocate the FCB */ _SEH2_TRY { if (Fcb == NULL) { Fcb = RxCreateNetFcb(RxContext, VNetRoot, NetRootName); if (Fcb == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { Status = RxAcquireExclusiveFcb(RxContext, Fcb); RxContext->Create.FcbAcquired = NT_SUCCESS(Status); } } } _SEH2_FINALLY { if (_SEH2_AbnormalTermination()) { RxReleaseFcbTableLock(&NetRoot->FcbTable); TableAcquired = FALSE;
if (Fcb != NULL) { RxTransitionNetFcb(Fcb, Condition_Bad);
ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE); if (RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE) != 0) { ExReleaseResourceLite(Fcb->Header.Resource); } } } } _SEH2_END;
if (TableAcquired) { RxReleaseFcbTableLock(&NetRoot->FcbTable); }
if (!NT_SUCCESS(Status)) { return Status; }
RxContext->pFcb = RX_GET_MRX_FCB(Fcb); DPRINT("FCB %p is in condition %lx\n", Fcb, Fcb->Condition);
if (!RxContext->Create.FcbAcquired) { RxWaitForStableNetFcb(Fcb, RxContext); Status = RxAcquireExclusiveFcb(RxContext, Fcb); RxContext->Create.FcbAcquired = NT_SUCCESS(Status); }
return Status;}
NTSTATUSRxFirstCanonicalize( PRX_CONTEXT RxContext, PUNICODE_STRING FileName, PUNICODE_STRING CanonicalName, PNET_ROOT_TYPE NetRootType){ NTSTATUS Status; NET_ROOT_TYPE Type; BOOLEAN UncName, PrependString, IsSpecial; USHORT CanonicalLength; UNICODE_STRING SessionIdString; WCHAR SessionIdBuffer[16];
PAGED_CODE();
Type = NET_ROOT_WILD; PrependString = FALSE; IsSpecial = FALSE; UncName = FALSE; Status = STATUS_SUCCESS;
/* Name has to contain at least \\ */ if (FileName->Length < 2 * sizeof(WCHAR)) { return STATUS_OBJECT_NAME_INVALID; }
/* First easy check, is that a path with a name? */ CanonicalLength = FileName->Length; if (FileName->Length > 5 * sizeof(WCHAR)) { if (FileName->Buffer[0] == '\\' && FileName->Buffer[1] == ';') { if (FileName->Buffer[3] == ':') { Type = NET_ROOT_DISK; } else { Type = NET_ROOT_PRINT; } } }
/* Nope, attempt deeper parsing */ if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR && FileName->Buffer[1] != ';') { ULONG SessionId; PWSTR FirstSlash, EndOfString;
SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME); UncName = TRUE;
/* The lack of drive letter will be replaced by session ID */ SessionId = RxGetSessionId(RxContext->CurrentIrpSp); RtlInitEmptyUnicodeString(&SessionIdString, SessionIdBuffer, sizeof(SessionIdBuffer)); RtlIntegerToUnicodeString(SessionId, 10, &SessionIdString);
EndOfString = Add2Ptr(FileName->Buffer, FileName->Length); for (FirstSlash = &FileName->Buffer[1]; FirstSlash != EndOfString; ++FirstSlash) { if (*FirstSlash == OBJ_NAME_PATH_SEPARATOR) { break; } }
if (EndOfString - FirstSlash <= 1) { Status = STATUS_OBJECT_NAME_INVALID; } else { UNIMPLEMENTED; DPRINT1("WARNING: Assuming not special + disk!\n"); Type = NET_ROOT_DISK; Status = STATUS_SUCCESS; //Status = STATUS_NOT_IMPLEMENTED; /* Should be check against IPC, mailslot, and so on */ } }
/* Update net root type with our deduced one */ *NetRootType = Type; DPRINT("Returning type: %x\n", Type);
if (!NT_SUCCESS(Status)) { return Status; }
/* Do we have to prepend session ID? */ if (UncName) { if (!IsSpecial) { PrependString = TRUE; CanonicalLength += SessionIdString.Length + 3 * sizeof(WCHAR); } }
/* If not UNC path, we should preprend stuff */ if (!PrependString && !IsSpecial && FileName->Buffer[0] != '\\') { return STATUS_OBJECT_PATH_INVALID; }
/* Allocate the buffer */ Status = RxAllocateCanonicalNameBuffer(RxContext, CanonicalName, CanonicalLength); if (!NT_SUCCESS(Status)) { return Status; }
/* We don't support that case, we always return disk */ if (IsSpecial) { ASSERT(CanonicalName->Length == CanonicalLength); UNIMPLEMENTED; Status = STATUS_NOT_IMPLEMENTED; } else { /* If we have to prepend, go ahead */ if (PrependString) { CanonicalName->Buffer[0] = '\\'; CanonicalName->Buffer[1] = ';'; CanonicalName->Buffer[2] = ':'; CanonicalName->Length = 3 * sizeof(WCHAR); RtlAppendUnicodeStringToString(CanonicalName, &SessionIdString); RtlAppendUnicodeStringToString(CanonicalName, FileName);
DPRINT1("CanonicalName: %wZ\n", CanonicalName); } /* Otherwise, that's a simple copy */ else { RtlCopyUnicodeString(CanonicalName, FileName); } }
return Status;}
/* * @implemented */VOIDRxFreeCanonicalNameBuffer( PRX_CONTEXT Context){ /* These two buffers are always the same */ ASSERT(Context->Create.CanonicalNameBuffer == Context->AlsoCanonicalNameBuffer);
if (Context->Create.CanonicalNameBuffer != NULL) { RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG); Context->Create.CanonicalNameBuffer = NULL; Context->AlsoCanonicalNameBuffer = NULL; }
ASSERT(Context->AlsoCanonicalNameBuffer == NULL);}
NTSTATUSRxFsdCommonDispatch( PRX_FSD_DISPATCH_VECTOR DispatchVector, UCHAR MajorFunction, PIO_STACK_LOCATION Stack, PFILE_OBJECT FileObject, PIRP Irp, PRDBSS_DEVICE_OBJECT RxDeviceObject){ KIRQL OldIrql; NTSTATUS Status; PRX_CONTEXT Context; UCHAR MinorFunction; PFILE_OBJECT StackFileObject; PRX_FSD_DISPATCH DispatchFunc; RX_TOPLEVELIRP_CONTEXT TopLevelContext; BOOLEAN TopLevel, Closing, PassToDriver, SetCancelRoutine, PostRequest, CanWait;
Status = STATUS_SUCCESS;
DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector, MajorFunction, Stack, FileObject, Irp, RxDeviceObject);
FsRtlEnterFileSystem();
TopLevel = RxTryToBecomeTheTopLevelIrp(&TopLevelContext, Irp, RxDeviceObject, FALSE);
_SEH2_TRY { CanWait = TRUE; Closing = FALSE; PostRequest = FALSE; SetCancelRoutine = TRUE; MinorFunction = Stack->MinorFunction; /* Can we wait? */ switch (MajorFunction) { case IRP_MJ_FILE_SYSTEM_CONTROL: if (FileObject != NULL) { CanWait = IoIsOperationSynchronous(Irp); } else { CanWait = TRUE; } break;
case IRP_MJ_READ: case IRP_MJ_WRITE: case IRP_MJ_QUERY_INFORMATION: case IRP_MJ_SET_INFORMATION: case IRP_MJ_QUERY_EA: case IRP_MJ_SET_EA: case IRP_MJ_FLUSH_BUFFERS: case IRP_MJ_QUERY_VOLUME_INFORMATION: case IRP_MJ_SET_VOLUME_INFORMATION: case IRP_MJ_DIRECTORY_CONTROL: case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_LOCK_CONTROL: case IRP_MJ_QUERY_SECURITY: case IRP_MJ_SET_SECURITY: CanWait = IoIsOperationSynchronous(Irp); break;
case IRP_MJ_CLOSE: case IRP_MJ_CLEANUP: Closing = TRUE; SetCancelRoutine = FALSE; break;
default: break; }
KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); /* Should we stop it right now, or mini-rdr deserves to know? */ PassToDriver = TRUE; if (RxGetRdbssState(RxDeviceObject) != RDBSS_STARTABLE) { if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && !Closing) { PassToDriver = FALSE; Status = STATUS_REDIRECTOR_NOT_STARTED; DPRINT1("Not started!\n"); } } else { if (DispatchVector != RxDeviceFCBVector && (FileObject->FileName.Length != 0 || FileObject->RelatedFileObject != NULL)) { PassToDriver = FALSE; Status = STATUS_REDIRECTOR_NOT_STARTED; DPRINT1("Not started!\n"); } } KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
StackFileObject = Stack->FileObject; /* Make sure we don't deal with orphaned stuff */ if (StackFileObject != NULL && StackFileObject->FsContext != NULL) { if (StackFileObject->FsContext2 != UIntToPtr(DFS_OPEN_CONTEXT) && StackFileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) && StackFileObject->FsContext != &RxDeviceFCB) { PFCB Fcb; PFOBX Fobx;
Fcb = StackFileObject->FsContext; Fobx = StackFileObject->FsContext2;
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED) || ((Fobx != NULL) && BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))) { if (Closing) { PassToDriver = TRUE; } else { PassToDriver = FALSE; Status = STATUS_UNEXPECTED_NETWORK_ERROR; DPRINT1("Operation on orphaned FCB: %p\n", Fcb); } } } }
/* Did we receive a close request whereas we're stopping? */ if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && Closing) { PFCB Fcb;
Fcb = StackFileObject->FsContext;
DPRINT1("Close received after stop\n"); DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n", Irp, Stack->MajorFunction, Stack->MinorFunction, StackFileObject, Fcb);
if (Fcb != NULL && Fcb != &RxDeviceFCB && NodeTypeIsFcb(Fcb)) { DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n", Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path); } }
/* Should we stop the whole thing now? */ if (!PassToDriver) { if (MajorFunction != IRP_MJ_DIRECTORY_CONTROL || MinorFunction != IRP_MN_REMOVE_DEVICE) { IoMarkIrpPending(Irp); Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); Status = STATUS_PENDING; } else { Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); }
_SEH2_LEAVE; }
/* No? Allocate a context to deal with the mini-rdr */ Context = RxCreateRxContext(Irp, RxDeviceObject, (CanWait ? RX_CONTEXT_FLAG_WAIT : 0)); if (Context == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; RxCompleteRequest_Real(RxNull, Irp, STATUS_INSUFFICIENT_RESOURCES); _SEH2_LEAVE; }
/* Set cancel routine if required */ if (SetCancelRoutine) { IoAcquireCancelSpinLock(&OldIrql); IoSetCancelRoutine(Irp, RxCancelRoutine); } else { IoAcquireCancelSpinLock(&OldIrql); IoSetCancelRoutine(Irp, NULL); } IoReleaseCancelSpinLock(OldIrql);
ASSERT(MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; /* Get the dispatch routine */ DispatchFunc = DispatchVector[MajorFunction].CommonRoutine;
if (MajorFunction == IRP_MJ_READ || MajorFunction == IRP_MJ_WRITE) { /* Handle the complete MDL case */ if (BooleanFlagOn(MinorFunction, IRP_MN_COMPLETE)) { DispatchFunc = RxCompleteMdl; } else { /* Do we have to post request? */ if (BooleanFlagOn(MinorFunction, IRP_MN_DPC)) { PostRequest = TRUE; } else { /* Our read function needs stack, make sure we won't overflow, * otherwise, post the request */ if (MajorFunction == IRP_MJ_READ) { if (IoGetRemainingStackSize() < 0xE00) { Context->PendingReturned = TRUE; Status = RxPostStackOverflowRead(Context); if (Status != STATUS_PENDING) { Context->PendingReturned = FALSE; RxCompleteAsynchronousRequest(Context, Status); }
_SEH2_LEAVE; } } } } }
Context->ResumeRoutine = DispatchFunc; /* There's a dispatch routine? Time to dispatch! */ if (DispatchFunc != NULL) { Context->PendingReturned = TRUE; if (PostRequest) { Status = RxFsdPostRequest(Context); } else { /* Retry as long as we have */ do { Status = DispatchFunc(Context); } while (Status == STATUS_RETRY);
if (Status == STATUS_PENDING) { _SEH2_LEAVE; }
/* Sanity check: did someone mess with our context? */ if (Context->CurrentIrp != Irp || Context->CurrentIrpSp != Stack || Context->MajorFunction != MajorFunction || Stack->MinorFunction != MinorFunction) { DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context); DPRINT1("->CurrentIrp %p %p\n", Context->CurrentIrp, Irp); DPRINT1("->CurrentIrpSp %p %p\n", Context->CurrentIrpSp, Stack); DPRINT1("->MajorFunction %d %d\n", Context->MajorFunction, MajorFunction); DPRINT1("->MinorFunction %d %d\n", Context->MinorFunction, MinorFunction); } Context->PendingReturned = FALSE; Status = RxCompleteAsynchronousRequest(Context, Status); } } else { Status = STATUS_NOT_IMPLEMENTED; } } _SEH2_FINALLY { if (TopLevel) { RxUnwindTopLevelIrp(&TopLevelContext); }
FsRtlExitFileSystem(); } _SEH2_END;
DPRINT("RxFsdDispatch, Status: %lx\n", Status); return Status;}
/* * @implemented */NTSTATUSNTAPIRxFsdDispatch( IN PRDBSS_DEVICE_OBJECT RxDeviceObject, IN PIRP Irp){ PFCB Fcb; PIO_STACK_LOCATION Stack; PRX_FSD_DISPATCH_VECTOR DispatchVector;
PAGED_CODE();
DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject, Irp);
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Dispatch easy case */ if (Stack->MajorFunction == IRP_MJ_SYSTEM_CONTROL) { return RxSystemControl(RxDeviceObject, Irp); }
/* Bail out broken cases */ if (Stack->MajorFunction == IRP_MJ_CREATE_MAILSLOT || Stack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE) { IoMarkIrpPending(Irp); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_PENDING; }
/* Immediately handle create */ if (Stack->MajorFunction == IRP_MJ_CREATE) { return RxFsdCommonDispatch(&RxFsdDispatchVector[0], Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject); }
/* If not a creation, we must have at least a FO with a FCB */ if (Stack->FileObject == NULL || Stack->FileObject->FsContext == NULL) { IoMarkIrpPending(Irp); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_PENDING; }
/* Set the dispatch vector if required */ Fcb = Stack->FileObject->FsContext; if (!NodeTypeIsFcb(Fcb) || Fcb->PrivateDispatchVector == NULL) { DispatchVector = &RxFsdDispatchVector[0]; } else { DispatchVector = Fcb->PrivateDispatchVector; }
/* Device cannot accept such requests */ if (RxDeviceObject == RxFileSystemDeviceObject) { IoMarkIrpPending(Irp); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_PENDING; }
/* Dispatch for real! */ return RxFsdCommonDispatch(DispatchVector, Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);}
/* * @implemented */NTSTATUSRxFsdPostRequest( IN PRX_CONTEXT RxContext){ /* Initialize posting if required */ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED)) { RxPrePostIrp(RxContext, RxContext->CurrentIrp); }
DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n", RxContext->MinorFunction, RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread, RxContext->SerialNumber);
RxAddToWorkque(RxContext, RxContext->CurrentIrp); return STATUS_PENDING;}
/* * @implemented */VOIDNTAPIRxFspDispatch( IN PVOID Context){ KIRQL EntryIrql; WORK_QUEUE_TYPE Queue; PRDBSS_DEVICE_OBJECT VolumeDO; PRX_CONTEXT RxContext, EntryContext;
PAGED_CODE();
RxContext = Context; EntryContext = Context; /* Save IRQL at entry for later checking */ EntryIrql = KeGetCurrentIrql();
/* No FO, deal with device */ if (RxContext->CurrentIrpSp->FileObject != NULL) { VolumeDO = RxFileSystemDeviceObject; } else { VolumeDO = NULL; }
/* Which queue to used for delayed? */ if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE)) { Queue = DelayedWorkQueue; } else { ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE)); Queue = CriticalWorkQueue; }
do { PIRP Irp; NTSTATUS Status; BOOLEAN RecursiveCall; RX_TOPLEVELIRP_CONTEXT TopLevelContext;
ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION); ASSERT(!RxContext->PostRequest);
RxContext->LastExecutionThread = PsGetCurrentThread(); SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext->MinorFunction, RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread, RxContext->SerialNumber);
Irp = RxContext->CurrentIrp;
FsRtlEnterFileSystem();
RecursiveCall = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL); RxTryToBecomeTheTopLevelIrp(&TopLevelContext, (RecursiveCall ? (PIRP)FSRTL_FSP_TOP_LEVEL_IRP : RxContext->CurrentIrp), RxContext->RxDeviceObject, TRUE);
ASSERT(RxContext->ResumeRoutine != NULL);
if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_DPC) && Irp->Tail.Overlay.Thread == NULL) { ASSERT((RxContext->MajorFunction == IRP_MJ_WRITE) || (RxContext->MajorFunction == IRP_MJ_READ)); Irp->Tail.Overlay.Thread = PsGetCurrentThread(); }
/* Call the resume routine */ do { BOOLEAN NoComplete;
NoComplete = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
Status = RxContext->ResumeRoutine(RxContext); if (!NoComplete && Status != STATUS_PENDING) { if (Status != STATUS_RETRY) { Status = RxCompleteRequest(RxContext, Status); } } } while (Status == STATUS_RETRY);
RxUnwindTopLevelIrp(&TopLevelContext); FsRtlExitFileSystem();
if (VolumeDO != NULL) { RxContext = RxRemoveOverflowEntry(VolumeDO, Queue); } else { RxContext = NULL; } } while (RxContext != NULL);
/* Did we mess with IRQL? */ if (KeGetCurrentIrql() >= APC_LEVEL) { DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext, EntryIrql); }}
/* * @implemented */ULONGRxGetNetworkProviderPriority( PUNICODE_STRING DeviceName){ PAGED_CODE(); return 1;}
/* * @implemented */VOIDNTAPIRxGetRegistryParameters( IN PUNICODE_STRING RegistryPath){ USHORT i; NTSTATUS Status; UCHAR Buffer[0x400]; HANDLE DriverHandle, KeyHandle; UNICODE_STRING KeyName, OutString; OBJECT_ATTRIBUTES ObjectAttributes;
PAGED_CODE();
InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&DriverHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return; }
RtlInitUnicodeString(&KeyName, L"Parameters"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DriverHandle, FALSE); Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes); if (NT_SUCCESS(Status)) { /* The only parameter we deal with is InitialDebugString */ RxGetStringRegistryParameter(KeyHandle, L"InitialDebugString", &OutString, Buffer, sizeof(Buffer), 0); if (OutString.Length != 0 && OutString.Length < 0x140) { PWSTR Read; PSTR Write;
Read = OutString.Buffer; Write = (PSTR)OutString.Buffer; for (i = 0; i < OutString.Length; ++i) { *Read = *Write; ++Write; *Write = ANSI_NULL; ++Read; }
/* Which is a string we'll just write out */ DPRINT("InitialDebugString read from registry: '%s'\n", OutString.Buffer); RxDebugControlCommand((PSTR)OutString.Buffer); }
ZwClose(KeyHandle); }
ZwClose(DriverHandle);}
/* * @implemented */ULONGRxGetSessionId( IN PIO_STACK_LOCATION IrpSp){ ULONG SessionId; PACCESS_TOKEN Token; PIO_SECURITY_CONTEXT SecurityContext;
PAGED_CODE();
/* If that's not a prefix claim, not an open request, session id will be 0 */ if (IrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL || IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_REDIR_QUERY_PATH) { if (IrpSp->MajorFunction != IRP_MJ_CREATE || IrpSp->Parameters.Create.SecurityContext == NULL) { return 0; }
SecurityContext = IrpSp->Parameters.Create.SecurityContext; } else { SecurityContext = ((PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->SecurityContext; }
/* Query the session id */ Token = SeQuerySubjectContextToken(&SecurityContext->AccessState->SubjectSecurityContext); SeQuerySessionIdToken(Token, &SessionId);
return SessionId;}
/* * @implemented */NTSTATUSNTAPIRxGetStringRegistryParameter( IN HANDLE KeyHandle, IN PCWSTR KeyName, OUT PUNICODE_STRING OutString, IN PUCHAR Buffer, IN ULONG BufferLength, IN BOOLEAN LogFailure){ NTSTATUS Status; ULONG ResultLength; UNICODE_STRING KeyString;
PAGED_CODE();
RtlInitUnicodeString(&KeyString, KeyName); Status = ZwQueryValueKey(KeyHandle, &KeyString, KeyValuePartialInformation, Buffer, BufferLength, &ResultLength); OutString->Length = 0; OutString->Buffer = 0; if (!NT_SUCCESS(Status)) { if (LogFailure) { RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BD3, Status); }
return Status; }
OutString->Buffer = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data); OutString->Length = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength - sizeof(UNICODE_NULL); OutString->MaximumLength = OutString->Length;
return STATUS_SUCCESS;}
/* * @implemented */PRDBSS_DEVICE_OBJECTRxGetTopDeviceObjectIfRdbssIrp( VOID){ PIRP TopLevelIrp; PRDBSS_DEVICE_OBJECT TopDevice = NULL;
TopLevelIrp = IoGetTopLevelIrp(); if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)) { TopDevice = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->RxDeviceObject; }
return TopDevice;}
/* * @implemented */PIRPRxGetTopIrpIfRdbssIrp( VOID){ PIRP Irp = NULL; PRX_TOPLEVELIRP_CONTEXT TopLevel;
TopLevel = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp(); if (RxIsThisAnRdbssTopLevelContext(TopLevel)) { Irp = TopLevel->Irp; }
return Irp;}
/* * @implemented */LUIDRxGetUid( IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext){ LUID Luid; PACCESS_TOKEN Token;
PAGED_CODE();
Token = SeQuerySubjectContextToken(SubjectSecurityContext); SeQueryAuthenticationIdToken(Token, &Luid);
return Luid;}
VOIDNTAPIRxIndicateChangeOfBufferingStateForSrvOpen( PMRX_SRV_CALL SrvCall, PMRX_SRV_OPEN SrvOpen, PVOID SrvOpenKey, PVOID Context){ UNIMPLEMENTED;}
/* * @implemented */VOIDNTAPIRxInitializeDispatchVectors( PDRIVER_OBJECT DriverObject){ USHORT i;
PAGED_CODE();
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i) { DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch; }
RxDeviceFCB.PrivateDispatchVector = RxDeviceFCBVector; ASSERT(RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL); ASSERT(RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
DriverObject->FastIoDispatch = &RxFastIoDispatch; RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(RxFastIoDispatch); RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible; RxFastIoDispatch.FastIoRead = RxFastIoRead; RxFastIoDispatch.FastIoWrite = RxFastIoWrite; RxFastIoDispatch.FastIoQueryBasicInfo = NULL; RxFastIoDispatch.FastIoQueryStandardInfo = NULL; RxFastIoDispatch.FastIoLock = NULL; RxFastIoDispatch.FastIoUnlockSingle = NULL; RxFastIoDispatch.FastIoUnlockAll = NULL; RxFastIoDispatch.FastIoUnlockAllByKey = NULL; RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl; RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection; RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection; RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush; RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
RxInitializeTopLevelIrpPackage();
RxData.CacheManagerCallbacks.AcquireForLazyWrite = RxAcquireFcbForLazyWrite; RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = RxReleaseFcbFromLazyWrite; RxData.CacheManagerCallbacks.AcquireForReadAhead = RxAcquireFcbForReadAhead; RxData.CacheManagerCallbacks.ReleaseFromReadAhead = RxReleaseFcbFromReadAhead;
RxData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = RxNoOpAcquire; RxData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = RxNoOpRelease; RxData.CacheManagerNoOpCallbacks.AcquireForReadAhead = RxNoOpAcquire; RxData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = RxNoOpRelease;}
NTSTATUSNTAPIRxInitializeLog( VOID){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */VOIDRxInitializeMinirdrDispatchTable( IN PDRIVER_OBJECT DriverObject){ PAGED_CODE();}
/* * @implemented */NTSTATUSNTAPIRxInitializeRegistrationStructures( VOID){ PAGED_CODE();
ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex); RxData.NumberOfMinirdrsRegistered = 0; RxData.NumberOfMinirdrsStarted = 0; InitializeListHead(&RxData.RegisteredMiniRdrs);
return STATUS_SUCCESS;}
/* * @implemented */VOIDNTAPIRxInitializeTopLevelIrpPackage( VOID){ KeInitializeSpinLock(&TopLevelIrpSpinLock); InitializeListHead(&TopLevelIrpAllocatedContextsList);}
VOIDNTAPIRxInitUnwind( PDRIVER_OBJECT DriverObject, USHORT State){ UNIMPLEMENTED;}
/* * @implemented */BOOLEANRxIsMemberOfTopLevelIrpAllocatedContextsList( PRX_TOPLEVELIRP_CONTEXT TopLevelContext){ KIRQL OldIrql; PLIST_ENTRY NextEntry; BOOLEAN Found = FALSE; PRX_TOPLEVELIRP_CONTEXT ListContext;
/* Browse all the allocated TLC to find ours */ KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql); for (NextEntry = TopLevelIrpAllocatedContextsList.Flink; NextEntry != &TopLevelIrpAllocatedContextsList; NextEntry = NextEntry->Flink) { ListContext = CONTAINING_RECORD(NextEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry); ASSERT(ListContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE); ASSERT(BooleanFlagOn(ListContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
/* Found! */ if (ListContext == TopLevelContext) { Found = TRUE; break; } } KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
return Found;}
/* * @implemented */BOOLEANRxIsOkToPurgeFcb( PFCB Fcb){ PLIST_ENTRY Entry;
/* No associated SRV_OPEN, it's OK to purge */ if (IsListEmpty(&Fcb->SrvOpenList)) { return TRUE; }
/* Only allow to purge if all the associated SRV_OPEN * - have no outstanding opens ongoing * - have only read attribute set */ for (Entry = Fcb->SrvOpenList.Flink; Entry != &Fcb->SrvOpenList; Entry = Entry->Flink) { PSRV_OPEN SrvOpen;
SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
/* Failing previous needs, don't allow purge */ if (SrvOpen->UncleanFobxCount != 0 || (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES) { return FALSE; } }
/* All correct, allow purge */ return TRUE;}
/* * @implemented */BOOLEANRxIsThisAnRdbssTopLevelContext( PRX_TOPLEVELIRP_CONTEXT TopLevelContext){ ULONG_PTR StackTop, StackBottom;
/* Bail out for flags */ if ((ULONG_PTR)TopLevelContext <= FSRTL_FAST_IO_TOP_LEVEL_IRP) { return FALSE; }
/* Is our provided TLC allocated on stack? */ IoGetStackLimits(&StackTop, &StackBottom); if ((ULONG_PTR)TopLevelContext <= StackBottom - sizeof(RX_TOPLEVELIRP_CONTEXT) && (ULONG_PTR)TopLevelContext >= StackTop) { /* Yes, so check whether it's really a TLC by checking alignement & signature */ if (!BooleanFlagOn((ULONG_PTR)TopLevelContext, 0x3) && TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE) { return TRUE; }
return FALSE; }
/* No, use the helper function */ return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext);}
/* * @implemented */BOOLEANRxIsThisTheTopLevelIrp( IN PIRP Irp){ PIRP TopLevelIrp;
/* When we put oursleves as top level, we set TLC as 'IRP', so look for it */ TopLevelIrp = IoGetTopLevelIrp(); if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)) { TopLevelIrp = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->Irp; }
return (TopLevelIrp == Irp);}
NTSTATUSNTAPIRxLockOperationCompletion( IN PVOID Context, IN PIRP Irp){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */VOIDNTAPIRxLogEventDirect( IN PRDBSS_DEVICE_OBJECT DeviceObject, IN PUNICODE_STRING OriginatorId, IN ULONG EventId, IN NTSTATUS Status, IN ULONG Line){ PUNICODE_STRING Originator = OriginatorId; LARGE_INTEGER LargeLine;
/* Set optional parameters */ LargeLine.QuadPart = Line; if (OriginatorId == NULL || OriginatorId->Length == 0) { Originator = (PUNICODE_STRING)&unknownId; }
/* And log */ RxLogEventWithAnnotation(DeviceObject, EventId, Status, &LargeLine, sizeof(LargeLine), Originator, 1);}
VOIDNTAPIRxLogEventWithAnnotation( IN PRDBSS_DEVICE_OBJECT DeviceObject, IN ULONG EventId, IN NTSTATUS Status, IN PVOID DataBuffer, IN USHORT DataBufferLength, IN PUNICODE_STRING Annotation, IN ULONG AnnotationCount){ UNIMPLEMENTED;}
NTSTATUSNTAPIRxLowIoCompletion( PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxLowIoIoCtlShellCompletion( PRX_CONTEXT RxContext){ PIRP Irp; NTSTATUS Status;
PAGED_CODE();
DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext);
Irp = RxContext->CurrentIrp; Status = RxContext->IoStatusBlock.Status;
/* Set information and status */ if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) { Irp->IoStatus.Information = RxContext->IoStatusBlock.Information; }
Irp->IoStatus.Status = Status;
return Status;}
NTSTATUSRxLowIoLockControlShell( IN PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSNTAPIRxLowIoNotifyChangeDirectoryCompletion( PRX_CONTEXT RxContext){ PAGED_CODE();
DPRINT("Completing NCD with: %lx, %lx\n", RxContext->IoStatusBlock.Status, RxContext->IoStatusBlock.Information);
/* Just copy back the IO_STATUS to the IRP */ RxSetIoStatusStatus(RxContext, RxContext->IoStatusBlock.Status); RxSetIoStatusInfo(RxContext, RxContext->IoStatusBlock.Information);
return RxContext->IoStatusBlock.Status;}
/* * @implemented */NTSTATUSRxLowIoReadShell( PRX_CONTEXT RxContext){ PFCB Fcb; NTSTATUS Status;
PAGED_CODE();
DPRINT("RxLowIoReadShell(%p)\n", RxContext);
Fcb = (PFCB)RxContext->pFcb; if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED)) { return STATUS_MORE_PROCESSING_REQUIRED; }
/* Always update stats for disks */ if (Fcb->CachedNetRootType == NET_ROOT_DISK) { ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkReadBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount); }
/* And forward the read to the mini-rdr */ Status = RxLowIoSubmit(RxContext, RxLowIoReadShellCompletion); DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext, Status);
return Status;}
NTSTATUSNTAPIRxLowIoReadShellCompletion( PRX_CONTEXT RxContext){ PIRP Irp; PFCB Fcb; NTSTATUS Status; BOOLEAN PagingIo, IsPipe; PIO_STACK_LOCATION Stack; PLOWIO_CONTEXT LowIoContext;
PAGED_CODE();
DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext);
Status = RxContext->IoStatusBlock.Status; DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
Irp = RxContext->CurrentIrp; PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
/* Set IRP information from the RX_CONTEXT status block */ Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
/* Fixup status for paging file if nothing was read */ if (PagingIo) { if (NT_SUCCESS(Status) && RxContext->IoStatusBlock.Information == 0) { Status = STATUS_END_OF_FILE; } }
LowIoContext = &RxContext->LowIoContext; ASSERT(RxLowIoIsBufferLocked(LowIoContext));
/* Check broken cases that should never happen */ Fcb = (PFCB)RxContext->pFcb; if (Status == STATUS_FILE_LOCK_CONFLICT) { if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED)) { ASSERT(FALSE); return STATUS_RETRY; } } else if (Status == STATUS_SUCCESS) { if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL)) { if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED) || BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED)) { ASSERT(FALSE); } }
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED)) { ASSERT(FALSE); } }
/* Readahead should go through Cc and not finish here */ ASSERT(!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD));
/* If it's sync, RxCommonRead will finish the work - nothing to do here */ if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL)) { return Status; }
Stack = RxContext->CurrentIrpSp; IsPipe = BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION); /* Release lock if required */ if (PagingIo) { RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId); } else { /* Set FastIo if read was a success */ if (NT_SUCCESS(Status) && !IsPipe) { SetFlag(Stack->FileObject->Flags, FO_FILE_FAST_IO_READ); }
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) { RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.ReadSerializationQueue); } else { RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId); } }
if (IsPipe) { UNIMPLEMENTED; }
/* Final sanity checks */ ASSERT(Status != STATUS_RETRY); ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length); ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
return Status;}
/* * @implemented */NTSTATUSRxLowIoWriteShell( IN PRX_CONTEXT RxContext){ PFCB Fcb; NTSTATUS Status;
PAGED_CODE();
DPRINT("RxLowIoWriteShell(%p)\n", RxContext);
Fcb = (PFCB)RxContext->pFcb;
ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) && !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
/* Always update stats for disks */ if (Fcb->CachedNetRootType == NET_ROOT_DISK) { ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkWriteBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount); }
/* And forward the write to the mini-rdr */ Status = RxLowIoSubmit(RxContext, RxLowIoWriteShellCompletion); DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext, Status);
return Status;}
NTSTATUSNTAPIRxLowIoWriteShellCompletion( PRX_CONTEXT RxContext){ PIRP Irp; PFCB Fcb; NTSTATUS Status; BOOLEAN PagingIo; PLOWIO_CONTEXT LowIoContext;
PAGED_CODE();
DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext);
Status = RxContext->IoStatusBlock.Status; DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
Irp = RxContext->CurrentIrp;
/* Set IRP information from the RX_CONTEXT status block */ Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
LowIoContext = &RxContext->LowIoContext; ASSERT(RxLowIoIsBufferLocked(LowIoContext));
/* Perform a few sanity checks */ Fcb = (PFCB)RxContext->pFcb; if (Status == STATUS_SUCCESS) { if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED)) { ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) && !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED)); }
ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED)); }
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); if (Status != STATUS_SUCCESS && PagingIo) { DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb, Fcb->NetRoot, Status); }
/* In case of async call, perform last bits not done in RxCommonWrite */ if (!BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL)) { PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack;
/* We only succeed if we wrote what was asked for */ if (NT_SUCCESS(Status) && !BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION)) { ASSERT(Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount); }
/* If write succeed, ,also update FILE_OBJECT flags */ Stack = RxContext->CurrentIrpSp; FileObject = Stack->FileObject; if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); }
if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE)) { SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); }
/* If VDL was extended, fix attributes */ if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL)) { LONGLONG LastOffset, FileSize;
LastOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset + Irp->IoStatus.Information; RxGetFileSizeWithLock(Fcb, &FileSize);
if (FileSize < LastOffset) { LastOffset = FileSize; }
Fcb->Header.ValidDataLength.QuadPart = LastOffset; }
/* One less outstanding write */ if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) { PNON_PAGED_FCB NonPagedFcb;
NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb; if (NonPagedFcb != NULL) { if (ExInterlockedAddUlong(&NonPagedFcb->OutstandingAsyncWrites, -1, &RxStrucSupSpinLock) == 1) { KeSetEvent(NonPagedFcb->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE); } } }
/* Release paging resource if acquired */ if (RxContext->FcbPagingIoResourceAcquired) { RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId); }
/* Resume blocked operations for pipes */ if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) { RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.WriteSerializationQueue); } else { /* And release FCB only for files */ if (RxContext->FcbResourceAcquired) { RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId); } }
/* Final sanity checks */ ASSERT(Status != STATUS_RETRY); ASSERT((Status != STATUS_SUCCESS) || (Irp->IoStatus.Information <= Stack->Parameters.Write.Length)); ASSERT(RxContext->MajorFunction == IRP_MJ_WRITE);
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION)) { UNIMPLEMENTED; } }
return Status;}
/* * @implemented */NTSTATUSRxNotifyChangeDirectory( PRX_CONTEXT RxContext){ PIRP Irp; NTSTATUS Status; PIO_STACK_LOCATION Stack;
PAGED_CODE();
/* The IRP can abviously wait */ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
/* Initialize its lowio */ RxInitializeLowIoContext(&RxContext->LowIoContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY);
_SEH2_TRY { /* Lock user buffer */ Stack = RxContext->CurrentIrpSp; RxLockUserBuffer(RxContext, IoWriteAccess, Stack->Parameters.NotifyDirectory.Length);
/* Copy parameters from IO_STACK */ RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.WatchTree = BooleanFlagOn(Stack->Flags, SL_WATCH_TREE); RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.CompletionFilter = Stack->Parameters.NotifyDirectory.CompletionFilter; RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.NotificationBufferLength = Stack->Parameters.NotifyDirectory.Length;
/* If we have an associated MDL */ Irp = RxContext->CurrentIrp; if (Irp->MdlAddress != NULL) { /* Then, call mini-rdr */ RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer != NULL) { Status = RxLowIoSubmit(RxContext, RxLowIoNotifyChangeDirectoryCompletion); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } else { Status = STATUS_INVALID_PARAMETER; } } _SEH2_FINALLY { /* All correct */ } _SEH2_END;
return Status;}
/* * @implemented */VOIDNTAPIRxpCancelRoutine( PVOID Context){ PRX_CONTEXT RxContext;
PAGED_CODE();
RxContext = Context;
/* First, notify mini-rdr about cancellation */ if (RxContext->MRxCancelRoutine != NULL) { RxContext->MRxCancelRoutine(RxContext); } /* If we didn't find in overflow queue, try in blocking operations */ else if (!RxCancelOperationInOverflowQueue(RxContext)) { RxCancelBlockingOperation(RxContext); }
/* And delete the context */ RxDereferenceAndDeleteRxContext_Real(RxContext);}
NTSTATUSRxPostStackOverflowRead ( IN PRX_CONTEXT RxContext){ PAGED_CODE();
UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */VOIDRxpPrepareCreateContextForReuse( PRX_CONTEXT RxContext){ /* Reuse can only happen for open operations (STATUS_RETRY) */ ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
/* Release the FCB if it was acquired */ if (RxContext->Create.FcbAcquired) { RxReleaseFcb(RxContext, RxContext->pFcb); RxContext->Create.FcbAcquired = FALSE; }
/* Free the canonical name */ RxFreeCanonicalNameBuffer(RxContext);
/* If we have a VNetRoot associated */ if (RxContext->Create.pVNetRoot != NULL || RxContext->Create.NetNamePrefixEntry != NULL) { /* Remove our link and thus, dereference the VNetRoot */ RxpAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE, TRUE); if (RxContext->Create.pVNetRoot != NULL) { RxDereferenceVNetRoot(RxContext->Create.pVNetRoot, TRUE); RxContext->Create.pVNetRoot = NULL; } RxpReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable, TRUE); }
DPRINT("RxContext: %p prepared for reuse\n", RxContext);}
/* * @implemented */NTSTATUSRxpQueryInfoMiniRdr( PRX_CONTEXT RxContext, FILE_INFORMATION_CLASS FileInfoClass, PVOID Buffer){ PFCB Fcb; NTSTATUS Status;
Fcb = (PFCB)RxContext->pFcb;
/* Set the RX_CONTEXT */ RxContext->Info.FileInformationClass = FileInfoClass; RxContext->Info.Buffer = Buffer;
/* Pass down */ MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryFileInfo, (RxContext));
return Status;}
/* * @implemented */NTSTATUSRxPrefixClaim( IN PRX_CONTEXT RxContext){ PIRP Irp; NTSTATUS Status; NET_ROOT_TYPE NetRootType; UNICODE_STRING CanonicalName, FileName, NetRootName;
PAGED_CODE();
Irp = RxContext->CurrentIrp;
/* This has to come from MUP */ if (Irp->RequestorMode == UserMode) { return STATUS_INVALID_DEVICE_REQUEST; }
if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) { PQUERY_PATH_REQUEST QueryRequest;
/* Get parameters */ QueryRequest = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
/* Don't overflow allocation */ if (QueryRequest->PathNameLength >= MAXUSHORT - 1) { return STATUS_INVALID_DEVICE_REQUEST; }
/* Forcefully rewrite IRP MJ */ RxContext->MajorFunction = IRP_MJ_CREATE;
/* Fake canon name */ RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG); if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Leave; }
/* Copy the prefix to look for */ RtlCopyMemory(RxContext->PrefixClaim.SuppliedPathName.Buffer, &QueryRequest->FilePathName[0], QueryRequest->PathNameLength); RxContext->PrefixClaim.SuppliedPathName.Length = QueryRequest->PathNameLength; RxContext->PrefixClaim.SuppliedPathName.MaximumLength = QueryRequest->PathNameLength;
/* Zero the create parameters */ RtlZeroMemory(&RxContext->Create, FIELD_OFFSET(RX_CONTEXT, AlsoCanonicalNameBuffer) - FIELD_OFFSET(RX_CONTEXT, Create.NtCreateParameters)); RxContext->Create.ThisIsATreeConnectOpen = TRUE; RxContext->Create.NtCreateParameters.SecurityContext = QueryRequest->SecurityContext; } else { /* If not devcontrol, it comes from open, name was already copied */ ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE); ASSERT(RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL); }
/* Canonilize name */ NetRootType = NET_ROOT_WILD; RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0); FileName.Length = RxContext->PrefixClaim.SuppliedPathName.Length; FileName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength; FileName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer; NetRootName.Length = RxContext->PrefixClaim.SuppliedPathName.Length; NetRootName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength; NetRootName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer; Status = RxFirstCanonicalize(RxContext, &FileName, &CanonicalName, &NetRootType); /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */ if (NT_SUCCESS(Status)) { Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &NetRootName); } if (Status == STATUS_PENDING) { return Status; } /* Reply to MUP */ if (NT_SUCCESS(Status)) { PQUERY_PATH_RESPONSE QueryResponse;
/* We accept the length that was canon (minus netroot) */ QueryResponse = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer; QueryResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - NetRootName.Length; }
Leave: /* If we reach that point with MJ, reset everything and make IRP being a device control */ if (RxContext->MajorFunction == IRP_MJ_CREATE) { if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL) { RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG); }
RxpPrepareCreateContextForReuse(RxContext);
RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL; }
return Status;}
/* * @implemented */NTSTATUSNTAPIRxPrepareToReparseSymbolicLink( PRX_CONTEXT RxContext, BOOLEAN SymbolicLinkEmbeddedInOldPath, PUNICODE_STRING NewPath, BOOLEAN NewPathIsAbsolute, PBOOLEAN ReparseRequired){ PWSTR NewBuffer; USHORT NewLength; PFILE_OBJECT FileObject;
/* Assume no reparse is required first */ *ReparseRequired = FALSE;
/* Only supported for IRP_MJ_CREATE */ if (RxContext->MajorFunction != IRP_MJ_CREATE) { return STATUS_INVALID_PARAMETER; }
/* If symbolic link is not embedded, and DELETE is specified, fail */ if (!SymbolicLinkEmbeddedInOldPath) { /* Excepted if DELETE is the only flag specified, then, open has to succeed * See: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/rxprocs/nf-rxprocs-rxpreparetoreparsesymboliclink (remarks) */ if (BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, DELETE) && BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, ~DELETE)) { return STATUS_ACCESS_DENIED; } }
/* At that point, assume reparse will be required */ *ReparseRequired = TRUE;
/* If new path isn't absolute, it's up to us to make it absolute */ if (!NewPathIsAbsolute) { /* The prefix will be \Device\Mup */ NewLength = NewPath->Length + (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL)); NewBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, NewLength, RX_MISC_POOLTAG); if (NewBuffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* Copy data for the new path */ RtlMoveMemory(NewBuffer, L"\\Device\\Mup", (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL))); RtlMoveMemory(Add2Ptr(NewBuffer, (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL))), NewPath->Buffer, NewPath->Length); } /* Otherwise, use caller path as it */ else { NewLength = NewPath->Length; NewBuffer = NewPath->Buffer; }
/* Get the FILE_OBJECT we'll modify */ FileObject = RxContext->CurrentIrpSp->FileObject;
/* Free old path first */ ExFreePoolWithTag(FileObject->FileName.Buffer, 0); /* And setup new one */ FileObject->FileName.Length = NewLength; FileObject->FileName.MaximumLength = NewLength; FileObject->FileName.Buffer = NewBuffer;
/* And set reparse flag */ SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE);
/* Done! */ return STATUS_SUCCESS;}
/* * @implemented */VOIDRxPrePostIrp( IN PVOID Context, IN PIRP Irp){ LOCK_OPERATION Lock; PIO_STACK_LOCATION Stack; PRX_CONTEXT RxContext = Context;
/* NULL IRP is no option */ if (Irp == NULL) { return; }
/* Check whether preparation was really needed */ if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED)) { return; } /* Mark the context as prepared */ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
/* Just lock the user buffer, with the correct length, depending on the MJ */ Lock = IoReadAccess; Stack = RxContext->CurrentIrpSp; if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE) { if (!BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL)) { if (RxContext->MajorFunction == IRP_MJ_READ) { Lock = IoWriteAccess; } RxLockUserBuffer(RxContext, Lock, Stack->Parameters.Read.Length); } } else { if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) || RxContext->MajorFunction == IRP_MJ_QUERY_EA) { Lock = IoWriteAccess; RxLockUserBuffer(RxContext, Lock, Stack->Parameters.QueryDirectory.Length); } else if (RxContext->MajorFunction == IRP_MJ_SET_EA) { RxLockUserBuffer(RxContext, Lock, Stack->Parameters.SetEa.Length); } }
/* As it will be posted (async), mark the IRP pending */ IoMarkIrpPending(Irp);}
/* * @implemented */NTSTATUSRxpSetInfoMiniRdr( PRX_CONTEXT RxContext, FILE_INFORMATION_CLASS Class){ PFCB Fcb; NTSTATUS Status;
/* Initialize parameters in RX_CONTEXT */ RxContext->Info.FileInformationClass = Class; RxContext->Info.Buffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer; RxContext->Info.Length = RxContext->CurrentIrpSp->Parameters.SetFile.Length;
/* And call mini-rdr */ Fcb = (PFCB)RxContext->pFcb; MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
return Status;}
VOIDNTAPIRxpUnregisterMinirdr( IN PRDBSS_DEVICE_OBJECT RxDeviceObject){ UNIMPLEMENTED;}
/* * @implemented */VOIDRxPurgeNetFcb( PFCB Fcb, PRX_CONTEXT LocalContext){ NTSTATUS Status;
PAGED_CODE();
/* First, flush */ MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
/* And force close */ RxReleaseFcb(NULL, Fcb); MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE); Status = RxAcquireExclusiveFcb(NULL, Fcb); ASSERT(Status == STATUS_SUCCESS);}
NTSTATUSRxQueryAlternateNameInfo( PRX_CONTEXT RxContext, PFILE_NAME_INFORMATION AltNameInfo){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSRxQueryBasicInfo( PRX_CONTEXT RxContext, PFILE_BASIC_INFORMATION BasicInfo){ PAGED_CODE();
DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext, BasicInfo);
/* Simply zero and forward to mini-rdr */ RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION)); return RxpQueryInfoMiniRdr(RxContext, FileBasicInformation, BasicInfo);}
NTSTATUSRxQueryCompressedInfo( PRX_CONTEXT RxContext, PFILE_COMPRESSION_INFORMATION CompressionInfo){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSRxQueryDirectory( PRX_CONTEXT RxContext){ PIRP Irp; PFCB Fcb; PFOBX Fobx; UCHAR Flags; NTSTATUS Status; BOOLEAN LockNotGranted; ULONG Length, FileIndex; PUNICODE_STRING FileName; PIO_STACK_LOCATION Stack; FILE_INFORMATION_CLASS FileInfoClass;
PAGED_CODE();
DPRINT("RxQueryDirectory(%p)\n", RxContext);
/* Get parameters */ Stack = RxContext->CurrentIrpSp; Length = Stack->Parameters.QueryDirectory.Length; FileName = Stack->Parameters.QueryDirectory.FileName; FileInfoClass = Stack->Parameters.QueryDirectory.FileInformationClass; DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n", FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), Length, FileName, FileInfoClass);
Irp = RxContext->CurrentIrp; Flags = Stack->Flags; FileIndex = Stack->Parameters.QueryDirectory.FileIndex; DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex, Irp->UserBuffer, Flags);
if (FileName != NULL) { DPRINT("FileName: %wZ\n", FileName); }
/* No FOBX: not a standard file/directory */ Fobx = (PFOBX)RxContext->pFobx; if (Fobx == NULL) { return STATUS_OBJECT_NAME_INVALID; }
/* We can only deal with a disk */ Fcb = (PFCB)RxContext->pFcb; if (Fcb->pNetRoot->Type != NET_ROOT_DISK) { DPRINT1("Not a disk! %x\n", Fcb->pNetRoot->Type); return STATUS_INVALID_DEVICE_REQUEST; }
/* Setup RX_CONTEXT related fields */ RxContext->QueryDirectory.FileIndex = FileIndex; RxContext->QueryDirectory.RestartScan = BooleanFlagOn(Flags, SL_RESTART_SCAN); RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn(Flags, SL_RETURN_SINGLE_ENTRY); RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn(Flags, SL_INDEX_SPECIFIED); RxContext->QueryDirectory.InitialQuery = (Fobx->UnicodeQueryTemplate.Buffer == NULL) && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
/* We don't support (yet?) a specific index being set */ if (RxContext->QueryDirectory.IndexSpecified) { return STATUS_NOT_IMPLEMENTED; }
/* Try to lock FCB */ LockNotGranted = TRUE; if (RxContext->QueryDirectory.InitialQuery) { Status = RxAcquireExclusiveFcb(RxContext, Fcb); if (Status != STATUS_LOCK_NOT_GRANTED) { if (!NT_SUCCESS(Status)) { return Status; }
if (Fobx->UnicodeQueryTemplate.Buffer != NULL) { RxContext->QueryDirectory.InitialQuery = FALSE; RxConvertToSharedFcb(RxContext, Fcb); }
LockNotGranted = FALSE; } } else { Status = RxAcquireExclusiveFcb(RxContext, Fcb); if (Status != STATUS_LOCK_NOT_GRANTED) { if (!NT_SUCCESS(Status)) { return Status; }
LockNotGranted = FALSE; } }
/* If it failed, post request */ if (LockNotGranted) { return RxFsdPostRequest(RxContext); }
/* This cannot be done on a orphaned directory */ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED)) { RxReleaseFcb(RxContext, Fcb); return STATUS_FILE_CLOSED; }
_SEH2_TRY { /* Set index */ if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan) { RxContext->QueryDirectory.FileIndex = 0; }
/* Assume success */ Status = STATUS_SUCCESS; /* If initial query, prepare FOBX */ if (RxContext->QueryDirectory.InitialQuery) { /* We cannot have a template already! */ ASSERT(!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE));
/* If we have a file name and a correct one, duplicate it in the FOBX */ if (FileName != NULL && FileName->Length != 0 && FileName->Buffer != NULL && (FileName->Length != sizeof(WCHAR) || FileName->Buffer[0] != '*') && (FileName->Length != 12 * sizeof(WCHAR) || RtlCompareMemory(FileName->Buffer, Rx8QMdot3QM, 12 * sizeof(WCHAR)) != 12 * sizeof(WCHAR))) { Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG); if (Fobx->UnicodeQueryTemplate.Buffer != NULL) { /* UNICODE_STRING; length has to be even */ if ((FileName->Length & 1) != 0) { Status = STATUS_INVALID_PARAMETER; RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG); } else { Fobx->UnicodeQueryTemplate.Length = FileName->Length; Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length; RtlMoveMemory(Fobx->UnicodeQueryTemplate.Buffer, FileName->Buffer, FileName->Length);
SetFlag(Fobx->Flags, FOBX_FLAG_FREE_UNICODE); } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } /* No name specified, or a match all wildcard? Match everything */ else { Fobx->ContainsWildCards = TRUE;
Fobx->UnicodeQueryTemplate.Buffer = &RxStarForTemplate; Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR); Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
SetFlag(Fobx->Flags, FOBX_FLAG_MATCH_ALL); }
/* No need for exclusive any longer */ if (NT_SUCCESS(Status)) { RxConvertToSharedFcb(RxContext, Fcb); } }
/* Lock user buffer and forward to mini-rdr */ if (NT_SUCCESS(Status)) { RxLockUserBuffer(RxContext, IoModifyAccess, Length); RxContext->Info.FileInformationClass = FileInfoClass; RxContext->Info.Buffer = RxNewMapUserBuffer(RxContext); RxContext->Info.Length = Length;
if (RxContext->Info.Buffer != NULL) { MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryDirectory, (RxContext)); }
/* Post if mini-rdr asks to */ if (RxContext->PostRequest) { RxFsdPostRequest(RxContext); } else { Irp->IoStatus.Information = Length - RxContext->Info.LengthRemaining; } } } _SEH2_FINALLY { RxReleaseFcb(RxContext, Fcb); } _SEH2_END;
return Status;}
NTSTATUSRxQueryEaInfo( PRX_CONTEXT RxContext, PFILE_EA_INFORMATION EaInfo){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSRxQueryInternalInfo( PRX_CONTEXT RxContext, PFILE_INTERNAL_INFORMATION InternalInfo){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSRxQueryNameInfo( PRX_CONTEXT RxContext, PFILE_NAME_INFORMATION NameInfo){ PFCB Fcb; PFOBX Fobx; PAGED_CODE();
DPRINT("RxQueryNameInfo(%p, %p)\n", RxContext, NameInfo);
/* Check we can at least copy name size */ if (RxContext->Info.LengthRemaining < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName)) { DPRINT1("Buffer too small: %d\n", RxContext->Info.LengthRemaining); RxContext->Info.Length = 0; return STATUS_BUFFER_OVERFLOW; }
RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
Fcb = (PFCB)RxContext->pFcb; Fobx = (PFOBX)RxContext->pFobx; /* Get the UNC name */ RxConjureOriginalName(Fcb, Fobx, &NameInfo->FileNameLength, &NameInfo->FileName[0], &RxContext->Info.Length, VNetRoot_As_UNC_Name);
/* If RxConjureOriginalName returned a negative len (-1) then output buffer * was too small, return the appropriate length & status. */ if (RxContext->Info.LengthRemaining < 0) { DPRINT1("Buffer too small!\n"); RxContext->Info.Length = 0; return STATUS_BUFFER_OVERFLOW; }
#if 1 // CORE-13938, rfb: please note I replaced 0 with 1 here if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY && RxContext->Info.LengthRemaining >= sizeof(WCHAR)) { NameInfo->FileName[NameInfo->FileNameLength / sizeof(WCHAR)] = L'\\'; NameInfo->FileNameLength += sizeof(WCHAR); RxContext->Info.LengthRemaining -= sizeof(WCHAR); }#endif
/* All correct */ return STATUS_SUCCESS;}
NTSTATUSRxQueryPipeInfo( PRX_CONTEXT RxContext, PFILE_PIPE_INFORMATION PipeInfo){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSRxQueryPositionInfo( PRX_CONTEXT RxContext, PFILE_POSITION_INFORMATION PositionInfo){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSRxQueryStandardInfo( PRX_CONTEXT RxContext, PFILE_STANDARD_INFORMATION StandardInfo){ PFCB Fcb; PFOBX Fobx; NTSTATUS Status;
PAGED_CODE();
DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext, StandardInfo);
/* Zero output buffer */ RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
Fcb = (PFCB)RxContext->pFcb; Fobx = (PFOBX)RxContext->pFobx; /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */ if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) || BooleanFlagOn(Fobx->pSrvOpen->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT)) { return RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo); }
/* Otherwise, fill what we can already */ Status = STATUS_SUCCESS; StandardInfo->NumberOfLinks = Fcb->NumberOfLinks; StandardInfo->DeletePending = BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE); StandardInfo->Directory = (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY); if (StandardInfo->NumberOfLinks == 0) { StandardInfo->NumberOfLinks = 1; }
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE) { StandardInfo->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart; RxGetFileSizeWithLock(Fcb, &StandardInfo->EndOfFile.QuadPart); }
/* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */ if (RxForceQFIPassThrough || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILESIZECACHEING_ENABLED)) { Status = RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo); } else { RxContext->IoStatusBlock.Information -= sizeof(FILE_STANDARD_INFORMATION); }
return Status;}
/* * @implemented */VOIDNTAPIRxReadRegistryParameters( VOID){ NTSTATUS Status; HANDLE KeyHandle; ULONG ResultLength; UCHAR Buffer[0x40]; UNICODE_STRING KeyName, ParamName; OBJECT_ATTRIBUTES ObjectAttributes; PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
PAGED_CODE();
RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return; }
PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer; RtlInitUnicodeString(&ParamName, L"DisableByteRangeLockingOnReadOnlyFiles"); Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength); if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD) { DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0); }
RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity"); Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength); if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD) { ULONG Granularity = *(PULONG)PartialInfo->Data;
if (Granularity > 16) { Granularity = 16; }
ReadAheadGranularity = Granularity << PAGE_SHIFT; }
RtlInitUnicodeString(&ParamName, L"DisableFlushOnCleanup"); Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength); if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD) { DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0); }
ZwClose(KeyHandle);}
/* * @implemented */NTSTATUSNTAPIRxRegisterMinirdr( OUT PRDBSS_DEVICE_OBJECT *DeviceObject, IN OUT PDRIVER_OBJECT DriverObject, IN PMINIRDR_DISPATCH MrdrDispatch, IN ULONG Controls, IN PUNICODE_STRING DeviceName, IN ULONG DeviceExtensionSize, IN DEVICE_TYPE DeviceType, IN ULONG DeviceCharacteristics){ NTSTATUS Status; PRDBSS_DEVICE_OBJECT RDBSSDevice;
PAGED_CODE();
if (!DeviceObject) { return STATUS_INVALID_PARAMETER; }
/* Create device object with provided parameters */ Status = IoCreateDevice(DriverObject, DeviceExtensionSize + sizeof(RDBSS_DEVICE_OBJECT), DeviceName, DeviceType, DeviceCharacteristics, FALSE, (PDEVICE_OBJECT *)&RDBSSDevice); if (!NT_SUCCESS(Status)) { return Status; }
if (!RxData.DriverObject) { return STATUS_UNSUCCESSFUL; }
/* Initialize our DO extension */ RDBSSDevice->RDBSSDeviceObject = NULL; ++RxFileSystemDeviceObject->ReferenceCount; *DeviceObject = RDBSSDevice; RDBSSDevice->RdbssExports = &RxExports; RDBSSDevice->Dispatch = MrdrDispatch; RDBSSDevice->RegistrationControls = Controls; RDBSSDevice->DeviceName = *DeviceName; RDBSSDevice->RegisterUncProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS); RDBSSDevice->RegisterMailSlotProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS); InitializeListHead(&RDBSSDevice->OverflowQueue[0]); InitializeListHead(&RDBSSDevice->OverflowQueue[1]); InitializeListHead(&RDBSSDevice->OverflowQueue[2]); KeInitializeSpinLock(&RDBSSDevice->OverflowQueueSpinLock); RDBSSDevice->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName, RDBSSDevice->NetworkProviderPriority);
ExAcquireFastMutex(&RxData.MinirdrRegistrationMutex); InsertTailList(&RxData.RegisteredMiniRdrs, &RDBSSDevice->MiniRdrListLinks); ExReleaseFastMutex(&RxData.MinirdrRegistrationMutex);
/* Unless mini-rdr explicitly asked not to, initialize dispatch table */ if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH)) { RxInitializeMinirdrDispatchTable(DriverObject); }
/* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */ if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER)) { LARGE_INTEGER ScavengerTimeLimit;
RDBSSDevice->pRxNetNameTable = &RDBSSDevice->RxNetNameTableInDeviceObject; RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE); RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE; ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL; RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject; RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit); }
RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
return STATUS_SUCCESS;}
/* * @implemented */VOIDRxRemoveFromTopLevelIrpAllocatedContextsList( PRX_TOPLEVELIRP_CONTEXT TopLevelContext){ KIRQL OldIrql;
/* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */ ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE); ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql); RemoveEntryList(&TopLevelContext->ListEntry); KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);}
/* * @implemented */PRX_CONTEXTRxRemoveOverflowEntry( PRDBSS_DEVICE_OBJECT DeviceObject, WORK_QUEUE_TYPE Queue){ KIRQL OldIrql; PRX_CONTEXT Context;
KeAcquireSpinLock(&DeviceObject->OverflowQueueSpinLock, &OldIrql); if (DeviceObject->OverflowQueueCount[Queue] <= 0) { /* No entries left, nothing to return */ InterlockedDecrement(&DeviceObject->PostedRequestCount[Queue]); Context = NULL; } else { PLIST_ENTRY Entry;
/* Decrement count */ --DeviceObject->OverflowQueueCount[Queue];
/* Return head */ Entry = RemoveHeadList(&DeviceObject->OverflowQueue[Queue]); Context = CONTAINING_RECORD(Entry, RX_CONTEXT, OverflowListEntry); ClearFlag(Context->Flags, (RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE)); Context->OverflowListEntry.Flink = NULL; } KeReleaseSpinLock(&DeviceObject->OverflowQueueSpinLock, OldIrql);
return Context;}
#if DBG/* * @implemented */VOIDRxRemoveShareAccess( _Inout_ PFILE_OBJECT FileObject, _Inout_ PSHARE_ACCESS ShareAccess, _In_ PSZ where, _In_ PSZ wherelogtag){ PAGED_CODE();
RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess); IoRemoveShareAccess(FileObject, ShareAccess); RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);}#endif
/* * @implemented */VOIDRxRemoveShareAccessPerSrvOpens( IN OUT PSRV_OPEN SrvOpen){ ACCESS_MASK DesiredAccess; BOOLEAN ReadAccess; BOOLEAN WriteAccess; BOOLEAN DeleteAccess;
PAGED_CODE();
/* Get access that were granted to SRV_OPEN */ DesiredAccess = SrvOpen->DesiredAccess; ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0; WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0; DeleteAccess = (DesiredAccess & DELETE) != 0;
/* If any, drop them */ if ((ReadAccess) || (WriteAccess) || (DeleteAccess)) { BOOLEAN SharedRead; BOOLEAN SharedWrite; BOOLEAN SharedDelete; ULONG DesiredShareAccess; PSHARE_ACCESS ShareAccess;
ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens; DesiredShareAccess = SrvOpen->ShareAccess;
ShareAccess->Readers -= ReadAccess; ShareAccess->Writers -= WriteAccess; ShareAccess->Deleters -= DeleteAccess;
ShareAccess->OpenCount--;
SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0; SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0; SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0; ShareAccess->SharedRead -= SharedRead; ShareAccess->SharedWrite -= SharedWrite; ShareAccess->SharedDelete -= SharedDelete; }}
NTSTATUSRxSearchForCollapsibleOpen( PRX_CONTEXT RxContext, ACCESS_MASK DesiredAccess, ULONG ShareAccess){ PFCB Fcb; NTSTATUS Status; PLIST_ENTRY ListEntry; BOOLEAN ShouldTry, Purged, Scavenged;
PAGED_CODE();
DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext, DesiredAccess, ShareAccess);
Fcb = (PFCB)RxContext->pFcb;
/* If we're asked to open for backup, don't allow SRV_OPEN reuse */ if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT)) { ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
RxScavengeRelatedFobxs(Fcb); RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
return STATUS_NOT_FOUND; }
/* If basic open, ask the mini-rdr if we should try to collapse */ if (RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN || RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN_IF) { ShouldTry = TRUE;
if (Fcb->MRxDispatch != NULL) { ASSERT(RxContext->pRelevantSrvOpen == NULL); ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
ShouldTry = NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext)); } } else { ShouldTry = FALSE; }
if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE)) { ShouldTry = FALSE; }
/* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */ if (!ShouldTry) { if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess))) { return STATUS_NOT_FOUND; }
ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
RxScavengeRelatedFobxs(Fcb); RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
return STATUS_NOT_FOUND; }
/* Only collapse for matching NET_ROOT & disks */ if (Fcb->pNetRoot != RxContext->Create.pNetRoot || Fcb->pNetRoot->Type != NET_ROOT_DISK) { return STATUS_NOT_FOUND; }
Purged = FALSE; Scavenged = FALSE; Status = STATUS_NOT_FOUND;TryAgain: /* Browse all our SRV_OPEN to find the matching one */ for (ListEntry = Fcb->SrvOpenList.Flink; ListEntry != &Fcb->SrvOpenList; ListEntry = ListEntry->Flink) { PSRV_OPEN SrvOpen;
SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks); /* Not the same VNET_ROOT, move to the next one */ if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot) { RxContext->Create.TryForScavengingOnSharingViolation = TRUE; continue; }
/* Is there a sharing violation? */ if (SrvOpen->DesiredAccess != DesiredAccess || SrvOpen->ShareAccess != ShareAccess || BooleanFlagOn(SrvOpen->Flags, (SRVOPEN_FLAG_CLOSED | SRVOPEN_FLAG_COLLAPSING_DISABLED | SRVOPEN_FLAG_FILE_DELETED | SRVOPEN_FLAG_FILE_RENAMED))) { if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot) { RxContext->Create.TryForScavengingOnSharingViolation = TRUE; continue; }
/* Check against the SRV_OPEN */ Status = RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess); if (!NT_SUCCESS(Status)) { break; } } else { /* Don't allow collaspse for reparse point opening */ if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions ^ SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT)) { Purged = TRUE; Scavenged = TRUE; Status = STATUS_NOT_FOUND; break; }
/* Not readonly? Or bytereange lock disabled? Try to collapse! */ if (DisableByteRangeLockingOnReadOnlyFiles || !BooleanFlagOn(SrvOpen->pFcb->Attributes, FILE_ATTRIBUTE_READONLY)) { RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL); if (NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext))) { /* Is close delayed - great reuse*/ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED)) { DPRINT("Delayed close successfull, reusing %p\n", SrvOpen); InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles); ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED); }
return STATUS_SUCCESS; }
Status = STATUS_NOT_FOUND; break; } } } /* We browse the whole list and didn't find any matching? NOT_FOUND */ if (ListEntry == &Fcb->SrvOpenList) { Status = STATUS_NOT_FOUND; }
/* Only required access: read attributes? Don't reuse */ if ((DesiredAccess & 0xFFEFFFFF) == FILE_READ_ATTRIBUTES) { return STATUS_NOT_FOUND; }
/* Not found? Scavenge and retry to look for collaspile SRV_OPEN */ if (!Scavenged) { ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED); Scavenged = TRUE; RxScavengeRelatedFobxs(Fcb); goto TryAgain; }
/* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */ if (!Purged && RxIsOkToPurgeFcb(Fcb)) { RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE); Purged = TRUE; goto TryAgain; }
/* If sharing violation, keep track of it */ if (Status == STATUS_SHARING_VIOLATION) { RxContext->Create.TryForScavengingOnSharingViolation = TRUE; }
DPRINT("Status: %x\n", Status); return Status;}
NTSTATUSRxSetAllocationInfo( PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSRxSetBasicInfo( PRX_CONTEXT RxContext){ NTSTATUS Status;
PAGED_CODE();
#define FILE_ATTRIBUTE_VOLUME 0x8#define VALID_FILE_ATTRIBUTES ( \ FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \ FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \ FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \ FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \ FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \ FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)#define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
/* First of all, call the mini-rdr */ Status = RxpSetInfoMiniRdr(RxContext, FileBasicInformation); /* If it succeed, perform last bits */ if (NT_SUCCESS(Status)) { PIRP Irp; PFCB Fcb; PFOBX Fobx; PFILE_OBJECT FileObject; ULONG Attributes, CleanAttr; PFILE_BASIC_INFORMATION BasicInfo;
Fcb = (PFCB)RxContext->pFcb; Fobx = (PFOBX)RxContext->pFobx; Irp = RxContext->CurrentIrp; BasicInfo = Irp->AssociatedIrp.SystemBuffer; FileObject = RxContext->CurrentIrpSp->FileObject;
/* If caller provided flags, handle the change */ Attributes = BasicInfo->FileAttributes; if (Attributes != 0) { /* Clean our flags first, with only stuff we support */ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY) { CleanAttr = (Attributes & VALID_DIR_ATTRIBUTES) | FILE_ATTRIBUTE_DIRECTORY; } else { CleanAttr = Attributes & VALID_FILE_ATTRIBUTES; }
/* Handle the temporary mark (set/unset depending on caller) */ if (BooleanFlagOn(Attributes, FILE_ATTRIBUTE_TEMPORARY)) { SetFlag(Fcb->FcbState, FCB_STATE_TEMPORARY); SetFlag(FileObject->Flags, FO_TEMPORARY_FILE); } else { ClearFlag(Fcb->FcbState, FCB_STATE_TEMPORARY); ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE); }
/* And set new attributes */ Fcb->Attributes = CleanAttr; }
/* If caller provided a creation time, set it */ if (BasicInfo->CreationTime.QuadPart != 0LL) { Fcb->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart; SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_CREATION); }
/* If caller provided a last access time, set it */ if (BasicInfo->LastAccessTime.QuadPart != 0LL) { Fcb->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart; SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS); }
/* If caller provided a last write time, set it */ if (BasicInfo->LastWriteTime.QuadPart != 0LL) { Fcb->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart; SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE); }
/* If caller provided a last change time, set it */ if (BasicInfo->ChangeTime.QuadPart != 0LL) { Fcb->LastChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart; SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE); } }
/* Done */ return Status;}
/* * @implemented */NTSTATUSRxSetDispositionInfo( PRX_CONTEXT RxContext){ NTSTATUS Status;
PAGED_CODE();
/* First, make the mini-rdr work! */ Status = RxpSetInfoMiniRdr(RxContext, FileDispositionInformation); /* If it succeed, we'll keep track of the change */ if (NT_SUCCESS(Status)) { PFCB Fcb; PFILE_OBJECT FileObject; PFILE_DISPOSITION_INFORMATION FileDispo;
Fcb = (PFCB)RxContext->pFcb; FileObject = RxContext->CurrentIrpSp->FileObject; FileDispo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer; /* Caller asks for deletion: mark as delete on close */ if (FileDispo->DeleteFile) { SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE); FileObject->DeletePending = TRUE; } /* Otherwise, clear it */ else { ClearFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE); FileObject->DeletePending = FALSE; }
/* Sanitize output */ Status = STATUS_SUCCESS; }
return Status;}
NTSTATUSRxSetEndOfFileInfo( PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSRxSetPipeInfo( PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSRxSetPositionInfo( PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */NTSTATUSRxSetRenameInfo( PRX_CONTEXT RxContext){ ULONG Length; NTSTATUS Status; PFCB RenameFcb, Fcb; PIO_STACK_LOCATION Stack; PFILE_RENAME_INFORMATION RenameInfo, UserInfo;
PAGED_CODE();
DPRINT("RxSetRenameInfo(%p)\n", RxContext);
Stack = RxContext->CurrentIrpSp; DPRINT("FO: %p, Replace: %d\n", Stack->Parameters.SetFile.FileObject, Stack->Parameters.SetFile.ReplaceIfExists);
/* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */ RxContext->Info.ReplaceIfExists = Stack->Parameters.SetFile.ReplaceIfExists; if (Stack->Parameters.SetFile.FileObject == NULL) { return RxpSetInfoMiniRdr(RxContext, Stack->Parameters.SetFile.FileInformationClass); }
Fcb = (PFCB)RxContext->pFcb; RenameFcb = Stack->Parameters.SetFile.FileObject->FsContext; /* First, validate the received file object */ ASSERT(NodeType(RenameFcb) == RDBSS_NTC_OPENTARGETDIR_FCB); if (Fcb->pNetRoot != RenameFcb->pNetRoot) { DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb, Fcb->pNetRoot, Fcb->pNetRoot->pNetRootName, RenameFcb, RenameFcb->pNetRoot, RenameFcb->pNetRoot->pNetRootName); return STATUS_NOT_SAME_DEVICE; }
/* We'll reallocate a safe buffer */ Length = Fcb->pNetRoot->DiskParameters.RenameInfoOverallocationSize + RenameFcb->FcbTableEntry.Path.Length + FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName); RenameInfo = RxAllocatePoolWithTag(PagedPool, Length, '??xR'); if (RenameInfo == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
_SEH2_TRY { /* Copy the data */ UserInfo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer; RenameInfo->ReplaceIfExists = UserInfo->ReplaceIfExists; RenameInfo->RootDirectory = UserInfo->RootDirectory; RenameInfo->FileNameLength = RenameFcb->FcbTableEntry.Path.Length; RtlMoveMemory(&RenameInfo->FileName[0], RenameFcb->FcbTableEntry.Path.Buffer, RenameFcb->FcbTableEntry.Path.Length);
/* Set them in the RX_CONTEXT */ RxContext->Info.FileInformationClass = Stack->Parameters.SetFile.FileInformationClass; RxContext->Info.Buffer = RenameInfo; RxContext->Info.Length = Length;
/* And call the mini-rdr */ MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext)); } _SEH2_FINALLY { /* Free */ RxFreePoolWithTag(RenameInfo, '??xR'); } _SEH2_END;
/* Done! */ return Status;}
#if DBG/* * @implemented */VOIDRxSetShareAccess( _In_ ACCESS_MASK DesiredAccess, _In_ ULONG DesiredShareAccess, _Inout_ PFILE_OBJECT FileObject, _Out_ PSHARE_ACCESS ShareAccess, _In_ PSZ where, _In_ PSZ wherelogtag){ PAGED_CODE();
RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess); IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess); RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);}#endif
NTSTATUSRxSetSimpleInfo( PRX_CONTEXT RxContext){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */VOIDRxSetupNetFileObject( PRX_CONTEXT RxContext){ PFCB Fcb; PFOBX Fobx; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack;
PAGED_CODE();
/* Assert FOBX is FOBX or NULL */ Fobx = (PFOBX)RxContext->pFobx; ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
Fcb = (PFCB)RxContext->pFcb; Stack = RxContext->CurrentIrpSp; FileObject = Stack->FileObject; /* If it's temporary mark FO as such */ if (Fcb != NULL && NodeType(Fcb) != RDBSS_NTC_VCB && BooleanFlagOn(Fcb->FcbState, FCB_STATE_TEMPORARY)) { if (FileObject == NULL) { return; }
FileObject->Flags |= FO_TEMPORARY_FILE; }
/* No FO, nothing to setup */ if (FileObject == NULL) { return; }
/* Assign FCB & CCB (FOBX) to FO */ FileObject->FsContext = Fcb; FileObject->FsContext2 = Fobx; if (Fobx != NULL) { ULONG_PTR StackTop, StackBottom;
/* If FO is allocated on pool, keep track of it */ IoGetStackLimits(&StackTop, &StackBottom); if ((ULONG_PTR)FileObject <= StackBottom || (ULONG_PTR)FileObject >= StackTop) { Fobx->AssociatedFileObject = FileObject; } else { Fobx->AssociatedFileObject = NULL; }
/* Make sure to mark FOBX if it's a DFS open */ if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT)) { SetFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN); } else { ClearFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN); } }
/* Set Cc pointers */ FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
/* Update access state */ if (Stack->Parameters.Create.SecurityContext != NULL) { PACCESS_STATE AccessState;
AccessState = Stack->Parameters.Create.SecurityContext->AccessState; AccessState->PreviouslyGrantedAccess |= AccessState->RemainingDesiredAccess; AccessState->RemainingDesiredAccess = 0; }}
/* * @implemented */NTSTATUSNTAPIRxStartMinirdr( IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp){ NTSTATUS Status; BOOLEAN Wait, AlreadyStarted; PRDBSS_DEVICE_OBJECT DeviceObject;
/* If we've not been post, then, do it */ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)) { SECURITY_SUBJECT_CONTEXT SubjectContext;
SeCaptureSubjectContext(&SubjectContext); RxContext->FsdUid = RxGetUid(&SubjectContext); SeReleaseSubjectContext(&SubjectContext);
*PostToFsp = TRUE; return STATUS_PENDING; }
/* Acquire all the required locks */ Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait)) { *PostToFsp = TRUE; return STATUS_PENDING; }
if (!RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, Wait)) { ExReleaseResourceLite(&RxData.Resource); *PostToFsp = TRUE; return STATUS_PENDING; }
AlreadyStarted = FALSE; DeviceObject = RxContext->RxDeviceObject; _SEH2_TRY { /* MUP handle set, means already registered */ if (DeviceObject->MupHandle != NULL) { AlreadyStarted = TRUE; Status = STATUS_REDIRECTOR_STARTED; _SEH2_LEAVE; }
/* If we're asked to register to MUP, then do it */ Status = STATUS_SUCCESS; if (DeviceObject->RegisterUncProvider) { Status = FsRtlRegisterUncProvider(&DeviceObject->MupHandle, &DeviceObject->DeviceName, DeviceObject->RegisterMailSlotProvider); } if (!NT_SUCCESS(Status)) { DeviceObject->MupHandle = NULL; _SEH2_LEAVE; }
/* Register as file system */ IoRegisterFileSystem(&DeviceObject->DeviceObject); DeviceObject->RegisteredAsFileSystem = TRUE;
/* Inform mini-rdr it has to start */ MINIRDR_CALL(Status, RxContext, DeviceObject->Dispatch, MRxStart, (RxContext, DeviceObject)); if (NT_SUCCESS(Status)) { ++DeviceObject->StartStopContext.Version; RxSetRdbssState(DeviceObject, RDBSS_STARTED); InterlockedExchangeAdd(&RxData.NumberOfMinirdrsStarted, 1);
Status = RxInitializeMRxDispatcher(DeviceObject); } } _SEH2_FINALLY { if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status)) { if (!AlreadyStarted) { RxUnstart(RxContext, DeviceObject); } }
RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable); ExReleaseResourceLite(&RxData.Resource); } _SEH2_END;
return Status;}
NTSTATUSNTAPIRxStopMinirdr( IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSRxSystemControl( IN PRDBSS_DEVICE_OBJECT RxDeviceObject, IN PIRP Irp){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* * @implemented */BOOLEANRxTryToBecomeTheTopLevelIrp( IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext, IN PIRP Irp, IN PRDBSS_DEVICE_OBJECT RxDeviceObject, IN BOOLEAN ForceTopLevel ){ BOOLEAN FromPool = FALSE;
PAGED_CODE();
/* If not top level, and not have to be, quit */ if (IoGetTopLevelIrp() && !ForceTopLevel) { return FALSE; }
/* If not TLC provider, allocate one */ if (TopLevelContext == NULL) { TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG); if (TopLevelContext == NULL) { return FALSE; }
FromPool = TRUE; }
/* Init it */ __RxInitializeTopLevelIrpContext(TopLevelContext, Irp, RxDeviceObject, FromPool);
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE); if (FromPool) { ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL)); }
/* Make it top level IRP */ IoSetTopLevelIrp((PIRP)TopLevelContext); return TRUE;}
#if DBG/* * @implemented */VOIDRxUpdateShareAccess( _Inout_ PFILE_OBJECT FileObject, _Inout_ PSHARE_ACCESS ShareAccess, _In_ PSZ where, _In_ PSZ wherelogtag){ PAGED_CODE();
RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess); IoUpdateShareAccess(FileObject, ShareAccess); RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);}#endif
/* * @implemented */VOIDRxUninitializeCacheMap( PRX_CONTEXT RxContext, PFILE_OBJECT FileObject, PLARGE_INTEGER TruncateSize){ PFCB Fcb; NTSTATUS Status; CACHE_UNINITIALIZE_EVENT UninitEvent;
PAGED_CODE();
Fcb = FileObject->FsContext; ASSERT(NodeTypeIsFcb(Fcb)); ASSERT(RxIsFcbAcquiredExclusive(Fcb));
KeInitializeEvent(&UninitEvent.Event, SynchronizationEvent, FALSE); CcUninitializeCacheMap(FileObject, TruncateSize, &UninitEvent);
/* Always release the FCB before waiting for the uninit event */ RxReleaseFcb(RxContext, Fcb);
KeWaitForSingleObject(&UninitEvent.Event, Executive, KernelMode, FALSE, NULL);
/* Re-acquire it afterwards */ Status = RxAcquireExclusiveFcb(RxContext, Fcb); ASSERT(NT_SUCCESS(Status));}
VOIDNTAPIRxUnload( IN PDRIVER_OBJECT DriverObject){ UNIMPLEMENTED;}
VOIDNTAPIRxUnlockOperation( IN PVOID Context, IN PFILE_LOCK_INFO LockInfo){ UNIMPLEMENTED;}
VOIDRxUnstart( PRX_CONTEXT Context, PRDBSS_DEVICE_OBJECT DeviceObject){ UNIMPLEMENTED;}
/* * @implemented */VOIDRxUnwindTopLevelIrp( IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext){ DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext);
/* No TLC provided? Ask the system for ours! */ if (TopLevelContext == NULL) { TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp(); if (TopLevelContext == NULL) { return; }
/* In that case, just assert it's really ours */ ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext)); ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL)); }
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE); ASSERT(TopLevelContext->Thread == PsGetCurrentThread()); /* Restore the previous top level IRP */ IoSetTopLevelIrp(TopLevelContext->Previous); /* If TLC was allocated from pool, remove it from list and release it */ if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL)) { RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext); RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG); }}
/* * @implemented */VOIDRxUpdateShareAccessPerSrvOpens( IN PSRV_OPEN SrvOpen){ ACCESS_MASK DesiredAccess; BOOLEAN ReadAccess; BOOLEAN WriteAccess; BOOLEAN DeleteAccess;
PAGED_CODE();
/* If already updated, no need to continue */ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED)) { return; }
/* Check if any access wanted */ DesiredAccess = SrvOpen->DesiredAccess; ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0; WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0; DeleteAccess = (DesiredAccess & DELETE) != 0;
/* In that case, update it */ if ((ReadAccess) || (WriteAccess) || (DeleteAccess)) { BOOLEAN SharedRead; BOOLEAN SharedWrite; BOOLEAN SharedDelete; ULONG DesiredShareAccess; PSHARE_ACCESS ShareAccess;
ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens; DesiredShareAccess = SrvOpen->ShareAccess;
SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0; SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0; SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
ShareAccess->OpenCount++;
ShareAccess->Readers += ReadAccess; ShareAccess->Writers += WriteAccess; ShareAccess->Deleters += DeleteAccess; ShareAccess->SharedRead += SharedRead; ShareAccess->SharedWrite += SharedWrite; ShareAccess->SharedDelete += SharedDelete; }
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED);}
/* * @implemented */NTSTATUSRxXXXControlFileCallthru( PRX_CONTEXT Context){ NTSTATUS Status;
PAGED_CODE();
DPRINT("RxXXXControlFileCallthru(%p)\n", Context);
/* No dispatch table? Nothing to dispatch */ if (Context->RxDeviceObject->Dispatch == NULL) { Context->pFobx = NULL; return STATUS_INVALID_DEVICE_REQUEST; }
/* Init the lowio context */ Status = RxLowIoPopulateFsctlInfo(Context); if (!NT_SUCCESS(Status)) { return Status; }
/* Check whether we're consistent: a length means a buffer */ if ((Context->LowIoContext.ParamsFor.FsCtl.InputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pInputBuffer == NULL) || (Context->LowIoContext.ParamsFor.FsCtl.OutputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)) { return STATUS_INVALID_PARAMETER; }
/* Forward the call to the mini-rdr */ DPRINT("Calling: %p\n", Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile); Status = Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile(Context); if (Status != STATUS_PENDING) { Context->CurrentIrp->IoStatus.Information = Context->InformationToReturn; }
DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context->CurrentIrp->IoStatus.Status, Context->CurrentIrp->IoStatus.Information); return Status;}