Something went wrong. Try again.
Reactos
Something went wrong. Try again.
211 kB · 6961 lines
C
at master
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
Create.c
Abstract:
This module implements the File Create routine for Fat called by the dispatch driver.
--*/
#include "fatprocs.h"
//// The Bug check file id for this module//
#define BugCheckFileId (FAT_BUG_CHECK_CREATE)
//// The debug trace level//
#define Dbg (DEBUG_TRACE_CREATE)
//// Macros for incrementing performance counters.//
#define CollectCreateHitStatistics(VCB) { \ PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors]; \ Stats->Fat.CreateHits += 1; \}
#define CollectCreateStatistics(VCB,STATUS) { \ PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors]; \ if ((STATUS) == STATUS_SUCCESS) { \ Stats->Fat.SuccessfulCreates += 1; \ } else { \ Stats->Fat.FailedCreates += 1; \ } \}
LUID FatSecurityPrivilege = { SE_SECURITY_PRIVILEGE, 0 };
//// local procedure prototypes//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenVolume ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenRootDcb ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingDcb ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PDCB Dcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN FileNameOpenedDos, _Out_ PBOOLEAN OplockPostIrp );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingFcb ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PFCB Fcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN FileNameOpenedDos, _Out_ PBOOLEAN OplockPostIrp );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenTargetDirectory ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PDCB Dcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ BOOLEAN DoesNameExist, _In_ BOOLEAN FileNameOpenedDos );
_Success_(return.Status == STATUS_SUCCESS)_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingDirectory ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Outptr_result_maybenull_ PDCB *Dcb, _In_ PDCB ParentDcb, _In_ PDIRENT Dirent, _In_ ULONG LfnByteOffset, _In_ ULONG DirentByteOffset, _In_ PUNICODE_STRING Lfn, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN FileNameOpenedDos, _In_ BOOLEAN OpenRequiringOplock );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingFile ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Outptr_result_maybenull_ PFCB *Fcb, _In_ PDCB ParentDcb, _In_ PDIRENT Dirent, _In_ ULONG LfnByteOffset, _In_ ULONG DirentByteOffset, _In_ PUNICODE_STRING Lfn, _In_ PUNICODE_STRING OrigLfn, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ ULONG CreateDisposition, _In_ BOOLEAN IsPagingFile, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN FileNameOpenedDos );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatCreateNewDirectory ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PDCB ParentDcb, _In_ POEM_STRING OemName, _In_ PUNICODE_STRING UnicodeName, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatCreateNewFile ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PDCB ParentDcb, _In_ POEM_STRING OemName, _In_ PUNICODE_STRING UnicodeName, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ PUNICODE_STRING LfnBuffer, _In_ BOOLEAN IsPagingFile, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN TemporaryFile );
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatSupersedeOrOverwriteFile ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PFCB Fcb, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge );
NTSTATUSFatCheckSystemSecurityAccess ( _In_ PIRP_CONTEXT IrpContext );
NTSTATUSFatCheckShareAccess ( _In_ PIRP_CONTEXT IrpContext, _In_ PFILE_OBJECT FileObject, _In_ PFCB Fcb, _In_ PACCESS_MASK DesiredAccess, _In_ ULONG ShareAccess );
#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, FatCheckShareAccess)#pragma alloc_text(PAGE, FatCheckSystemSecurityAccess)#pragma alloc_text(PAGE, FatCommonCreate)
#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)#pragma alloc_text(PAGE, FatCommonCreateOnNewStack)#pragma alloc_text(PAGE, FatCommonCreateCallout)#endif
#pragma alloc_text(PAGE, FatCreateNewDirectory)#pragma alloc_text(PAGE, FatCreateNewFile)#pragma alloc_text(PAGE, FatFsdCreate)#pragma alloc_text(PAGE, FatOpenExistingDcb)#pragma alloc_text(PAGE, FatOpenExistingDirectory)#pragma alloc_text(PAGE, FatOpenExistingFcb)#pragma alloc_text(PAGE, FatOpenExistingFile)#pragma alloc_text(PAGE, FatOpenRootDcb)#pragma alloc_text(PAGE, FatOpenTargetDirectory)#pragma alloc_text(PAGE, FatOpenVolume)#pragma alloc_text(PAGE, FatSupersedeOrOverwriteFile)#pragma alloc_text(PAGE, FatSetFullNameInFcb)#endif
_Function_class_(IRP_MJ_CREATE)_Function_class_(DRIVER_DISPATCH)NTSTATUSNTAPIFatFsdCreate ( _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp )
/*++
Routine Description:
This routine implements the FSD part of the NtCreateFile and NtOpenFile API calls.
Arguments:
VolumeDeviceObject - Supplies the volume device object where the file/directory exists that we are trying to open/create
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The Fsd status for the Irp
--*/
{ NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL;
BOOLEAN TopLevel; BOOLEAN ExceptionCompletedIrp = FALSE;
PAGED_CODE();
// // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS //
if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) {
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
return STATUS_SUCCESS; }
TimerStart(Dbg);
DebugTrace(+1, Dbg, "FatFsdCreate\n", 0);
// // Call the common create routine, with block allowed if the operation // is synchronous. //
FsRtlEnterFileSystem();
TopLevel = FatIsIrpTopLevel( Irp );
_SEH2_TRY {
IrpContext = FatCreateIrpContext( Irp, TRUE );
#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) Status = FatCommonCreateOnNewStack( IrpContext, Irp );#else Status = FatCommonCreate( IrpContext, Irp );#endif
} _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
// // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code //
Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); ExceptionCompletedIrp = TRUE; } _SEH2_END;
if (TopLevel) { IoSetTopLevelIrp( NULL ); }
FsRtlExitFileSystem();
// // Complete the request, unless we had an exception, in which case it // was completed in FatProcessException (and the IrpContext freed). // // IrpContext is freed inside FatCompleteRequest. //
if (!ExceptionCompletedIrp && Status != STATUS_PENDING) { FatCompleteRequest( IrpContext, Irp, Status ); }
// // And return to our caller //
DebugTrace(-1, Dbg, "FatFsdCreate -> %08lx\n", Status );
TimerStop(Dbg,"FatFsdCreate");
UNREFERENCED_PARAMETER( VolumeDeviceObject );
return Status;}
#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)_Requires_lock_held_(_Global_critical_region_)VOIDFatCommonCreateCallout ( _In_ PFAT_CALLOUT_PARAMETERS CalloutParameters )
/*++
Routine Description:
This function is the callout routine that will execute on a new stack when processing a create. It simply calls FatCommonCreate() with the parameters in the context and stores the return value in the context.
Arguments:
Context - Supplies an opaque pointer to this function's context. It is actually an FAT_CALLOUT_PARAMETERS structure.
Return Value:
None.
--*/
{ PAGED_CODE();
// // Call FatCommonCreate() with the passed parameters and store the result. // Exceptions cannot be raised across stack boundaries, so we need to catch // exceptions here and deal with them. //
try {
CalloutParameters->IrpStatus = FatCommonCreate( CalloutParameters->Create.IrpContext, CalloutParameters->Create.Irp );
} except (FatExceptionFilter( CalloutParameters->Create.IrpContext, GetExceptionInformation() )) {
// // Return the resulting status. //
CalloutParameters->ExceptionStatus = GetExceptionCode(); }
}
_Requires_lock_held_(_Global_critical_region_)NTSTATUSFatCommonCreateOnNewStack ( _In_ PIRP_CONTEXT IrpContext, _In_ PIRP Irp )
/*++
Routine Description:
This routine sets up a switch to a new stack and call to FatCommonCreate().
Arguments:
IrpContext - Supplies the context structure for the overall request.
Irp - Supplies the IRP being processed.
CreateContext - Supplies a pointer on the old stack that is used to store context information for the create itself.
Return Value:
NTSTATUS - The status from FatCommonCreate().
--*/{ FAT_CALLOUT_PARAMETERS CalloutParameters; NTSTATUS status;
PAGED_CODE();
// // Create requests consume a lot of stack space. As such, we always switch to a // new stack when processing a create. Setup the callout parameters and make the // call. Note that this cannot fail, since we pass a stack context for a reserve stack. //
CalloutParameters.Create.IrpContext = IrpContext; CalloutParameters.Create.Irp = Irp; CalloutParameters.ExceptionStatus = CalloutParameters.IrpStatus = STATUS_SUCCESS;
// // Mark that we are swapping the stack //
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_SWAPPED_STACK );
status = KeExpandKernelStackAndCalloutEx( FatCommonCreateCallout, &CalloutParameters, KERNEL_STACK_SIZE, FALSE, NULL );
// // Mark that the stack is no longer swapped. Note that there are paths // that may clear this flag before returning. //
if (status != STATUS_PENDING) {
ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_SWAPPED_STACK ); }
// // If we had an exception occur, re-raise the exception. //
if (!NT_SUCCESS( CalloutParameters.ExceptionStatus )) { FatRaiseStatus( IrpContext, CalloutParameters.ExceptionStatus ); }
// // If the call to KeExpandKernelStackAndCalloutEx returns an error this // means that the callout routine (FatCommonCreateCallout) was never // called. Translate that error, and return it. //
if (!NT_SUCCESS( status )) {
// // Translate to an expected error value //
if (status == STATUS_NO_MEMORY) {
status = STATUS_INSUFFICIENT_RESOURCES; }
return status; }
// // Return the status given to us by the callout. //
return CalloutParameters.IrpStatus;}#endif
_Requires_lock_held_(_Global_critical_region_)NTSTATUSFatCommonCreate ( _Inout_ PIRP_CONTEXT IrpContext, _Inout_ PIRP Irp )
/*++
Routine Description:
This is the common routine for creating/opening a file called by both the fsd and fsp threads.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - the return status for the operation
--*/
{ NTSTATUS Status; IO_STATUS_BLOCK Iosb = {0}; PIO_STACK_LOCATION IrpSp;
PFILE_OBJECT FileObject; PFILE_OBJECT RelatedFileObject; UNICODE_STRING FileName; ULONG AllocationSize; PFILE_FULL_EA_INFORMATION EaBuffer; PACCESS_MASK DesiredAccess; ULONG Options; USHORT FileAttributes; USHORT ShareAccess; ULONG EaLength;
BOOLEAN CreateDirectory; BOOLEAN NoIntermediateBuffering; BOOLEAN OpenDirectory; BOOLEAN IsPagingFile; BOOLEAN OpenTargetDirectory; BOOLEAN DirectoryFile; BOOLEAN NonDirectoryFile; BOOLEAN NoEaKnowledge; BOOLEAN DeleteOnClose; BOOLEAN OpenRequiringOplock; BOOLEAN TemporaryFile; BOOLEAN FileNameOpenedDos = FALSE;
ULONG CreateDisposition;
PVCB Vcb; PFCB Fcb = NULL; PCCB Ccb; PDCB ParentDcb; PDCB FinalDcb = NULL;
UNICODE_STRING FinalName = {0}; UNICODE_STRING RemainingPart; UNICODE_STRING NextRemainingPart = {0}; UNICODE_STRING UpcasedFinalName; WCHAR UpcasedBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
OEM_STRING OemFinalName; UCHAR OemBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE*2];
PDIRENT Dirent; PBCB DirentBcb = NULL; ULONG LfnByteOffset; ULONG DirentByteOffset;
BOOLEAN PostIrp = FALSE; BOOLEAN OplockPostIrp = FALSE; BOOLEAN TrailingBackslash; BOOLEAN FirstLoop = TRUE;
ULONG MatchFlags = 0;
CCB LocalCcb; UNICODE_STRING Lfn; UNICODE_STRING OrigLfn = {0};
WCHAR LfnBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
PAGED_CODE();
// // Get the current IRP stack location //
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "FatCommonCreate\n", 0 ); DebugTrace( 0, Dbg, "Irp = %p\n", Irp ); DebugTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags ); DebugTrace( 0, Dbg, "->FileObject = %p\n", IrpSp->FileObject ); DebugTrace( 0, Dbg, " ->RelatedFileObject = %p\n", IrpSp->FileObject->RelatedFileObject ); DebugTrace( 0, Dbg, " ->FileName = %wZ\n", &IrpSp->FileObject->FileName ); DebugTrace( 0, Dbg, " ->FileName.Length = 0n%d\n", IrpSp->FileObject->FileName.Length ); DebugTrace( 0, Dbg, "->AllocationSize.LowPart = %08lx\n", Irp->Overlay.AllocationSize.LowPart ); DebugTrace( 0, Dbg, "->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart ); DebugTrace( 0, Dbg, "->SystemBuffer = %p\n", Irp->AssociatedIrp.SystemBuffer ); DebugTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess ); DebugTrace( 0, Dbg, "->Options = %08lx\n", IrpSp->Parameters.Create.Options ); DebugTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes ); DebugTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess ); DebugTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength );
// // This is here because the Win32 layer can't avoid sending me double // beginning backslashes. //
if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) && (IrpSp->FileObject->FileName.Buffer[1] == L'\\') && (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) {
IrpSp->FileObject->FileName.Length -= sizeof(WCHAR);
RtlMoveMemory( &IrpSp->FileObject->FileName.Buffer[0], &IrpSp->FileObject->FileName.Buffer[1], IrpSp->FileObject->FileName.Length );
// // If there are still two beginning backslashes, the name is bogus. //
if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) && (IrpSp->FileObject->FileName.Buffer[1] == L'\\') && (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) {
DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_OBJECT_NAME_INVALID\n", 0); return STATUS_OBJECT_NAME_INVALID; } }
// // Reference our input parameters to make things easier //
NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
FileObject = IrpSp->FileObject; FileName = FileObject->FileName; RelatedFileObject = FileObject->RelatedFileObject; AllocationSize = Irp->Overlay.AllocationSize.LowPart; EaBuffer = Irp->AssociatedIrp.SystemBuffer; DesiredAccess = &IrpSp->Parameters.Create.SecurityContext->DesiredAccess; Options = IrpSp->Parameters.Create.Options; FileAttributes = IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL; ShareAccess = IrpSp->Parameters.Create.ShareAccess; EaLength = IrpSp->Parameters.Create.EaLength;
// // Set up the file object's Vpb pointer in case anything happens. // This will allow us to get a reasonable pop-up. //
if ( RelatedFileObject != NULL ) { FileObject->Vpb = RelatedFileObject->Vpb; }
// // Force setting the archive bit in the attributes byte to follow OS/2, // & DOS semantics. Also mask out any extraneous bits, note that // we can't use the ATTRIBUTE_VALID_FLAGS constant because that has // the control and normal flags set. // // Delay setting ARCHIVE in case this is a directory: 2/16/95 //
FileAttributes &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_ENCRYPTED);
// // Locate the volume device object and Vcb that we are trying to access //
Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
// // Decipher Option flags and values //
// // If this is an open by fileid operation, just fail it explicitly. FAT's // source of fileids is not reversible for open operations. //
if (BooleanFlagOn( Options, FILE_OPEN_BY_FILE_ID )) {
return STATUS_NOT_IMPLEMENTED; }
DirectoryFile = BooleanFlagOn( Options, FILE_DIRECTORY_FILE ); NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE ); NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING ); NoEaKnowledge = BooleanFlagOn( Options, FILE_NO_EA_KNOWLEDGE ); DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE );#if (NTDDI_VERSION >= NTDDI_WIN7) OpenRequiringOplock = BooleanFlagOn( Options, FILE_OPEN_REQUIRING_OPLOCK );#else OpenRequiringOplock = FALSE;#endif
TemporaryFile = BooleanFlagOn( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
CreateDisposition = (Options >> 24) & 0x000000ff;
IsPagingFile = BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ); OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY );
CreateDirectory = (BOOLEAN)(DirectoryFile && ((CreateDisposition == FILE_CREATE) || (CreateDisposition == FILE_OPEN_IF)));
OpenDirectory = (BOOLEAN)(DirectoryFile && ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OPEN_IF)));
// // Make sure the input large integer is valid and that the dir/nondir // indicates a storage type we understand. //
if (Irp->Overlay.AllocationSize.HighPart != 0 || (DirectoryFile && NonDirectoryFile)) {
DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_INVALID_PARAMETER\n", 0); return STATUS_INVALID_PARAMETER; }
// // Acquire exclusive access to the vcb, and enqueue the Irp if // we didn't get it. //
if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
Iosb.Status = FatFsdPostRequest( IrpContext, Irp );
DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status ); return Iosb.Status; }
// // Make sure we haven't been called recursively by a filter inside an existing // create request. //
if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS)) {
#ifdef _MSC_VER#pragma prefast( suppress:28159, "this is a serious programming error if it happens" )#endif FatBugCheck( 0, 0, 0); }
// // Initialize the DirentBcb to null //
DirentBcb = NULL;
// // Initialize our temp strings with their stack buffers. //
OemFinalName.Length = 0; OemFinalName.MaximumLength = sizeof( OemBuffer); OemFinalName.Buffer = (PCHAR)OemBuffer;
UpcasedFinalName.Length = 0; UpcasedFinalName.MaximumLength = sizeof( UpcasedBuffer); UpcasedFinalName.Buffer = UpcasedBuffer;
Lfn.Length = 0; Lfn.MaximumLength = sizeof( LfnBuffer); Lfn.Buffer = LfnBuffer;
_SEH2_TRY {
// // Make sure the vcb is in a usable condition. This will raise // and error condition if the volume is unusable //
FatVerifyVcb( IrpContext, Vcb );
// // If the Vcb is locked then we cannot open another file //
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
DebugTrace(0, Dbg, "Volume is locked\n", 0);
Status = STATUS_ACCESS_DENIED; if (Vcb->VcbCondition != VcbGood) {
Status = STATUS_VOLUME_DISMOUNTED; } try_return( Iosb.Status = Status ); }
// // Don't allow the DELETE_ON_CLOSE option if the volume is // write-protected. //
if (DeleteOnClose && FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
// // Set the real device for the pop-up info, and set the verify // bit in the device object, so that we will force a verify // in case the user put the correct media back in. //
IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, Vcb->Vpb->RealDevice );
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); }
// // If this is a fat32 volume, EA's are not supported. //
if (EaBuffer != NULL) {
try_return( Iosb.Status = STATUS_EAS_NOT_SUPPORTED ); }
// // Check if we are opening the volume and not a file/directory. // We are opening the volume if the name is empty and there // isn't a related file object. If there is a related file object // then it is the Vcb itself. //
if (FileName.Length == 0) {
PVCB DecodeVcb = NULL;
if (RelatedFileObject == NULL || FatDecodeFileObject( RelatedFileObject, &DecodeVcb, &Fcb, &Ccb ) == UserVolumeOpen) {
NT_ASSERT( RelatedFileObject == NULL || Vcb == DecodeVcb );
// // Check if we were to open a directory //
if (DirectoryFile) {
DebugTrace(0, Dbg, "Cannot open volume as a directory\n", 0);
try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY ); }
// // Can't open the TargetDirectory of the DASD volume. //
if (OpenTargetDirectory) {
try_return( Iosb.Status = STATUS_INVALID_PARAMETER ); }
DebugTrace(0, Dbg, "Opening the volume, Vcb = %p\n", Vcb);
CollectCreateHitStatistics(Vcb);
Iosb = FatOpenVolume( IrpContext, FileObject, Vcb, DesiredAccess, ShareAccess, CreateDisposition );
Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); } }
// // If there is a related file object then this is a relative open. // The related file object is the directory to start our search at. // Return an error if it is not a directory. //
if (RelatedFileObject != NULL) {
PVCB RelatedVcb; PDCB RelatedDcb; PCCB RelatedCcb; TYPE_OF_OPEN TypeOfOpen;
TypeOfOpen = FatDecodeFileObject( RelatedFileObject, &RelatedVcb, &RelatedDcb, &RelatedCcb );
if (TypeOfOpen != UserFileOpen && TypeOfOpen != UserDirectoryOpen) {
DebugTrace(0, Dbg, "Invalid related file object\n", 0);
try_return( Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND ); }
// // A relative open must be via a relative path. //
if (FileName.Length != 0 && FileName.Buffer[0] == L'\\') {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
// // Set up the file object's Vpb pointer in case anything happens. //
NT_ASSERT( Vcb == RelatedVcb );
FileObject->Vpb = RelatedFileObject->Vpb;
// // Now verify the related Fcb so we don't get in trouble later // by assuming its in good shape. //
FatVerifyFcb( IrpContext, RelatedDcb );
ParentDcb = RelatedDcb;
} else {
// // This is not a relative open, so check if we're // opening the root dcb //
if ((FileName.Length == sizeof(WCHAR)) && (FileName.Buffer[0] == L'\\')) {
// // Check if we were not supposed to open a directory //
if (NonDirectoryFile) {
DebugTrace(0, Dbg, "Cannot open root directory as a file\n", 0);
try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY ); }
// // Can't open the TargetDirectory of the root directory. //
if (OpenTargetDirectory) {
try_return( Iosb.Status = STATUS_INVALID_PARAMETER ); }
// // Not allowed to delete root directory. //
if (DeleteOnClose) {
try_return( Iosb.Status = STATUS_CANNOT_DELETE ); }
DebugTrace(0, Dbg, "Opening root dcb\n", 0);
CollectCreateHitStatistics(Vcb);
Iosb = FatOpenRootDcb( IrpContext, FileObject, Vcb, DesiredAccess, ShareAccess, CreateDisposition );
Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); }
// // Nope, we will be opening relative to the root directory. //
ParentDcb = Vcb->RootDcb;
// // Now verify the root Dcb so we don't get in trouble later // by assuming its in good shape. //
FatVerifyFcb( IrpContext, ParentDcb ); }
// // FatCommonCreate(): trailing backslash check //
if ((FileName.Length != 0) && (FileName.Buffer[FileName.Length/sizeof(WCHAR)-1] == L'\\')) {
FileName.Length -= sizeof(WCHAR); TrailingBackslash = TRUE;
} else {
TrailingBackslash = FALSE; }
// // Check for max path. We might want to tighten this down to DOS MAX_PATH // for maximal interchange with non-NT platforms, but for now defer to the // possibility of something depending on it. //
if (ParentDcb->FullFileName.Buffer == NULL) {
FatSetFullFileNameInFcb( IrpContext, ParentDcb ); }
if ((USHORT) (ParentDcb->FullFileName.Length + sizeof(WCHAR) + FileName.Length) <= FileName.Length) {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
// // We loop here until we land on an Fcb that is in a good // condition. This way we can reopen files that have stale handles // to files of the same name but are now different. //
while ( TRUE ) {
Fcb = ParentDcb; RemainingPart = FileName;
// // Now walk down the Dcb tree looking for the longest prefix. // This one exit condition in the while() is to handle a // special case condition (relative NULL name open), the main // exit conditions are at the bottom of the loop. //
while (RemainingPart.Length != 0) {
PFCB NextFcb;
FsRtlDissectName( RemainingPart, &FinalName, &NextRemainingPart );
// // If RemainingPart starts with a backslash the name is // invalid. // Check for no more than 255 characters in FinalName //
if (((NextRemainingPart.Length != 0) && (NextRemainingPart.Buffer[0] == L'\\')) || (FinalName.Length > 255*sizeof(WCHAR))) {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
// // Now, try to convert this one component into Oem and search // the splay tree. If it works then that's great, otherwise // we have to try with the UNICODE name instead. //
FatEnsureStringBufferEnough( &OemFinalName, FinalName.Length);
Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE );
if (NT_SUCCESS(Status)) {
NextFcb = FatFindFcb( IrpContext, &Fcb->Specific.Dcb.RootOemNode, (PSTRING)&OemFinalName, &FileNameOpenedDos );
} else {
NextFcb = NULL; OemFinalName.Length = 0;
if (Status != STATUS_UNMAPPABLE_CHARACTER) {
try_return( Iosb.Status = Status ); } }
// // If we didn't find anything searching the Oem space, we // have to try the Unicode space. To save cycles in the // common case that this tree is empty, we do a quick check // here. //
if ((NextFcb == NULL) && Fcb->Specific.Dcb.RootUnicodeNode) {
// // First downcase, then upcase the string, because this // is what happens when putting names into the tree (see // strucsup.c, FatConstructNamesInFcb()). //
FatEnsureStringBufferEnough( &UpcasedFinalName, FinalName.Length);
Status = RtlDowncaseUnicodeString(&UpcasedFinalName, &FinalName, FALSE ); NT_ASSERT( NT_SUCCESS( Status ));
Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &UpcasedFinalName, FALSE ); NT_ASSERT( NT_SUCCESS( Status ));
NextFcb = FatFindFcb( IrpContext, &Fcb->Specific.Dcb.RootUnicodeNode, (PSTRING)&UpcasedFinalName, &FileNameOpenedDos ); }
// // If we got back an Fcb then we consumed the FinalName // legitimately, so the remaining name is now RemainingPart. //
if (NextFcb != NULL) { Fcb = NextFcb; RemainingPart = NextRemainingPart; }
if ((NextFcb == NULL) || (NodeType(NextFcb) == FAT_NTC_FCB) || (NextRemainingPart.Length == 0)) {
break; } }
// // Remaining name cannot start with a backslash //
if (RemainingPart.Length && (RemainingPart.Buffer[0] == L'\\')) {
RemainingPart.Length -= sizeof(WCHAR); RemainingPart.Buffer += 1; }
// // Now verify that everybody up to the longest found prefix is valid. //
_SEH2_TRY {
FatVerifyFcb( IrpContext, Fcb );
} _SEH2_EXCEPT( (_SEH2_GetExceptionCode() == STATUS_FILE_INVALID) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
FatResetExceptionState( IrpContext ); } _SEH2_END;
if ( Fcb->FcbCondition == FcbGood ) {
// // If we are trying to open a paging file and have happened // upon the DelayedCloseFcb, make it go away, and try again. //
if (IsPagingFile && FirstLoop && (NodeType(Fcb) == FAT_NTC_FCB) && (!IsListEmpty( &FatData.AsyncCloseList ) || !IsListEmpty( &FatData.DelayedCloseList ))) {
FatFspClose(Vcb);
FirstLoop = FALSE;
continue;
} else {
break; }
} else {
FatRemoveNames( IrpContext, Fcb ); } }
NT_ASSERT( Fcb->FcbCondition == FcbGood );
// // If there is already an Fcb for a paging file open and // it was not already opened as a paging file, we cannot // continue as it is too difficult to move a live Fcb to // non-paged pool. //
if (IsPagingFile) {
if (NodeType(Fcb) == FAT_NTC_FCB && !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
try_return( Iosb.Status = STATUS_SHARING_VIOLATION ); }
// // Check for a system file. //
} else if (FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
try_return( Iosb.Status = STATUS_ACCESS_DENIED ); }
// // If the longest prefix is pending delete (either the file or // some higher level directory), we cannot continue. //
if (FlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE )) {
try_return( Iosb.Status = STATUS_DELETE_PENDING ); }
// // Now that we've found the longest matching prefix we'll // check if there isn't any remaining part because that means // we've located an existing fcb/dcb to open and we can do the open // without going to the disk //
if (RemainingPart.Length == 0) {
// // First check if the user wanted to open the target directory // and if so then call the subroutine to finish the open. //
if (OpenTargetDirectory) {
CollectCreateHitStatistics(Vcb);
Iosb = FatOpenTargetDirectory( IrpContext, FileObject, Fcb->ParentDcb, DesiredAccess, ShareAccess, TRUE, FileNameOpenedDos ); Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); }
// // We can open an existing fcb/dcb, now we only need to case // on which type to open. //
if (NodeType(Fcb) == FAT_NTC_DCB || NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
// // This is a directory we're opening up so check if // we were not to open a directory //
if (NonDirectoryFile) {
DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0);
try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY ); }
DebugTrace(0, Dbg, "Open existing dcb, Dcb = %p\n", Fcb);
CollectCreateHitStatistics(Vcb);
Iosb = FatOpenExistingDcb( IrpContext, IrpSp, FileObject, Vcb, (PDCB)Fcb, DesiredAccess, ShareAccess, CreateDisposition, NoEaKnowledge, DeleteOnClose, OpenRequiringOplock, FileNameOpenedDos, &OplockPostIrp );
if (Iosb.Status != STATUS_PENDING) {
Irp->IoStatus.Information = Iosb.Information;
} else {
DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0);
PostIrp = TRUE; }
try_return( Iosb.Status ); }
// // Check if we're trying to open an existing Fcb and that // the user didn't want to open a directory. Note that this // call might actually come back with status_pending because // the user wanted to supersede or overwrite the file and we // cannot block. If it is pending then we do not complete the // request, and we fall through the bottom to the code that // dispatches the request to the fsp. //
if (NodeType(Fcb) == FAT_NTC_FCB) {
// // Check if we were only to open a directory //
if (OpenDirectory) {
DebugTrace(0, Dbg, "Cannot open file as directory\n", 0);
try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY ); }
DebugTrace(0, Dbg, "Open existing fcb, Fcb = %p\n", Fcb);
if ( TrailingBackslash ) { try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
CollectCreateHitStatistics(Vcb);
Iosb = FatOpenExistingFcb( IrpContext, IrpSp, FileObject, Vcb, Fcb, DesiredAccess, ShareAccess, AllocationSize, EaBuffer, EaLength, FileAttributes, CreateDisposition, NoEaKnowledge, DeleteOnClose, OpenRequiringOplock, FileNameOpenedDos, &OplockPostIrp );
if (Iosb.Status != STATUS_PENDING) {
// // Check if we need to set the cache support flag in // the file object //
if (NT_SUCCESS( Iosb.Status) && !NoIntermediateBuffering) {
FileObject->Flags |= FO_CACHE_SUPPORTED; }
Irp->IoStatus.Information = Iosb.Information;
} else {
DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0);
PostIrp = TRUE; }
try_return( Iosb.Status ); }
// // Not and Fcb or a Dcb so we bug check //
#ifdef _MSC_VER#pragma prefast( suppress:28159, "this is a serious corruption if it happens" )#endif FatBugCheck( NodeType(Fcb), (ULONG_PTR) Fcb, 0 ); }
// // There is more in the name to parse than we have in existing // fcbs/dcbs. So now make sure that fcb we got for the largest // matching prefix is really a dcb otherwise we can't go any // further //
if ((NodeType(Fcb) != FAT_NTC_DCB) && (NodeType(Fcb) != FAT_NTC_ROOT_DCB)) {
DebugTrace(0, Dbg, "Cannot open file as subdirectory, Fcb = %p\n", Fcb);
try_return( Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND ); }
// // Otherwise we continue on processing the Irp and allowing ourselves // to block for I/O as necessary. Find/create additional dcb's for // the one we're trying to open. We loop until either remaining part // is empty or we get a bad filename. When we exit FinalName is // the last name in the string we're after, and ParentDcb is the // parent directory that will contain the opened/created // file/directory. // // Make sure the rest of the name is valid in at least the LFN // character set (which just happens to be that of HPFS). // // If we are not in ChicagoMode, use FAT semantics. //
ParentDcb = Fcb; FirstLoop = TRUE;
while (TRUE) {
// // We do one little optimization here on the first iteration of // the loop since we know that we have already tried to convert // FinalOemName from the original UNICODE. //
if (FirstLoop) {
FirstLoop = FALSE; RemainingPart = NextRemainingPart; Status = OemFinalName.Length ? STATUS_SUCCESS : STATUS_UNMAPPABLE_CHARACTER;
} else {
// // Dissect the remaining part. //
DebugTrace(0, Dbg, "Dissecting the name %wZ\n", &RemainingPart);
FsRtlDissectName( RemainingPart, &FinalName, &RemainingPart );
// // If RemainingPart starts with a backslash the name is // invalid. // Check for no more than 255 characters in FinalName //
if (((RemainingPart.Length != 0) && (RemainingPart.Buffer[0] == L'\\')) || (FinalName.Length > 255*sizeof(WCHAR))) {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
// // Now, try to convert this one component into Oem. If it works // then that's great, otherwise we have to try with the UNICODE // name instead. //
FatEnsureStringBufferEnough( &OemFinalName, FinalName.Length);
Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE ); }
if (NT_SUCCESS(Status)) {
// // We'll start by trying to locate the dirent for the name. Note // that we already know that there isn't an Fcb/Dcb for the file // otherwise we would have found it when we did our prefix lookup. //
if (FatIsNameShortOemValid( IrpContext, OemFinalName, FALSE, FALSE, FALSE )) {
FatStringTo8dot3( IrpContext, OemFinalName, &LocalCcb.OemQueryTemplate.Constant );
LocalCcb.Flags = 0;
} else {
LocalCcb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE; }
} else {
LocalCcb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE;
if (Status != STATUS_UNMAPPABLE_CHARACTER) {
try_return( Iosb.Status = Status ); } }
// // Now we know a lot about the final name, so do legal name // checking here. //
if (FatData.ChicagoMode) {
if (!FatIsNameLongUnicodeValid( IrpContext, &FinalName, FALSE, FALSE, FALSE )) {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
} else {
if (FlagOn(LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE)) {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); } }
DebugTrace(0, Dbg, "FinalName is %wZ\n", &FinalName); DebugTrace(0, Dbg, "RemainingPart is %wZ\n", &RemainingPart);
FatEnsureStringBufferEnough( &UpcasedFinalName, FinalName.Length);
if (!NT_SUCCESS(Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &FinalName, FALSE))) {
try_return( Iosb.Status = Status ); }
LocalCcb.UnicodeQueryTemplate = UpcasedFinalName; LocalCcb.ContainsWildCards = FALSE;
Lfn.Length = 0;
FatLocateDirent( IrpContext, ParentDcb, &LocalCcb, 0, &MatchFlags, &Dirent, &DirentBcb, (PVBO)&DirentByteOffset, &FileNameOpenedDos, &Lfn, &OrigLfn);
// // Remember we read this Dcb for error recovery. //
FinalDcb = ParentDcb;
// // If the remaining part is now empty then this is the last name // in the string and the one we want to open //
if (RemainingPart.Length == 0) {
break; }
// // We didn't find a dirent, bail. //
if (Dirent == NULL) {
Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND; try_return( Iosb.Status ); }
// // We now have a dirent, make sure it is a directory //
if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND; try_return( Iosb.Status ); }
// // Compute the LfnByteOffset. //
LfnByteOffset = DirentByteOffset - FAT_LFN_DIRENTS_NEEDED(&OrigLfn) * sizeof(LFN_DIRENT);
// // Create a dcb for the new directory //
ParentDcb = FatCreateDcb( IrpContext, Vcb, ParentDcb, LfnByteOffset, DirentByteOffset, Dirent, &Lfn );
// // Remember we created this Dcb for error recovery. //
FinalDcb = ParentDcb;
FatSetFullNameInFcb( IrpContext, ParentDcb, &FinalName ); }
// // First check if the user wanted to open the target directory // and if so then call the subroutine to finish the open. //
if (OpenTargetDirectory) {
Iosb = FatOpenTargetDirectory( IrpContext, FileObject, ParentDcb, DesiredAccess, ShareAccess, Dirent ? TRUE : FALSE, FileNameOpenedDos);
Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); }
if (Dirent != NULL) {
// // Compute the LfnByteOffset. //
LfnByteOffset = DirentByteOffset - FAT_LFN_DIRENTS_NEEDED(&OrigLfn) * sizeof(LFN_DIRENT);
// // We were able to locate an existing dirent entry, so now // see if it is a directory that we're trying to open. //
if (FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
// // Make sure its okay to open a directory //
if (NonDirectoryFile) {
DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0);
try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY ); }
DebugTrace(0, Dbg, "Open existing directory\n", 0);
Iosb = FatOpenExistingDirectory( IrpContext, IrpSp, FileObject, Vcb, &Fcb, ParentDcb, Dirent, LfnByteOffset, DirentByteOffset, &Lfn, DesiredAccess, ShareAccess, CreateDisposition, NoEaKnowledge, DeleteOnClose, FileNameOpenedDos, OpenRequiringOplock );
Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); }
// // Otherwise we're trying to open and existing file, and we // need to check if the user only wanted to open a directory. //
if (OpenDirectory) {
DebugTrace(0, Dbg, "Cannot open file as directory\n", 0);
try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY ); }
DebugTrace(0, Dbg, "Open existing file\n", 0);
if ( TrailingBackslash ) { try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
Iosb = FatOpenExistingFile( IrpContext, FileObject, Vcb, &Fcb, ParentDcb, Dirent, LfnByteOffset, DirentByteOffset, &Lfn, &OrigLfn, DesiredAccess, ShareAccess, AllocationSize, EaBuffer, EaLength, FileAttributes, CreateDisposition, IsPagingFile, NoEaKnowledge, DeleteOnClose, OpenRequiringOplock, FileNameOpenedDos );
// // Check if we need to set the cache support flag in // the file object //
if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) {
FileObject->Flags |= FO_CACHE_SUPPORTED; }
Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); }
// // We can't locate a dirent so this is a new file. //
// // Now check to see if we wanted to only open an existing file. // And then case on whether we wanted to create a file or a directory. //
if ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OVERWRITE)) {
DebugTrace( 0, Dbg, "Cannot open nonexisting file\n", 0);
try_return( Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND ); }
// // Skip a few cycles later if we know now that the Oem name is not // valid 8.3. //
if (FlagOn(LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE)) {
OemFinalName.Length = 0; }
// // Determine the granted access for this operation now. //
if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
try_return( Iosb ); }
if (CreateDirectory) {
DebugTrace(0, Dbg, "Create new directory\n", 0);
// // If this media is write protected, don't even try the create. //
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
// // Set the real device for the pop-up info, and set the verify // bit in the device object, so that we will force a verify // in case the user put the correct media back in. //
IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, Vcb->Vpb->RealDevice );
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); }
// // Don't allow people to create directories with the // temporary bit set. //
if (TemporaryFile) {
try_return( Iosb.Status = STATUS_INVALID_PARAMETER ); }
Iosb = FatCreateNewDirectory( IrpContext, IrpSp, FileObject, Vcb, ParentDcb, &OemFinalName, &FinalName, DesiredAccess, ShareAccess, EaBuffer, EaLength, FileAttributes, NoEaKnowledge, DeleteOnClose, OpenRequiringOplock );
Irp->IoStatus.Information = Iosb.Information; try_return( Iosb.Status ); }
DebugTrace(0, Dbg, "Create new file\n", 0);
if ( TrailingBackslash ) {
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); }
// // If this media is write protected, don't even try the create. //
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
// // Set the real device for the pop-up info, and set the verify // bit in the device object, so that we will force a verify // in case the user put the correct media back in. //
IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, Vcb->Vpb->RealDevice );
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); }
Iosb = FatCreateNewFile( IrpContext, IrpSp, FileObject, Vcb, ParentDcb, &OemFinalName, &FinalName, DesiredAccess, ShareAccess, AllocationSize, EaBuffer, EaLength, FileAttributes, &Lfn, IsPagingFile, NoEaKnowledge, DeleteOnClose, OpenRequiringOplock, TemporaryFile );
// // Check if we need to set the cache support flag in // the file object //
if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) {
FileObject->Flags |= FO_CACHE_SUPPORTED; }
Irp->IoStatus.Information = Iosb.Information;
try_exit: NOTHING;
// // This is a Beta Fix. Do this at a better place later. //
if (NT_SUCCESS(Iosb.Status) && !OpenTargetDirectory) {
PFCB LocalFcb;
// // If there is an Fcb/Dcb, set the long file name. //
LocalFcb = FileObject->FsContext;
if (LocalFcb && ((NodeType(LocalFcb) == FAT_NTC_FCB) || (NodeType(LocalFcb) == FAT_NTC_DCB)) && (LocalFcb->FullFileName.Buffer == NULL)) {
FatSetFullNameInFcb( IrpContext, LocalFcb, &FinalName ); } }
} _SEH2_FINALLY {
DebugUnwind( FatCommonCreate );
#if (NTDDI_VERSION >= NTDDI_WIN7)
// // If we're not getting out with success, and if the caller wanted // atomic create-with-oplock semantics make sure we back out any // oplock that may have been granted. //
if ((AbnormalTermination() || !NT_SUCCESS( Iosb.Status )) && OpenRequiringOplock && (Iosb.Status != STATUS_CANNOT_BREAK_OPLOCK) && (IrpContext->ExceptionStatus != STATUS_CANNOT_BREAK_OPLOCK) && (Fcb != NULL) && FatIsFileOplockable( Fcb )) {
FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_BACK_OUT_ATOMIC_OPLOCK, NULL, NULL, NULL ); }#endif
// // There used to be a test here - the ASSERT replaces it. We will // never have begun enumerating directories if we post the IRP for // oplock reasons. //
NT_ASSERT( !OplockPostIrp || DirentBcb == NULL );
FatUnpinBcb( IrpContext, DirentBcb );
// // If we are in an error path, check for any created subdir Dcbs that // have to be unwound. Don't whack the root directory. // // Note this will leave a branch of Dcbs dangling if the directory file // had not been built on the leaf (case: opening path which has an // element containing an invalid character name). //
if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) {
ULONG SavedFlags;
// // Before doing the uninitialize, we have to unpin anything // that has been repinned, but disable writethrough first. We // disable raise from unpin-repin since we're already failing. //
SavedFlags = IrpContext->Flags;
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE | IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH );
FatUnpinRepinnedBcbs( IrpContext );
if ((FinalDcb != NULL) && (NodeType(FinalDcb) == FAT_NTC_DCB) && IsListEmpty(&FinalDcb->Specific.Dcb.ParentDcbQueue) && (FinalDcb->OpenCount == 0) && (FinalDcb->Specific.Dcb.DirectoryFile != NULL)) {
PFILE_OBJECT DirectoryFileObject;
DirectoryFileObject = FinalDcb->Specific.Dcb.DirectoryFile;
FinalDcb->Specific.Dcb.DirectoryFile = NULL;
CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
ObDereferenceObject( DirectoryFileObject ); }
IrpContext->Flags = SavedFlags; }
if (_SEH2_AbnormalTermination()) {
FatReleaseVcb( IrpContext, Vcb ); }
// // Free up any string buffers we allocated //
FatFreeStringBuffer( &OemFinalName);
FatFreeStringBuffer( &UpcasedFinalName);
FatFreeStringBuffer( &Lfn); } _SEH2_END;
// // The following code is only executed if we are exiting the // procedure through a normal termination. We complete the request // and if for any reason that bombs out then we need to unreference // and possibly delete the fcb and ccb. //
_SEH2_TRY {
if (PostIrp) {
// // If the Irp hasn't already been posted, do it now. //
if (!OplockPostIrp) {
Iosb.Status = FatFsdPostRequest( IrpContext, Irp ); }
} else {
FatUnpinRepinnedBcbs( IrpContext ); }
} _SEH2_FINALLY {
DebugUnwind( FatCommonCreate-in-FatCompleteRequest );
if (_SEH2_AbnormalTermination() ) {
PVCB LocalVcb; PFCB LocalFcb; PCCB LocalCcb2; PFILE_OBJECT DirectoryFileObject;
// // Unwind all of our counts. Note that if a write failed, then // the volume has been marked for verify, and all volume // structures will be cleaned up automatically. //
(VOID) FatDecodeFileObject( FileObject, &LocalVcb, &LocalFcb, &LocalCcb2 );
LocalFcb->UncleanCount -= 1; LocalFcb->OpenCount -= 1; LocalVcb->OpenFileCount -= 1;
if (IsFileObjectReadOnly(FileObject)) { LocalVcb->ReadOnlyCount -= 1; }
// // WinSE #307418 "Occasional data corruption when standby/resume // while copying files to removable FAT formatted media". // If new file creation request was interrupted by system suspend // operation we should revert the changes we made to the parent // directory and to the allocation table. //
if (IrpContext->ExceptionStatus == STATUS_VERIFY_REQUIRED && NodeType( LocalFcb ) == FAT_NTC_FCB) {
FatTruncateFileAllocation( IrpContext, LocalFcb, 0 );
FatDeleteDirent( IrpContext, LocalFcb, NULL, TRUE ); }
// // If we leafed out on a new Fcb we should get rid of it at this point. // // Since the object isn't being opened, we have to do all of the teardown // here. Our close path will not occur for this fileobject. Note this // will leave a branch of Dcbs dangling since we do it by hand and don't // chase to the root. //
if (LocalFcb->OpenCount == 0 && (NodeType( LocalFcb ) == FAT_NTC_FCB || IsListEmpty(&LocalFcb->Specific.Dcb.ParentDcbQueue))) {
NT_ASSERT( NodeType( LocalFcb ) != FAT_NTC_ROOT_DCB );
if ( (NodeType( LocalFcb ) == FAT_NTC_DCB) && (LocalFcb->Specific.Dcb.DirectoryFile != NULL) ) {
DirectoryFileObject = LocalFcb->Specific.Dcb.DirectoryFile; LocalFcb->Specific.Dcb.DirectoryFile = NULL;
CcUninitializeCacheMap( DirectoryFileObject, &FatLargeZero, NULL );
ObDereferenceObject( DirectoryFileObject );
} else { if (ARGUMENT_PRESENT( FileObject )) { FileObject->SectionObjectPointer = NULL; } FatDeleteFcb( IrpContext, &LocalFcb ); } }
FatDeleteCcb( IrpContext, &LocalCcb2 );
FatReleaseVcb( IrpContext, LocalVcb );
} else {
FatReleaseVcb( IrpContext, Vcb );
if ( !PostIrp ) {
// // If this request is successful and the file was opened // for FILE_EXECUTE access, then set the FileObject bit. //
NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL ); if (FlagOn( *DesiredAccess, FILE_EXECUTE )) {
SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ ); }
// // Lock volume in drive if we opened a paging file, allocating a // reserve MDL to guarantee paging file operations can always // go forward. //
if (IsPagingFile && NT_SUCCESS(Iosb.Status)) {
#ifdef _MSC_VER#pragma prefast( suppress:28112, "this should be safe" )#endif if (!FatReserveMdl) {
PMDL ReserveMdl = IoAllocateMdl( NULL, FAT_RESERVE_MDL_SIZE * PAGE_SIZE, TRUE, FALSE, NULL );
// // Stash the MDL, and if it turned out there was already one there // just free what we got. //
#ifndef __REACTOS__ InterlockedCompareExchangePointer( &FatReserveMdl, ReserveMdl, NULL );#else InterlockedCompareExchangePointer( (void * volatile*)&FatReserveMdl, ReserveMdl, NULL );#endif
#ifdef _MSC_VER#pragma prefast( suppress:28112, "this should be safe" )#endif if (FatReserveMdl != ReserveMdl) {
IoFreeMdl( ReserveMdl ); } }
SetFlag(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE);
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE ); } }
} }
DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status); } _SEH2_END;
CollectCreateStatistics(Vcb, Iosb.Status);
return Iosb.Status;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenVolume ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition )
/*++
Routine Description:
This routine opens the specified volume for DASD access
Arguments:
FileObject - Supplies the File object
Vcb - Supplies the Vcb denoting the volume being opened
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
CreateDisposition - Supplies the create disposition for this operation
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp;
#ifndef __REACTOS__ IO_STATUS_BLOCK Iosb = {0,0};#else IO_STATUS_BLOCK Iosb = {{0}};#endif
BOOLEAN CleanedVolume = FALSE;
// // The following variables are for abnormal termination //
BOOLEAN UnwindShareAccess = FALSE; PCCB UnwindCcb = NULL; BOOLEAN UnwindCounts = FALSE; BOOLEAN UnwindVolumeLock = FALSE;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenVolume...\n", 0);
_SEH2_TRY {
// // Check for proper desired access and rights //
if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) {
try_return( Status = STATUS_ACCESS_DENIED ); }
// // If the user does not want to share write or delete then we will try // and take out a lock on the volume. //
if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) && !FlagOn(ShareAccess, FILE_SHARE_DELETE)) {
#if (NTDDI_VERSION >= NTDDI_VISTA) // // See if the user has requested write access. If so, they cannot share // read. There is one exception to this. We allow autochk to get an // implicit lock on the volume while still allowing readers. Once the // the system is booted, though, we do not allow this type of access. //
if (FlagOn( *DesiredAccess, (FILE_WRITE_DATA | FILE_APPEND_DATA) ) && FsRtlAreVolumeStartupApplicationsComplete()) {
ClearFlag( ShareAccess, FILE_SHARE_READ ); }#endif
// // Do a quick check here for handles on exclusive open. //
if (!FlagOn(ShareAccess, FILE_SHARE_READ) && !FatIsHandleCountZero( IrpContext, Vcb )) {
try_return( Status = STATUS_SHARING_VIOLATION ); }
// // Force Mm to get rid of its referenced file objects. //
FatFlushFat( IrpContext, Vcb );
FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
// // If the user also does not want to share read then we check // if anyone is already using the volume, and if so then we // deny the access. If the user wants to share read then // we allow the current opens to stay provided they are only // readonly opens and deny further opens. //
if (!FlagOn(ShareAccess, FILE_SHARE_READ)) {
if (Vcb->OpenFileCount != 0) {
try_return( Status = STATUS_SHARING_VIOLATION ); }
} else {
if (Vcb->ReadOnlyCount != Vcb->OpenFileCount) {
try_return( Status = STATUS_SHARING_VIOLATION ); } }
// // Lock the volume //
Vcb->VcbState |= VCB_STATE_FLAG_LOCKED; Vcb->FileObjectWithVcbLocked = FileObject; UnwindVolumeLock = TRUE;
// // Clean the volume //
CleanedVolume = TRUE;
} else if (FlagOn( *DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA )) {
// // Flush the volume and let ourselves push the clean bit out if everything // worked. //
if (NT_SUCCESS( FatFlushVolume( IrpContext, Vcb, Flush ))) {
CleanedVolume = TRUE; } }
// // Clean the volume if we believe it safe and reasonable. //
if (CleanedVolume && FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) && !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) && !CcIsThereDirtyData(Vcb->Vpb)) {
// // Cancel any pending clean volumes. //
(VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
FatMarkVolume( IrpContext, Vcb, VolumeClean ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
// // Unlock the volume if it is removable. //
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); } }
// // If the volume is already opened by someone then we need to check // the share access //
if (Vcb->DirectAccessOpenCount > 0) {
if (!NT_SUCCESS(Status = IoCheckShareAccess( *DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess, TRUE ))) {
try_return( NOTHING ); }
} else {
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess ); }
UnwindShareAccess = TRUE;
// // Set up the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserVolumeOpen, Vcb, UnwindCcb = FatCreateCcb( IrpContext ));
FileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
Vcb->DirectAccessOpenCount += 1; Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } UnwindCounts = TRUE; FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
// // At this point the open will succeed, so check if the user is getting explicit access // to the device. If not, we will note this so we can deny modifying FSCTL to it. //
IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); Status = FatExplicitDeviceAccessGranted( IrpContext, Vcb->Vpb->RealDevice, IrpSp->Parameters.Create.SecurityContext->AccessState, (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? UserMode : IrpContext->OriginatingIrp->RequestorMode ));
if (NT_SUCCESS( Status )) {
SetFlag( UnwindCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); }
// // And set our status to success //
Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED;
try_exit: NOTHING; } _SEH2_FINALLY {
DebugUnwind( FatOpenVolume );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status)) {
if (UnwindCounts) { Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } } if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Vcb->ShareAccess ); } if (UnwindVolumeLock) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; } }
DebugTrace(-1, Dbg, "FatOpenVolume -> Iosb.Status = %08lx\n", Status); } _SEH2_END;
Iosb.Status = Status; return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenRootDcb ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition )
/*++
Routine Description:
This routine opens the root dcb for the volume
Arguments:
FileObject - Supplies the File object
Vcb - Supplies the Vcb denoting the volume whose dcb is being opened.
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
CreateDisposition - Supplies the create disposition for this operation
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
Arguments:
--*/
{ PDCB RootDcb; IO_STATUS_BLOCK Iosb = {0};
// // The following variables are for abnormal termination //
BOOLEAN UnwindShareAccess = FALSE; PCCB UnwindCcb = NULL; BOOLEAN UnwindCounts = FALSE; BOOLEAN RootDcbAcquired = FALSE;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0);
// // Locate the root dcb //
RootDcb = Vcb->RootDcb;
// // Get the Dcb exlcusive. This is important as cleanup does not // acquire the Vcb. //
(VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb ); RootDcbAcquired = TRUE;
_SEH2_TRY {
// // Check the create disposition and desired access //
if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
if (!FatCheckFileAccess( IrpContext, RootDcb->DirentFatFlags, DesiredAccess)) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
// // If the Root dcb is already opened by someone then we need // to check the share access //
if (RootDcb->OpenCount > 0) {
if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, ShareAccess, FileObject, &RootDcb->ShareAccess, TRUE ))) {
try_return( Iosb ); }
} else {
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &RootDcb->ShareAccess ); }
UnwindShareAccess = TRUE;
// // Setup the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserDirectoryOpen, RootDcb, UnwindCcb = FatCreateCcb( IrpContext ));
RootDcb->UncleanCount += 1; RootDcb->OpenCount += 1; Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } UnwindCounts = TRUE;
// // And set our status to success //
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED;
try_exit: NOTHING; } _SEH2_FINALLY {
DebugUnwind( FatOpenRootDcb );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination()) {
if (UnwindCounts) { RootDcb->UncleanCount -= 1; RootDcb->OpenCount -= 1; Vcb->OpenFileCount -= 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } } if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); } }
if (RootDcbAcquired) {
FatReleaseFcb( IrpContext, RootDcb ); }
DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingDcb ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PDCB Dcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN FileNameOpenedDos, _Out_ PBOOLEAN OplockPostIrp )
/*++
Routine Description:
This routine opens the specified existing dcb
Arguments:
FileObject - Supplies the File object
Vcb - Supplies the Vcb denoting the volume containing the dcb
Dcb - Supplies the already existing dcb
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
CreateDisposition - Supplies the create disposition for this operation
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
DeleteOnClose - The caller wants the file gone when the handle is closed
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0}; PBCB DirentBcb = NULL; PDIRENT Dirent;
// // The following variables are for abnormal termination //
BOOLEAN UnwindShareAccess = FALSE; PCCB UnwindCcb = NULL; BOOLEAN DcbAcquired = FALSE;
#if (NTDDI_VERSION <= NTDDI_WIN7) UNREFERENCED_PARAMETER( OpenRequiringOplock );#endif
UNREFERENCED_PARAMETER( IrpSp );
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenExistingDcb...\n", 0);
// // Get the Dcb exlcusive. This is important as cleanup does not // acquire the Vcb. //
(VOID)FatAcquireExclusiveFcb( IrpContext, Dcb ); DcbAcquired = TRUE;
_SEH2_TRY {
*OplockPostIrp = FALSE;
// // Before spending any noticeable effort, see if we have the odd case // of someone trying to delete-on-close the root dcb. This will only // happen if we're hit with a null-filename relative open via the root. //
if (NodeType(Dcb) == FAT_NTC_ROOT_DCB && DeleteOnClose) {
Iosb.Status = STATUS_CANNOT_DELETE; try_return( Iosb ); }
#if (NTDDI_VERSION >= NTDDI_WIN8)
// // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, NULL, NULL, NULL );
if (Iosb.Status != STATUS_SUCCESS) {
try_return( NOTHING ); }
#endif // // If the caller has no Ea knowledge, we immediately check for // Need Ea's on the file. We don't need to check for ea's on the // root directory, because it never has any. Fat32 doesn't have // any, either. //
if (NoEaKnowledge && NodeType(Dcb) != FAT_NTC_ROOT_DCB && !FatIsFat32(Vcb)) {
ULONG NeedEaCount;
// // Get the dirent for the file and then check that the need // ea count is 0. //
FatGetDirentFromFcbOrDcb( IrpContext, Dcb, FALSE, &Dirent, &DirentBcb );
FatGetNeedEaCount( IrpContext, Vcb, Dirent, &NeedEaCount );
FatUnpinBcb( IrpContext, DirentBcb );
if (NeedEaCount != 0) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); } }
// // Check the create disposition and desired access //
if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) {
Iosb.Status = STATUS_OBJECT_NAME_COLLISION; try_return( Iosb ); }
if (!FatCheckFileAccess( IrpContext, Dcb->DirentFatFlags, DesiredAccess)) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
// // If the dcb is already opened by someone then we need // to check the share access //
if (Dcb->OpenCount > 0) {
if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext, FileObject, Dcb, DesiredAccess, ShareAccess ))) {#if (NTDDI_VERSION >= NTDDI_WIN8)
NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
// // If we got a sharing violation try to break outstanding handle // oplocks and retry the sharing check. If the caller specified // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock; // we just return the sharing violation. //
if ((Iosb.Status == STATUS_SHARING_VIOLATION) && !FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) {
OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Dcb), IrpContext->OriginatingIrp, 0, IrpContext, FatOplockComplete, FatPrePostIrp );
// // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP // has been posted and we need to stop working. //
if (OplockBreakStatus == STATUS_PENDING) {
Iosb.Status = STATUS_PENDING; *OplockPostIrp = TRUE; try_return( NOTHING );
// // If FsRtlOplockBreakH returned an error we want to return that now. //
} else if (!NT_SUCCESS( OplockBreakStatus )) {
Iosb.Status = OplockBreakStatus; try_return( Iosb );
// // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating // that there is no oplock to be broken. The sharing violation is // returned in that case. //
} else {
NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
try_return( Iosb ); }
// // The initial sharing check failed with something other than sharing // violation (which should never happen, but let's be future-proof), // or we *did* get a sharing violation and the caller specified // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over. //
} else {
try_return( Iosb ); }#else
try_return( Iosb );#endif } }
#if (NTDDI_VERSION >= NTDDI_WIN8)
// // Now check that we can continue based on the oplock state of the // directory. If there are no open handles yet we don't need to do // this check; oplocks can only exist when there are handles. //
if (Dcb->UncleanCount != 0) {
Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Dcb), IrpContext->OriginatingIrp, IrpContext, FatOplockComplete, FatPrePostIrp ); }
// // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. //
if (Iosb.Status == STATUS_PENDING) {
*OplockPostIrp = TRUE; try_return( NOTHING ); }
// // If the caller wants atomic create-with-oplock semantics, tell // the oplock package. We haven't incremented the Fcb's UncleanCount // for this create yet, so add that in on the call. //
if (OpenRequiringOplock && (Iosb.Status == STATUS_SUCCESS)) {
Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Dcb), IrpContext->OriginatingIrp, (Dcb->UncleanCount + 1) ); }
// // If we've encountered a failure we need to leave. FsRtlCheckOplock // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED // on the create call. That's an NT_SUCCESS code, so we need to keep // going. //
if ((Iosb.Status != STATUS_SUCCESS) && (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
try_return( NOTHING ); }
#endif
// // Now that we're done with the oplock work update the share counts. // If the Dcb isn't yet opened we just set the share access rather than // update it. //
if (Dcb->OpenCount > 0) {
IoUpdateShareAccess( FileObject, &Dcb->ShareAccess );
} else {
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &Dcb->ShareAccess ); }
UnwindShareAccess = TRUE;
// // Setup the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserDirectoryOpen, Dcb, UnwindCcb = FatCreateCcb( IrpContext ));
Dcb->UncleanCount += 1; Dcb->OpenCount += 1; Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
// // Mark the delete on close bit if the caller asked for that. //
{ PCCB Ccb = (PCCB)FileObject->FsContext2;
if (DeleteOnClose) {
SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); } if (FileNameOpenedDos) {
SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); }
}
// // In case this was set, clear it now. //
ClearFlag(Dcb->FcbState, FCB_STATE_DELAY_CLOSE);
// // And set our status to success //
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED;
try_exit: NOTHING; } _SEH2_FINALLY {
DebugUnwind( FatOpenExistingDcb );
// // Unpin the Dirent Bcb if pinned. //
FatUnpinBcb( IrpContext, DirentBcb );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination()) {
if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); } }
if (DcbAcquired) {
FatReleaseFcb( IrpContext, Dcb ); }
DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingFcb ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PFCB Fcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN FileNameOpenedDos, _Out_ PBOOLEAN OplockPostIrp )
/*++
Routine Description:
This routine opens the specified existing fcb
Arguments:
FileObject - Supplies the File object
Vcb - Supplies the Vcb denoting the volume containing the Fcb
Fcb - Supplies the already existing fcb
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
AllocationSize - Supplies the initial allocation if the file is being superseded or overwritten
EaBuffer - Supplies the Ea set if the file is being superseded or overwritten
EaLength - Supplies the size, in byte, of the EaBuffer
FileAttributes - Supplies file attributes to use if the file is being superseded or overwritten
CreateDisposition - Supplies the create disposition for this operation
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
DeleteOnClose - The caller wants the file gone when the handle is closed
OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
FileNameOpenedDos - The caller hit the short side of the name pair finding this file
OplockPostIrp - Address to store boolean indicating if the Irp needs to be posted to the Fsp.
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0};
PBCB DirentBcb = NULL; PDIRENT Dirent;
ACCESS_MASK AddedAccess = 0;
// // The following variables are for abnormal termination //
BOOLEAN UnwindShareAccess = FALSE; PCCB UnwindCcb = NULL; BOOLEAN DecrementFcbOpenCount = FALSE; BOOLEAN FcbAcquired = FALSE;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0);
// // Get the Fcb exlcusive. This is important as cleanup does not // acquire the Vcb. //
(VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); FcbAcquired = TRUE;
_SEH2_TRY {
*OplockPostIrp = FALSE;
#if (NTDDI_VERSION >= NTDDI_WIN7)
// // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, NULL, NULL, NULL );
if (Iosb.Status != STATUS_SUCCESS) {
try_return( NOTHING ); }#endif
// // Take special action if there is a current batch oplock or // batch oplock break in process on the Fcb. //
if (FsRtlCurrentBatchOplock( FatGetFcbOplock(Fcb) )) {
// // We remember if a batch oplock break is underway for the // case where the sharing check fails. //
Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;
Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, IrpContext, FatOplockComplete, FatPrePostIrp );
// // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. //
if (Iosb.Status == STATUS_PENDING) {
*OplockPostIrp = TRUE; try_return( NOTHING ); } }
// // Check if the user wanted to create the file, also special case // the supersede and overwrite options. Those add additional, // possibly only implied, desired accesses to the caller, which // we must be careful to pull back off if the caller did not actually // request them. // // In other words, check against the implied access, but do not modify // share access as a result. //
if (CreateDisposition == FILE_CREATE) {
Iosb.Status = STATUS_OBJECT_NAME_COLLISION; try_return( Iosb );
} else if (CreateDisposition == FILE_SUPERSEDE) {
SetFlag( AddedAccess, DELETE & ~(*DesiredAccess) );
*DesiredAccess |= DELETE;
} else if ((CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) {
SetFlag( AddedAccess, (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) );
*DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; }
// // Check the desired access //
if (!FatCheckFileAccess( IrpContext, Fcb->DirentFatFlags, DesiredAccess )) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
// // Check for trying to delete a read only file. //
if (DeleteOnClose && FlagOn( Fcb->DirentFatFlags, FAT_DIRENT_ATTR_READ_ONLY )) {
Iosb.Status = STATUS_CANNOT_DELETE; try_return( Iosb ); }
// // If we are asked to do an overwrite or supersede operation then // deny access for files where the file attributes for system and // hidden do not match //
if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) {
BOOLEAN Hidden; BOOLEAN System;
Hidden = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_HIDDEN ); System = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_SYSTEM );
if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) {
DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
// // If this media is write protected, don't even try the create. //
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
// // Set the real device for the pop-up info, and set the verify // bit in the device object, so that we will force a verify // in case the user put the correct media back in. //
IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, Vcb->Vpb->RealDevice );
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); } }
// // Check if the Fcb has the proper share access. This routine will also // check for writable user secions if the user did not allow write sharing. //
if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext, FileObject, Fcb, DesiredAccess, ShareAccess ))) {
#if (NTDDI_VERSION >= NTDDI_WIN7)
NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
// // If we got a sharing violation try to break outstanding handle // oplocks and retry the sharing check. If the caller specified // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock; // we just return the sharing violation. //
if ((Iosb.Status == STATUS_SHARING_VIOLATION) && !FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) {
OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, 0, IrpContext, FatOplockComplete, FatPrePostIrp );
// // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP // has been posted and we need to stop working. //
if (OplockBreakStatus == STATUS_PENDING) {
Iosb.Status = STATUS_PENDING; *OplockPostIrp = TRUE; try_return( NOTHING );
// // If FsRtlOplockBreakH returned an error we want to return that now. //
} else if (!NT_SUCCESS( OplockBreakStatus )) {
Iosb.Status = OplockBreakStatus; try_return( Iosb );
// // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating // that there is no oplock to be broken. The sharing violation is // returned in that case. //
} else {
NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
try_return( Iosb ); }
// // The initial sharing check failed with something other than sharing // violation (which should never happen, but let's be future-proof), // or we *did* get a sharing violation and the caller specified // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over. //
} else {
try_return( Iosb ); }
#else
try_return( Iosb );
#endif }
// // Now check that we can continue based on the oplock state of the // file. If there are no open handles yet we don't need to do this // check; oplocks can only exist when there are handles. // // It is important that we modified the DesiredAccess in place so // that the Oplock check proceeds against any added access we had // to give the caller. //
if (Fcb->UncleanCount != 0) {
Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, IrpContext, FatOplockComplete, FatPrePostIrp ); }
// // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. //
if (Iosb.Status == STATUS_PENDING) {
*OplockPostIrp = TRUE; try_return( NOTHING ); }
// // If the caller wants atomic create-with-oplock semantics, tell // the oplock package. We haven't incremented the Fcb's UncleanCount // for this create yet, so add that in on the call. //
if (OpenRequiringOplock && (Iosb.Status == STATUS_SUCCESS)) {
Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, (Fcb->UncleanCount + 1) ); }
// // If we've encountered a failure we need to leave. FsRtlCheckOplock // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED // on the create call. That's an NT_SUCCESS code, so we need to keep // going. //
if ((Iosb.Status != STATUS_SUCCESS) && (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
try_return( NOTHING ); }
// // Set the flag indicating if Fast I/O is possible //
Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
// // If the user wants write access access to the file make sure there // is not a process mapping this file as an image. Any attempt to // delete the file will be stopped in fileinfo.c // // If the user wants to delete on close, we must check at this // point though. //
if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {
Fcb->OpenCount += 1; DecrementFcbOpenCount = TRUE;
if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite )) {
Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; try_return( Iosb ); } }
// // If this is a non-cached open on a non-paging file, and there // are no open cached handles, but there is a still a data // section, attempt a flush and purge operation to avoid cache // coherency overhead later. We ignore any I/O errors from // the flush. // // We set the CREATE_IN_PROGRESS flag to prevent the Fcb from // going away out from underneath us. //
if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) && (Fcb->UncleanCount == Fcb->NonCachedUncleanCount) && (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) && !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, NULL );
// // Grab and release PagingIo to serialize ourselves with the lazy writer. // This will work to ensure that all IO has completed on the cached // data and we will succesfully tear away the cache section. //
ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE); ExReleaseResourceLite( Fcb->Header.PagingIoResource );
CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE );
ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); }
// // Check if the user only wanted to open the file //
if ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OPEN_IF)) {
DebugTrace(0, Dbg, "Doing open operation\n", 0);
// // If the caller has no Ea knowledge, we immediately check for // Need Ea's on the file. //
if (NoEaKnowledge && !FatIsFat32(Vcb)) {
ULONG NeedEaCount;
// // Get the dirent for the file and then check that the need // ea count is 0. //
FatGetDirentFromFcbOrDcb( IrpContext, Fcb, FALSE, &Dirent, &DirentBcb );
FatGetNeedEaCount( IrpContext, Vcb, Dirent, &NeedEaCount );
FatUnpinBcb( IrpContext, DirentBcb );
if (NeedEaCount != 0) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); } }
// // Everything checks out okay, so setup the context and // section object pointers. //
FatSetFileObject( FileObject, UserFileOpen, Fcb, UnwindCcb = FatCreateCcb( IrpContext ));
FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
// // Fill in the information field, the status field is already // set. //
Iosb.Information = FILE_OPENED;
try_return( Iosb ); }
// // Check if we are to supersede/overwrite the file, we can wait for // any I/O at this point //
if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) {
NTSTATUS OldStatus;
DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
// // We remember the previous status code because it may contain // information about the oplock status. //
OldStatus = Iosb.Status;
// // Determine the granted access for this operation now. //
if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
try_return( Iosb ); }
// // And overwrite the file. //
Iosb = FatSupersedeOrOverwriteFile( IrpContext, FileObject, Fcb, AllocationSize, EaBuffer, EaLength, FileAttributes, CreateDisposition, NoEaKnowledge );
if (Iosb.Status == STATUS_SUCCESS) {
Iosb.Status = OldStatus; }
try_return( Iosb ); }
// // If we ever get here then the I/O system gave us some bad input //
#ifdef _MSC_VER#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )#endif FatBugCheck( CreateDisposition, 0, 0 );
try_exit: NOTHING;
// // Update the share access and counts if successful //
if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) {
// // Now, we may have added some access bits above to indicate the access // this caller would conflict with (as opposed to what they get) in order // to perform the overwrite/supersede. We need to make a call to that will // recalculate the bits in the fileobject to reflect the real access they // will get. //
if (AddedAccess) {
NTSTATUS Status;
ClearFlag( *DesiredAccess, AddedAccess );
#ifdef _MSC_VER#pragma prefast( suppress:28931, "it needs to be there for debug assert" );#endif Status = IoCheckShareAccess( *DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess, TRUE );
// // It must be the case that we are really asking for less access, so // any conflict must have been detected before this point. //
NT_ASSERT( Status == STATUS_SUCCESS );
} else {
IoUpdateShareAccess( FileObject, &Fcb->ShareAccess ); }
UnwindShareAccess = TRUE;
// // In case this was set, clear it now. //
ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
Fcb->UncleanCount += 1; Fcb->OpenCount += 1; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { Fcb->NonCachedUncleanCount += 1; } Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
{ PCCB Ccb;
Ccb = (PCCB)FileObject->FsContext2;
// // Mark the DeleteOnClose bit if the operation was successful. //
if ( DeleteOnClose ) {
SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); }
// // Mark the OpenedByShortName bit if the operation was successful. //
if ( FileNameOpenedDos ) {
SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); }
// // Mark the ManageVolumeAccess bit if the privilege is held. //
if (FatCheckManageVolumeAccess( IrpContext, IrpSp->Parameters.Create.SecurityContext->AccessState, (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? UserMode : IrpContext->OriginatingIrp->RequestorMode ))) {
SetFlag( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); } }
}
} _SEH2_FINALLY {
DebugUnwind( FatOpenExistingFcb );
// // Unpin the Dirent Bcb if pinned. //
FatUnpinBcb( IrpContext, DirentBcb );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination()) {
if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); } }
if (DecrementFcbOpenCount) {
Fcb->OpenCount -= 1;
if (Fcb->OpenCount == 0) { if (ARGUMENT_PRESENT( FileObject )) { FileObject->SectionObjectPointer = NULL; } FatDeleteFcb( IrpContext, &Fcb ); FcbAcquired = FALSE; } }
if (FcbAcquired) {
FatReleaseFcb( IrpContext, Fcb ); }
DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenTargetDirectory ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PDCB Dcb, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ BOOLEAN DoesNameExist, _In_ BOOLEAN FileNameOpenedDos )
/*++
Routine Description:
This routine opens the target directory and replaces the name in the file object with the remaining name.
Arguments:
FileObject - Supplies the File object
Dcb - Supplies an already existing dcb that we are going to open
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
DoesNameExist - Indicates if the file name already exists in the target directory.
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0};
// // The following variables are for abnormal termination //
BOOLEAN UnwindShareAccess = FALSE; PCCB UnwindCcb = NULL; BOOLEAN DcbAcquired = FALSE;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0);
// // Get the Dcb exlcusive. This is important as cleanup does not // acquire the Vcb. //
(VOID)FatAcquireExclusiveFcb( IrpContext, Dcb ); DcbAcquired = TRUE;
_SEH2_TRY {
ULONG i;
// // If the Dcb is already opened by someone then we need // to check the share access //
if (Dcb->OpenCount > 0) {
if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, ShareAccess, FileObject, &Dcb->ShareAccess, TRUE ))) {
try_return( Iosb ); }
} else {
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &Dcb->ShareAccess ); }
UnwindShareAccess = TRUE;
// // Setup the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserDirectoryOpen, Dcb, UnwindCcb = FatCreateCcb( IrpContext ));
Dcb->UncleanCount += 1; Dcb->OpenCount += 1; Dcb->Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Dcb->Vcb->ReadOnlyCount += 1; }
// // Update the name in the file object, by definition the remaining // part must be shorter than the original file name so we'll just // overwrite the file name. //
i = FileObject->FileName.Length/sizeof(WCHAR) - 1;
// // Get rid of a trailing backslash //
if (FileObject->FileName.Buffer[i] == L'\\') {
NT_ASSERT(i != 0);
FileObject->FileName.Length -= sizeof(WCHAR); i -= 1; }
// // Find the first non-backslash character. i will be its index. //
while (TRUE) {
if (FileObject->FileName.Buffer[i] == L'\\') {
i += 1; break; }
if (i == 0) { break; }
i--; }
if (i) {
FileObject->FileName.Length -= (USHORT)(i * sizeof(WCHAR));
RtlMoveMemory( &FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[i], FileObject->FileName.Length ); }
// // And set our status to success //
Iosb.Status = STATUS_SUCCESS; Iosb.Information = (DoesNameExist ? FILE_EXISTS : FILE_DOES_NOT_EXIST);
if ( ( NT_SUCCESS(Iosb.Status) ) && ( DoesNameExist ) ) { PCCB Ccb;
Ccb = (PCCB)FileObject->FsContext2;
// // Mark the OpenedByShortName bit if the operation was successful. //
if ( FileNameOpenedDos ) {
SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); } }
try_exit: NOTHING; } _SEH2_FINALLY {
DebugUnwind( FatOpenTargetDirectory );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination()) {
if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); } }
if (DcbAcquired) {
FatReleaseFcb( IrpContext, Dcb ); }
DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//_Success_(return.Status == STATUS_SUCCESS)_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCK#ifdef _MSC_VER#pragma warning(suppress:6101) // bug in PREFast means the _Success_ annotation is not correctly applied#endifFatOpenExistingDirectory ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Outptr_result_maybenull_ PDCB *Dcb, _In_ PDCB ParentDcb, _In_ PDIRENT Dirent, _In_ ULONG LfnByteOffset, _In_ ULONG DirentByteOffset, _In_ PUNICODE_STRING Lfn, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN FileNameOpenedDos, _In_ BOOLEAN OpenRequiringOplock )
/*++
Routine Description:
This routine opens the specified directory. The directory has not previously been opened.
Arguments:
FileObject - Supplies the File object
Vcb - Supplies the Vcb denoting the volume containing the dcb
Dcb - Returns the newly-created DCB for the file.
ParentDcb - Supplies the parent directory containing the subdirectory to be opened
DirectoryName - Supplies the file name of the directory being opened.
Dirent - Supplies the dirent for the directory being opened
LfnByteOffset - Tells where the Lfn begins. If there is no Lfn this field is the same as DirentByteOffset.
DirentByteOffset - Supplies the Vbo of the dirent within its parent directory
Lfn - May supply a long name for the file.
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
CreateDisposition - Supplies the create disposition for this operation
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
DeleteOnClose - The caller wants the file gone when the handle is closed
OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0};
// // The following variables are for abnormal termination //
PDCB UnwindDcb = NULL; PCCB UnwindCcb = NULL;
BOOLEAN CountsIncremented = FALSE;
UNREFERENCED_PARAMETER( DeleteOnClose );#if (NTDDI_VERSION <= NTDDI_WIN7) UNREFERENCED_PARAMETER( OpenRequiringOplock );#endif UNREFERENCED_PARAMETER( IrpSp );
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenExistingDirectory...\n", 0);
_SEH2_TRY {
// // If the caller has no Ea knowledge, we immediately check for // Need Ea's on the file. //
if (NoEaKnowledge && !FatIsFat32(Vcb)) {
ULONG NeedEaCount;
FatGetNeedEaCount( IrpContext, Vcb, Dirent, &NeedEaCount );
if (NeedEaCount != 0) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); } }
// // Check the create disposition and desired access //
if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) {
Iosb.Status = STATUS_OBJECT_NAME_COLLISION; try_return( Iosb ); }
if (!FatCheckFileAccess( IrpContext, Dirent->Attributes, DesiredAccess)) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
// // Create a new dcb for the directory //
*Dcb = UnwindDcb = FatCreateDcb( IrpContext, Vcb, ParentDcb, LfnByteOffset, DirentByteOffset, Dirent, Lfn );
#if (NTDDI_VERSION >= NTDDI_WIN8)
// // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Dcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, NULL, NULL, NULL );
// // If the caller wants atomic create-with-oplock semantics, tell // the oplock package. We haven't incremented the Fcb's UncleanCount // for this create yet, so add that in on the call. //
if (OpenRequiringOplock && (Iosb.Status == STATUS_SUCCESS)) {
Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(*Dcb), IrpContext->OriginatingIrp, ((*Dcb)->UncleanCount + 1) ); }
// // Get out if either of the above calls failed. Raise to trigger // cleanup of the new Dcb. //
if (Iosb.Status != STATUS_SUCCESS) {
NT_ASSERT( Iosb.Status != STATUS_PENDING );
FatRaiseStatus( IrpContext, Iosb.Status ); }#endif
// // Setup our share access //
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &(*Dcb)->ShareAccess );
// // Setup the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserDirectoryOpen, (*Dcb), UnwindCcb = FatCreateCcb( IrpContext ));
(*Dcb)->UncleanCount += 1; (*Dcb)->OpenCount += 1; Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
CountsIncremented = TRUE;
// // And set our status to success //
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED;
if ( NT_SUCCESS(Iosb.Status) ) { PCCB Ccb;
Ccb = (PCCB)FileObject->FsContext2;
// // Mark the OpenedByShortName bit if the operation was successful. //
if ( FileNameOpenedDos ) {
SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); } }
try_exit: NOTHING; } _SEH2_FINALLY {
DebugUnwind( FatOpenExistingDirectory );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination()) {
if (CountsIncremented) {
(*Dcb)->UncleanCount -= 1; (*Dcb)->OpenCount -= 1; Vcb->OpenFileCount -= 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } }
if (UnwindDcb != NULL) { if (ARGUMENT_PRESENT( FileObject )) { FileObject->SectionObjectPointer = NULL; } FatDeleteFcb( IrpContext, &UnwindDcb ); *Dcb = NULL; } if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } }
DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatOpenExistingFile ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Outptr_result_maybenull_ PFCB *Fcb, _In_ PDCB ParentDcb, _In_ PDIRENT Dirent, _In_ ULONG LfnByteOffset, _In_ ULONG DirentByteOffset, _In_ PUNICODE_STRING Lfn, _In_ PUNICODE_STRING OrigLfn, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ ULONG CreateDisposition, _In_ BOOLEAN IsPagingFile, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN FileNameOpenedDos )
/*++
Routine Description:
This routine opens the specified file. The file has not previously been opened.
Arguments:
FileObject - Supplies the File object
Vcb - Supplies the Vcb denoting the volume containing the file
Fcb - Returns the newly-created FCB for the file.
ParentDcb - Supplies the parent directory containing the file to be opened
Dirent - Supplies the dirent for the file being opened
LfnByteOffset - Tells where the Lfn begins. If there is no Lfn this field is the same as DirentByteOffset.
DirentByteOffset - Supplies the Vbo of the dirent within its parent directory
Lfn - May supply a long name for the file.
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the share access of the caller
AllocationSize - Supplies the initial allocation if the file is being superseded, overwritten, or created.
EaBuffer - Supplies the Ea set if the file is being superseded, overwritten, or created.
EaLength - Supplies the size, in byte, of the EaBuffer
FileAttributes - Supplies file attributes to use if the file is being superseded, overwritten, or created
CreateDisposition - Supplies the create disposition for this operation
IsPagingFile - Indicates if this is the paging file being opened.
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
DeleteOnClose - The caller wants the file gone when the handle is closed
OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
FileNameOpenedDos - The caller opened this file by hitting the 8.3 side of the Lfn/8.3 pair
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0};
ACCESS_MASK AddedAccess = 0;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
// // The following variables are for abnormal termination //
PFCB UnwindFcb = NULL; PCCB UnwindCcb = NULL; BOOLEAN CountsIncremented = FALSE;
#if (NTDDI_VERSION < NTDDI_WIN7) UNREFERENCED_PARAMETER( OpenRequiringOplock );#endif
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenExistingFile...\n", 0);
_SEH2_TRY {
// // Check if the user wanted to create the file or if access is // denied //
if (CreateDisposition == FILE_CREATE) { Iosb.Status = STATUS_OBJECT_NAME_COLLISION; try_return( Iosb );
} else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) {
SetFlag( AddedAccess, DELETE & ~(*DesiredAccess) );
*DesiredAccess |= DELETE;
} else if (((CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) {
SetFlag( AddedAccess, (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) );
*DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; }
if (!FatCheckFileAccess( IrpContext, Dirent->Attributes, DesiredAccess)) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); }
// // Check for trying to delete a read only file. //
if (DeleteOnClose && FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) {
Iosb.Status = STATUS_CANNOT_DELETE; try_return( Iosb ); }
// // IF we are asked to do an overwrite or supersede operation then // deny access for files where the file attributes for system and // hidden do not match //
if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) {
BOOLEAN Hidden; BOOLEAN System;
Hidden = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_HIDDEN ); System = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_SYSTEM );
if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) {
DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
if ( !IsPagingFile ) {
Iosb.Status = STATUS_ACCESS_DENIED; try_return( Iosb ); } }
// // If this media is write protected, don't even try the create. //
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
// // Set the real device for the pop-up info, and set the verify // bit in the device object, so that we will force a verify // in case the user put the correct media back in. //
IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, Vcb->Vpb->RealDevice );
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); } }
// // Create a new Fcb for the file, and set the file size in // the fcb. //
*Fcb = UnwindFcb = FatCreateFcb( IrpContext, Vcb, ParentDcb, LfnByteOffset, DirentByteOffset, Dirent, Lfn, OrigLfn, IsPagingFile, FALSE );
(*Fcb)->Header.ValidDataLength.LowPart = (*Fcb)->Header.FileSize.LowPart;
// // If this is a paging file, lookup the allocation size so that // the Mcb is always valid //
if (IsPagingFile) {
FatLookupFileAllocationSize( IrpContext, *Fcb ); }
#if (NTDDI_VERSION >= NTDDI_WIN7)
// // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Fcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, NULL, NULL, NULL );
// // If the caller wants atomic create-with-oplock semantics, tell // the oplock package. We haven't incremented the Fcb's UncleanCount // for this create yet, so add that in on the call. //
if (OpenRequiringOplock && (Iosb.Status == STATUS_SUCCESS)) {
Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(*Fcb), IrpContext->OriginatingIrp, ((*Fcb)->UncleanCount + 1) ); }
// // Get out if either of the above calls failed. Raise to trigger // cleanup of the new Fcb. //
if (Iosb.Status != STATUS_SUCCESS) {
NT_ASSERT( Iosb.Status != STATUS_PENDING );
FatRaiseStatus( IrpContext, Iosb.Status ); }#endif
// // Now case on whether we are to simply open, supersede, or // overwrite the file. //
switch (CreateDisposition) {
case FILE_OPEN: case FILE_OPEN_IF:
DebugTrace(0, Dbg, "Doing only an open operation\n", 0);
// // If the caller has no Ea knowledge, we immediately check for // Need Ea's on the file. //
if (NoEaKnowledge && !FatIsFat32(Vcb)) {
ULONG NeedEaCount;
FatGetNeedEaCount( IrpContext, Vcb, Dirent, &NeedEaCount );
if (NeedEaCount != 0) {
FatRaiseStatus( IrpContext, STATUS_ACCESS_DENIED ); } }
// // Setup the context and section object pointers. //
FatSetFileObject( FileObject, UserFileOpen, *Fcb, UnwindCcb = FatCreateCcb( IrpContext ));
FileObject->SectionObjectPointer = &(*Fcb)->NonPaged->SectionObjectPointers;
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED; break;
case FILE_SUPERSEDE: case FILE_OVERWRITE: case FILE_OVERWRITE_IF:
DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
// // Determine the granted access for this operation now. //
if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
try_return( Iosb ); }
Iosb = FatSupersedeOrOverwriteFile( IrpContext, FileObject, *Fcb, AllocationSize, EaBuffer, EaLength, FileAttributes, CreateDisposition, NoEaKnowledge ); break;
default:
DebugTrace(0, Dbg, "Illegal Create Disposition\n", 0);
#ifdef _MSC_VER#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )#endif FatBugCheck( CreateDisposition, 0, 0 ); break; }
try_exit: NOTHING;
// // Setup our share access and counts if things were successful. //
if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS( Iosb.Status )) {
// // Remove any virtual access the caller needed to check against, but will // not really receive. Overwrite/supersede is a bit of a special case. //
ClearFlag( *DesiredAccess, AddedAccess );
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &(*Fcb)->ShareAccess );
(*Fcb)->UncleanCount += 1; (*Fcb)->OpenCount += 1; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { (*Fcb)->NonCachedUncleanCount += 1; } Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
CountsIncremented = TRUE; }
{ PCCB Ccb;
Ccb = (PCCB)FileObject->FsContext2;
if ( NT_SUCCESS(Iosb.Status) ) {
// // Mark the DeleteOnClose bit if the operation was successful. //
if ( DeleteOnClose ) {
SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); }
// // Mark the OpenedByShortName bit if the operation was successful. //
if ( FileNameOpenedDos ) {
SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); }
// // Mark the ManageVolumeAccess bit if the privilege is held. //
if (FatCheckManageVolumeAccess( IrpContext, IrpSp->Parameters.Create.SecurityContext->AccessState, (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? UserMode : IrpContext->OriginatingIrp->RequestorMode ))) {
SetFlag( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); }
} }
} _SEH2_FINALLY {
DebugUnwind( FatOpenExistingFile );
// // If this is an abnormal termination then undo our work //
if (_SEH2_AbnormalTermination()) {
if (CountsIncremented) { (*Fcb)->UncleanCount -= 1; (*Fcb)->OpenCount -= 1; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { (*Fcb)->NonCachedUncleanCount -= 1; } Vcb->OpenFileCount -= 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } }
if (UnwindFcb != NULL) { if (ARGUMENT_PRESENT( FileObject )) { FileObject->SectionObjectPointer = NULL; } FatDeleteFcb( IrpContext, &UnwindFcb ); *Fcb = NULL; }
if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } }
DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatCreateNewDirectory ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PDCB ParentDcb, _In_ POEM_STRING OemName, _In_ PUNICODE_STRING UnicodeName, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock )
/*++
Routine Description:
This routine creates a new directory. The directory has already been verified not to exist yet.
Arguments:
FileObject - Supplies the file object for the newly created directory
Vcb - Supplies the Vcb denote the volume to contain the new directory
ParentDcb - Supplies the parent directory containg the newly created directory
OemName - Supplies the Oem name for the newly created directory. It may or maynot be 8.3 complient, but will be upcased.
UnicodeName - Supplies the Unicode name for the newly created directory. It may or maynot be 8.3 complient. This name contains the original case information.
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the shared access of the caller
EaBuffer - Supplies the Ea set for the newly created directory
EaLength - Supplies the length, in bytes, of EaBuffer
FileAttributes - Supplies the file attributes for the newly created directory.
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
DeleteOnClose - The caller wants the file gone when the handle is closed
OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb;
PDCB Dcb = NULL; PCCB Ccb = NULL;
PDIRENT Dirent = NULL; PBCB DirentBcb = NULL; ULONG DirentsNeeded; ULONG DirentByteOffset;
PDIRENT ShortDirent; ULONG ShortDirentByteOffset;
USHORT EaHandle;
BOOLEAN AllLowerComponent; BOOLEAN AllLowerExtension; BOOLEAN CreateLfn;
ULONG BytesInFirstPage = 0; ULONG DirentsInFirstPage = 0; PDIRENT FirstPageDirent = 0;
PBCB SecondPageBcb = NULL; ULONG SecondPageOffset; PDIRENT SecondPageDirent = NULL;
BOOLEAN DirentFromPool = FALSE;
OEM_STRING ShortName; UCHAR ShortNameBuffer[12];
#if (NTDDI_VERSION <= NTDDI_WIN7) UNREFERENCED_PARAMETER( OpenRequiringOplock );#endif
UNREFERENCED_PARAMETER( IrpSp );
PAGED_CODE();
DebugTrace(+1, Dbg, "FatCreateNewDirectory...\n", 0);
ShortName.Length = 0; ShortName.MaximumLength = 12; ShortName.Buffer = (PCHAR)&ShortNameBuffer[0];
EaHandle = 0;
// // We fail this operation if the caller doesn't understand Ea's. //
if (NoEaKnowledge && EaLength > 0) {
Iosb.Status = STATUS_ACCESS_DENIED;
DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status); return Iosb; }
// // DeleteOnClose and ReadOnly are not compatible. //
if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
Iosb.Status = STATUS_CANNOT_DELETE; return Iosb; }
// Now get the names that we will be using. //
FatSelectNames( IrpContext, ParentDcb, OemName, UnicodeName, &ShortName, NULL, &AllLowerComponent, &AllLowerExtension, &CreateLfn );
// // If we are not in Chicago mode, ignore the magic bits. //
if (!FatData.ChicagoMode) {
AllLowerComponent = FALSE; AllLowerExtension = FALSE; CreateLfn = FALSE; }
// // Create/allocate a new dirent //
DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(UnicodeName) + 1 : 1;
DirentByteOffset = FatCreateNewDirent( IrpContext, ParentDcb, DirentsNeeded, FALSE ); _SEH2_TRY {
FatPrepareWriteDirectoryFile( IrpContext, ParentDcb, DirentByteOffset, sizeof(DIRENT), &DirentBcb,#ifndef __REACTOS__ &Dirent,#else (PVOID *)&Dirent,#endif FALSE, TRUE, &Iosb.Status );
NT_ASSERT( NT_SUCCESS( Iosb.Status ) && DirentBcb && Dirent );
// // Deal with the special case of an LFN + Dirent structure crossing // a page boundry. //
if ((DirentByteOffset / PAGE_SIZE) != ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
SecondPageBcb; SecondPageOffset; SecondPageDirent;
SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
BytesInFirstPage = SecondPageOffset - DirentByteOffset;
DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
FatPrepareWriteDirectoryFile( IrpContext, ParentDcb, SecondPageOffset, sizeof(DIRENT), &SecondPageBcb,#ifndef __REACTOS__ &SecondPageDirent,#else (PVOID *)&SecondPageDirent,#endif FALSE, TRUE, &Iosb.Status );
NT_ASSERT( NT_SUCCESS( Iosb.Status ) && SecondPageBcb && SecondPageDirent );
FirstPageDirent = Dirent;
Dirent = FsRtlAllocatePoolWithTag( PagedPool, DirentsNeeded * sizeof(DIRENT), TAG_DIRENT );
DirentFromPool = TRUE; }
// // Bump up Dirent and DirentByteOffset //
ShortDirent = Dirent + DirentsNeeded - 1; ShortDirentByteOffset = DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT);
NT_ASSERT( NT_SUCCESS( Iosb.Status ));
// // Fill in the fields of the dirent. //
FatConstructDirent( IrpContext, ShortDirent, &ShortName, AllLowerComponent, AllLowerExtension, CreateLfn ? UnicodeName : NULL, FileAttributes | FAT_DIRENT_ATTR_DIRECTORY, TRUE, NULL );
// // If the dirent crossed pages, we have to do some real gross stuff. //
if (DirentFromPool) {
RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage );
RtlCopyMemory( SecondPageDirent, Dirent + DirentsInFirstPage, DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage );
ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1; }
// // Create a new dcb for the directory. //
Dcb = FatCreateDcb( IrpContext, Vcb, ParentDcb, DirentByteOffset, ShortDirentByteOffset, ShortDirent, CreateLfn ? UnicodeName : NULL );
#if (NTDDI_VERSION >= NTDDI_WIN8) // // The next three FsRtl calls are for oplock work. We deliberately // do these here so that if either call fails we will be able to // clean up without adding a bunch of code to unwind counts, fix // the file object, etc. //
// // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, NULL, NULL, NULL );
// // If the caller wants atomic create-with-oplock semantics, tell // the oplock package. We haven't incremented the Dcb's UncleanCount // for this create yet, so add that in on the call. //
if (OpenRequiringOplock && (Iosb.Status == STATUS_SUCCESS)) {
Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Dcb), IrpContext->OriginatingIrp, (Dcb->UncleanCount + 1) ); }
// // Break parent directory oplock. Directory oplock breaks are always // advisory, so we will never block/get STATUS_PENDING here. On the // off chance this fails with INSUFFICIENT_RESOURCES we do it here // where we can still tolerate a failure. //
if (Iosb.Status == STATUS_SUCCESS) {
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(ParentDcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_PARENT_OBJECT, NULL, NULL, NULL ); }
// // Get out if any of the oplock calls failed. //
if (Iosb.Status != STATUS_SUCCESS) {
FatRaiseStatus( IrpContext, Iosb.Status ); }#endif
// // Tentatively add the new Ea's, //
if (EaLength > 0) {
// // This returns false if we are trying to create a file // with Need Ea's and don't understand EA's. //
FatCreateEa( IrpContext, Dcb->Vcb, (PUCHAR) EaBuffer, EaLength, &Dcb->ShortName.Name.Oem, &EaHandle ); }
if (!FatIsFat32(Dcb->Vcb)) {
ShortDirent->ExtendedAttributes = EaHandle; }
// // After this point we cannot just simply mark the dirent deleted, // we have to deal with the directory file object. //
// // Make the dirent into a directory. Note that even if this call // raises because of disk space, the diectory file object has been // created. //
FatInitializeDirectoryDirent( IrpContext, Dcb, ShortDirent );
// // Setup the context and section object pointers, and update // our reference counts. Note that this call cannot fail. //
FatSetFileObject( FileObject, UserDirectoryOpen, Dcb, Ccb = FatCreateCcb( IrpContext ) );
// // Initialize the LongFileName if it has not already been set, so that // FatNotify below won't have to. If there are filesystem filters // attached to FAT, the LongFileName could have gotten set if the // filter queried for name information on this file object while // watching the IO needed in FatInitializeDirectoryDirent. //
if (Dcb->FullFileName.Buffer == NULL) {
FatSetFullNameInFcb( IrpContext, Dcb, UnicodeName ); }
// // We call the notify package to report that the // we added a file. //
FatNotifyReportChange( IrpContext, Vcb, Dcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_ADDED );
// // Setup our share access //
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &Dcb->ShareAccess );
// // From this point on, nothing can raise. //
Dcb->UncleanCount += 1; Dcb->OpenCount += 1; Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
if (DeleteOnClose) {
SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); }
// // And set our return status //
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_CREATED;
} _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
// // We'll catch all exceptions and handle them below. //
Iosb.Status = IrpContext->ExceptionStatus; } _SEH2_END;
// // If we failed then undo our work. //
if (!NT_SUCCESS( Iosb.Status )) {
// // We always have to delete the Ccb if we created one. //
if ( Ccb != NULL ) {
FatDeleteCcb( IrpContext, &Ccb ); }
#ifdef _MSC_VER#pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but DCB can be NULL depending on where we raise" )#endif if ( Dcb == NULL) {
NT_ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap, DirentByteOffset / sizeof(DIRENT), DirentsNeeded ) );
RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap, DirentByteOffset / sizeof(DIRENT), DirentsNeeded );
// // Mark the dirents deleted. The codes is complex because of // dealing with an LFN than crosses a page boundry. //
if (Dirent != NULL) {
ULONG i;
// // We failed before creating a directory file object. // We can just mark the dirent deleted and exit. //
for (i = 0; i < DirentsNeeded; i++) {
if (DirentFromPool == FALSE) {
// // Simple case. //
Dirent[i].FileName[0] = FAT_DIRENT_DELETED;
} else {
// // If the second CcPreparePinWrite failed, we have // to stop early. //
if ((SecondPageBcb == NULL) && (i == DirentsInFirstPage)) {
break; }
// // Now conditionally update either page. //
if (i < DirentsInFirstPage) {
FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED;
} else {
SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED; } } } } } }
// // Just drop the Bcbs we have in the parent right now so if we // failed to create the directory and we take the path to rip apart // the partially created child, when we sync-uninit we won't cause // a lazy writer processing the parent to block on us. This would // consume one of the lazy writers, one of which must be running free // in order for us to come back from the sync-uninit. // // Neat, huh? // // Granted, the delete dirent below will be marginally less efficient // since the Bcb may be reclaimed by the time it executes. Life is // tough. //
FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinBcb( IrpContext, SecondPageBcb );
if (DirentFromPool) {
ExFreePool( Dirent ); }
if (!NT_SUCCESS( Iosb.Status )) {
#ifdef _MSC_VER#pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but DCB can be NULL depending on where we raise" )#endif if (Dcb != NULL) {
// // We have created the Dcb. If an error occurred while // creating the Ea's, there will be no directory file // object. //
PFILE_OBJECT DirectoryFileObject;
DirectoryFileObject = Dcb->Specific.Dcb.DirectoryFile;
// // Knock down all of the repinned data so we can begin to destroy // this failed child. We don't care about any raising here - we're // already got a fire going. // // Note that if we failed to do this, the repinned initial pieces // of the child would cause the sync-uninit to block forever. // // A previous spin on this fix had us not make the ./.. creation // "reversible" (bad term) and thus avoid having the Bcb still // outstanding. This wound up causing very bad things to happen // on DMF floppies when we tried to do a similar yank-down in the // create path - we want the purge it does to make sure we never // try to write the bytes out ... it is just a lot cleaner to // unpinrepin. I'll leave the reversible logic in place if it ever // proves useful. //
// // There is a possibility that this may be a generally good idea // for "live" finally clauses - set in ExceptionFilter, clear in // ProcessException. Think about this. //
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE ); FatUnpinRepinnedBcbs( IrpContext ); ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE );
if (Dcb->FirstClusterOfFile != 0) {
_SEH2_TRY {
Dcb->Header.FileSize.LowPart = 0;
CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile, (PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
// // Now zap the allocation backing it. //
FatTruncateFileAllocation( IrpContext, Dcb, 0 );
} _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
// // We catch all exceptions that Fat catches, but don't do // anything with them. // } _SEH2_END; }
if (DirectoryFileObject != NULL) {
FatSyncUninitializeCacheMap( IrpContext, DirectoryFileObject ); }
_SEH2_TRY {
// // Remove the directory entry we made in the parent Dcb. //
FatDeleteDirent( IrpContext, Dcb, NULL, TRUE );
// // FatDeleteDirent can pin and dirty BCBs, so lets unrepin again. //
FatUnpinRepinnedBcbs( IrpContext );
} _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
// // We catch all exceptions that Fat catches, but don't do // anything with them. // } _SEH2_END;
// // Finaly, dereference the directory file object. This will // cause a close Irp to be processed, blowing away the Fcb. //
if (DirectoryFileObject != NULL) {
// // Dereference the file object for this DCB. The DCB will // go away when this file object is closed. //
Dcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject );
} else {
// // This was also a PDK fix. If the stream file exists, this would // be done during the dereference file object operation. Otherwise // we have to remove the Dcb and check if we should remove the parent. // For now we will just leave the parent lying around. //
#ifdef _MSC_VER#pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but FileObject can be NULL depending on where we raise" )#endif if (ARGUMENT_PRESENT( FileObject )) { FileObject->SectionObjectPointer = NULL; } FatDeleteFcb( IrpContext, &Dcb ); } }
DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
FatRaiseStatus( IrpContext, Iosb.Status ); }
UNREFERENCED_PARAMETER( EaBuffer ); UNREFERENCED_PARAMETER( EaLength );
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatCreateNewFile ( _In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _Inout_ PFILE_OBJECT FileObject, _Inout_ PVCB Vcb, _Inout_ PDCB ParentDcb, _In_ POEM_STRING OemName, _In_ PUNICODE_STRING UnicodeName, _In_ PACCESS_MASK DesiredAccess, _In_ USHORT ShareAccess, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ PUNICODE_STRING LfnBuffer, _In_ BOOLEAN IsPagingFile, _In_ BOOLEAN NoEaKnowledge, _In_ BOOLEAN DeleteOnClose, _In_ BOOLEAN OpenRequiringOplock, _In_ BOOLEAN TemporaryFile )
/*++
Routine Description:
This routine creates a new file. The file has already been verified not to exist yet.
Arguments:
FileObject - Supplies the file object for the newly created file
Vcb - Supplies the Vcb denote the volume to contain the new file
ParentDcb - Supplies the parent directory containg the newly created File
OemName - Supplies the Oem name for the newly created file. It may or maynot be 8.3 complient, but will be upcased.
UnicodeName - Supplies the Unicode name for the newly created file. It may or maynot be 8.3 complient. This name contains the original case information.
DesiredAccess - Supplies the desired access of the caller
ShareAccess - Supplies the shared access of the caller
AllocationSize - Supplies the initial allocation size for the file
EaBuffer - Supplies the Ea set for the newly created file
EaLength - Supplies the length, in bytes, of EaBuffer
FileAttributes - Supplies the file attributes for the newly created file
LfnBuffer - A MAX_LFN sized buffer for directory searching
IsPagingFile - Indicates if this is the paging file being created
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
DeleteOnClose - The caller wants the file gone when the handle is closed
OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
TemporaryFile - Signals the lazywriter to not write dirty data unless absolutely has to.
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0};
PFCB Fcb = NULL;
PDIRENT Dirent = NULL; PBCB DirentBcb = NULL; ULONG DirentsNeeded; ULONG DirentByteOffset;
PDIRENT ShortDirent; ULONG ShortDirentByteOffset;
USHORT EaHandle;
BOOLEAN AllLowerComponent; BOOLEAN AllLowerExtension; BOOLEAN CreateLfn;
ULONG BytesInFirstPage = 0; ULONG DirentsInFirstPage = 0; PDIRENT FirstPageDirent = NULL;
PBCB SecondPageBcb = NULL; ULONG SecondPageOffset; PDIRENT SecondPageDirent = NULL;
BOOLEAN DirentFromPool = FALSE;
OEM_STRING ShortName; UCHAR ShortNameBuffer[12];
UNICODE_STRING UniTunneledShortName; WCHAR UniTunneledShortNameBuffer[12]; UNICODE_STRING UniTunneledLongName; WCHAR UniTunneledLongNameBuffer[26]; LARGE_INTEGER TunneledCreationTime; ULONG TunneledDataSize; BOOLEAN HaveTunneledInformation; BOOLEAN UsingTunneledLfn = FALSE;
PUNICODE_STRING RealUnicodeName;
// // The following variables are for abnormal termination //
PDIRENT UnwindDirent = NULL; PFCB UnwindFcb = NULL; BOOLEAN UnwindAllocation = FALSE; BOOLEAN CountsIncremented = FALSE; PCCB UnwindCcb = NULL;
ULONG LocalAbnormalTermination = FALSE;
#if (NTDDI_VERSION < NTDDI_WIN7) UNREFERENCED_PARAMETER( OpenRequiringOplock );#endif
PAGED_CODE();
DebugTrace(+1, Dbg, "FatCreateNewFile...\n", 0);
ShortName.Length = 0; ShortName.MaximumLength = sizeof(ShortNameBuffer); ShortName.Buffer = (PCHAR)&ShortNameBuffer[0];
UniTunneledShortName.Length = 0; UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer); UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0];
UniTunneledLongName.Length = 0; UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer); UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0];
EaHandle = 0;
// // We fail this operation if the caller doesn't understand Ea's. //
if (NoEaKnowledge && EaLength > 0) {
Iosb.Status = STATUS_ACCESS_DENIED;
DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status); return Iosb; }
// // DeleteOnClose and ReadOnly are not compatible. //
if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
Iosb.Status = STATUS_CANNOT_DELETE; return Iosb; }
// // Look in the tunnel cache for names and timestamps to restore //
TunneledDataSize = sizeof(LARGE_INTEGER); HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel, FatDirectoryKey(ParentDcb), UnicodeName, &UniTunneledShortName, &UniTunneledLongName, &TunneledDataSize, &TunneledCreationTime ); NT_ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER));
// // Now get the names that we will be using. //
FatSelectNames( IrpContext, ParentDcb, OemName, UnicodeName, &ShortName, (HaveTunneledInformation? &UniTunneledShortName : NULL), &AllLowerComponent, &AllLowerExtension, &CreateLfn );
// // If we are not in Chicago mode, ignore the magic bits. //
RealUnicodeName = UnicodeName;
if (!FatData.ChicagoMode) {
AllLowerComponent = FALSE; AllLowerExtension = FALSE; CreateLfn = FALSE;
} else {
// // If the Unicode name was legal for a short name and we got // a tunneling hit which had a long name associated which is // avaliable for use, use it. //
if (!CreateLfn && UniTunneledLongName.Length && !FatLfnDirentExists(IrpContext, ParentDcb, &UniTunneledLongName, LfnBuffer)) {
UsingTunneledLfn = TRUE; CreateLfn = TRUE;
RealUnicodeName = &UniTunneledLongName;
// // Short names are always upcase if an LFN exists //
AllLowerComponent = FALSE; AllLowerExtension = FALSE; } }
// // Create/allocate a new dirent //
DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(RealUnicodeName) + 1 : 1;
DirentByteOffset = FatCreateNewDirent( IrpContext, ParentDcb, DirentsNeeded, FALSE );
_SEH2_TRY {
FatPrepareWriteDirectoryFile( IrpContext, ParentDcb, DirentByteOffset, sizeof(DIRENT), &DirentBcb,#ifndef __REACTOS__ &Dirent,#else (PVOID *)&Dirent,#endif FALSE, TRUE, &Iosb.Status );
NT_ASSERT( NT_SUCCESS( Iosb.Status ) );
UnwindDirent = Dirent;
// // Deal with the special case of an LFN + Dirent structure crossing // a page boundry. //
if ((DirentByteOffset / PAGE_SIZE) != ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
SecondPageBcb; SecondPageOffset; SecondPageDirent;
SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
BytesInFirstPage = SecondPageOffset - DirentByteOffset;
DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
FatPrepareWriteDirectoryFile( IrpContext, ParentDcb, SecondPageOffset, sizeof(DIRENT), &SecondPageBcb,#ifndef __REACTOS__ &SecondPageDirent,#else (PVOID *)&SecondPageDirent,#endif FALSE, TRUE, &Iosb.Status );
NT_ASSERT( NT_SUCCESS( Iosb.Status ) );
FirstPageDirent = Dirent;
Dirent = FsRtlAllocatePoolWithTag( PagedPool, DirentsNeeded * sizeof(DIRENT), TAG_DIRENT );
DirentFromPool = TRUE; }
// // Bump up Dirent and DirentByteOffset //
ShortDirent = Dirent + DirentsNeeded - 1; ShortDirentByteOffset = DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT);
NT_ASSERT( NT_SUCCESS( Iosb.Status ));
// // Fill in the fields of the dirent. //
FatConstructDirent( IrpContext, ShortDirent, &ShortName, AllLowerComponent, AllLowerExtension, CreateLfn ? RealUnicodeName : NULL, (FileAttributes | FILE_ATTRIBUTE_ARCHIVE), TRUE, (HaveTunneledInformation ? &TunneledCreationTime : NULL) );
// // If the dirent crossed pages, we have to do some real gross stuff. //
if (DirentFromPool) {
RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage );
RtlCopyMemory( SecondPageDirent, Dirent + DirentsInFirstPage, DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage );
ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1; }
// // Create a new Fcb for the file. Once the Fcb is created we // will not need to unwind dirent because delete dirent will // now do the work. //
Fcb = UnwindFcb = FatCreateFcb( IrpContext, Vcb, ParentDcb, DirentByteOffset, ShortDirentByteOffset, ShortDirent, CreateLfn ? RealUnicodeName : NULL, CreateLfn ? RealUnicodeName : NULL, IsPagingFile, FALSE ); UnwindDirent = NULL;
#if (NTDDI_VERSION >= NTDDI_WIN7) // // The next three FsRtl calls are for oplock work. We deliberately // do these here so that if either call fails we will be able to // clean up without adding a bunch of code to unwind counts, fix // the file object, etc. //
// // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, NULL, NULL, NULL );
// // If the caller wants atomic create-with-oplock semantics, tell // the oplock package. We haven't incremented the Fcb's UncleanCount // for this create yet, so add that in on the call. //
if (OpenRequiringOplock && (Iosb.Status == STATUS_SUCCESS)) {
Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), IrpContext->OriginatingIrp, (Fcb->UncleanCount + 1) ); }#endif
#if (NTDDI_VERSION >= NTDDI_WIN8) // // Break parent directory oplock. Directory oplock breaks are always // advisory, so we will never block/get STATUS_PENDING here. On the // off chance this fails with INSUFFICIENT_RESOURCES we do it here // where we can still tolerate a failure. //
if (Iosb.Status == STATUS_SUCCESS) {
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(ParentDcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_PARENT_OBJECT, NULL, NULL, NULL ); }
// // Get out if any of the oplock calls failed. We raise to provoke // abnormal termination and ensure that the newly-created Fcb gets // deleted. //
if (Iosb.Status != STATUS_SUCCESS) {
FatRaiseStatus( IrpContext, Iosb.Status ); }#endif
// // If this is a temporary file, note it in the FcbState //
if (TemporaryFile) {
SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY ); }
// // Add some initial file allocation //
FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize );
UnwindAllocation = TRUE;
Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
// // Tentatively add the new Ea's //
if ( EaLength > 0 ) {
FatCreateEa( IrpContext, Fcb->Vcb, (PUCHAR) EaBuffer, EaLength, &Fcb->ShortName.Name.Oem, &EaHandle ); }
if (!FatIsFat32(Fcb->Vcb)) {
ShortDirent->ExtendedAttributes = EaHandle; }
// // Initialize the LongFileName right now so that FatNotify // below won't have to. //
if (Fcb->FullFileName.Buffer == NULL) { FatSetFullNameInFcb( IrpContext, Fcb, RealUnicodeName ); }
// // Setup the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserFileOpen, Fcb, UnwindCcb = FatCreateCcb( IrpContext ));
FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
// // We call the notify package to report that the // we added a file. //
FatNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED );
// // Setup our share access //
IoSetShareAccess( *DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess );
Fcb->UncleanCount += 1; Fcb->OpenCount += 1; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { Fcb->NonCachedUncleanCount += 1; } Vcb->OpenFileCount += 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } CountsIncremented = TRUE;
// // And set our return status //
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_CREATED;
if ( NT_SUCCESS(Iosb.Status) ) {
// // Mark the DeleteOnClose bit if the operation was successful. //
if ( DeleteOnClose ) {
SetFlag( UnwindCcb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); }
// // Mark the OpenedByShortName bit if the operation was successful. // If we created an Lfn, we have some sort of generated short name // and thus don't consider ourselves to have opened it - though we // may have had a case mix Lfn "Foo.bar" and generated "FOO.BAR" // // Unless, of course, we wanted to create a short name and hit an // associated Lfn in the tunnel cache //
if ( !CreateLfn && !UsingTunneledLfn ) {
SetFlag( UnwindCcb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); }
// // Mark the ManageVolumeAccess bit if the privilege is held. //
if (FatCheckManageVolumeAccess( IrpContext, IrpSp->Parameters.Create.SecurityContext->AccessState, (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? UserMode : IrpContext->OriginatingIrp->RequestorMode ))) {
SetFlag( UnwindCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); }
}
} _SEH2_FINALLY {
DebugUnwind( FatCreateNewFile );
if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) {
// // Tunneling package grew the buffer from pool //
ExFreePool( UniTunneledLongName.Buffer ); }
// // If this is an abnormal termination then undo our work. // // The extra exception handling here is complex. We've got // two places here where an exception can be thrown again. //
LocalAbnormalTermination = _SEH2_AbnormalTermination();
if (LocalAbnormalTermination) {
if (CountsIncremented) { Fcb->UncleanCount -= 1; Fcb->OpenCount -= 1; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { Fcb->NonCachedUncleanCount -= 1; } Vcb->OpenFileCount -= 1; if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } }
if (UnwindFcb == NULL) {
NT_ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap, DirentByteOffset / sizeof(DIRENT), DirentsNeeded ) );
RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap, DirentByteOffset / sizeof(DIRENT), DirentsNeeded ); }
// // Mark the dirents deleted. The code is complex because of // dealing with an LFN that crosses a page boundary. //
if (UnwindDirent != NULL) {
ULONG i;
for (i = 0; i < DirentsNeeded; i++) {
if (DirentFromPool == FALSE) {
// // Simple case. //
Dirent[i].FileName[0] = FAT_DIRENT_DELETED;
} else {
// // If the second CcPreparePinWrite failed, we have // to stop early. //
if ((SecondPageBcb == NULL) && (i == DirentsInFirstPage)) {
break; }
// // Now conditionally update either page. //
if (i < DirentsInFirstPage) {
FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED;
} else {
SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED; } } } } }
// // We must handle exceptions in the following fragments and plow on with the // unwind of this create operation. This is basically inverted from the // previous state of the code. Since AbnormalTermination() changes when we // enter a new enclosure, we cached the original state ... //
_SEH2_TRY {
if (LocalAbnormalTermination) { if (UnwindAllocation) { FatTruncateFileAllocation( IrpContext, Fcb, 0 ); } }
} _SEH2_FINALLY {
_SEH2_TRY {
if (LocalAbnormalTermination) { if (UnwindFcb != NULL) { FatDeleteDirent( IrpContext, UnwindFcb, NULL, TRUE ); } }
} _SEH2_FINALLY {
if (LocalAbnormalTermination) { if (UnwindFcb != NULL) { if (ARGUMENT_PRESENT( FileObject )) { FileObject->SectionObjectPointer = NULL; } FatDeleteFcb( IrpContext, &UnwindFcb ); } if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } }
// // This is the normal cleanup code. //
FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinBcb( IrpContext, SecondPageBcb );
if (DirentFromPool) {
ExFreePool( Dirent ); }
} _SEH2_END; } _SEH2_END;
DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
//// Internal support routine//
_Requires_lock_held_(_Global_critical_region_)IO_STATUS_BLOCKFatSupersedeOrOverwriteFile ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _Inout_ PFCB Fcb, _In_ ULONG AllocationSize, _In_ PFILE_FULL_EA_INFORMATION EaBuffer, _In_ ULONG EaLength, _In_ USHORT FileAttributes, _In_ ULONG CreateDisposition, _In_ BOOLEAN NoEaKnowledge )
/*++
Routine Description:
This routine performs a file supersede or overwrite operation.
Arguments:
FileObject - Supplies a pointer to the file object
Fcb - Supplies a pointer to the Fcb
AllocationSize - Supplies an initial allocation size
EaBuffer - Supplies the Ea set for the superseded/overwritten file
EaLength - Supplies the length, in bytes, of EaBuffer
FileAttributes - Supplies the supersede/overwrite file attributes
CreateDisposition - Supplies the create disposition for the file It must be either supersede, overwrite, or overwrite if.
NoEaKnowledge - This opener doesn't understand Ea's and we fail this open if the file has NeedEa's.
Return Value:
IO_STATUS_BLOCK - Returns the completion status for the operation
--*/
{ IO_STATUS_BLOCK Iosb = {0};
PDIRENT Dirent; PBCB DirentBcb;
USHORT EaHandle = 0; BOOLEAN EaChange = FALSE; BOOLEAN ReleasePaging = FALSE;
PCCB Ccb;
ULONG NotifyFilter; ULONG HeaderSize = 0; LARGE_INTEGER AllocSize = {0};
// // The following variables are for abnormal termination //
PCCB UnwindCcb = NULL; USHORT UnwindEa = 0;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatSupersedeOrOverwriteFile...\n", 0);
DirentBcb = NULL;
// // We fail this operation if the caller doesn't understand Ea's. //
if (NoEaKnowledge && EaLength > 0) {
Iosb.Status = STATUS_ACCESS_DENIED;
DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status); return Iosb; }
_SEH2_TRY {
// // Before we actually truncate, check to see if the purge // is going to fail. //
if (!MmCanFileBeTruncated( &Fcb->NonPaged->SectionObjectPointers, &FatLargeZero )) {
try_return( Iosb.Status = STATUS_USER_MAPPED_FILE ); }
// // Setup the context and section object pointers, and update // our reference counts //
FatSetFileObject( FileObject, UserFileOpen, Fcb, Ccb = UnwindCcb = FatCreateCcb( IrpContext ));
FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
// // Since this is an supersede/overwrite, purge the section so // that mappers will see zeros. We set the CREATE_IN_PROGRESS flag // to prevent the Fcb from going away out from underneath us. //
SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE );
// // Tentatively add the new Ea's //
if (EaLength > 0) {
FatCreateEa( IrpContext, Fcb->Vcb, (PUCHAR) EaBuffer, EaLength, &Fcb->ShortName.Name.Oem, &EaHandle );
UnwindEa = EaHandle; EaChange = TRUE; }
#if (NTDDI_VERSION >= NTDDI_WIN8) // // Break parent directory oplock. Directory oplock breaks are always // advisory, so we will never block/get STATUS_PENDING here. On the // off chance this fails with INSUFFICIENT_RESOURCES we do it here // where we can still tolerate a failure. //
Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb), IrpContext->OriginatingIrp, OPLOCK_FLAG_PARENT_OBJECT, NULL, NULL, NULL );
if (Iosb.Status != STATUS_SUCCESS) {
FatRaiseStatus( IrpContext, Iosb.Status ); }#endif
// // Now set the new allocation size, we do that by first // zeroing out the current file size. Then we truncate and // allocate up to the new allocation size //
(VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE ); ReleasePaging = TRUE;
Fcb->Header.FileSize.LowPart = 0; Fcb->Header.ValidDataLength.LowPart = 0; Fcb->ValidDataToDisk = 0;
// // Validate that the allocation size will work. //
AllocSize.QuadPart = AllocationSize; if (!FatIsIoRangeValid( Fcb->Vcb, AllocSize, 0 )) {
DebugTrace(-1, Dbg, "Illegal allocation size\n", 0);
FatRaiseStatus( IrpContext, STATUS_DISK_FULL ); }
// // Tell the cache manager the size went to zero // This call is unconditional, because MM always wants to know. //
CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
FatTruncateFileAllocation( IrpContext, Fcb, AllocationSize+HeaderSize );
ExReleaseResourceLite( Fcb->Header.PagingIoResource ); ReleasePaging = FALSE;
FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize+HeaderSize );
Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
// // Modify the attributes and time of the file, by first reading // in the dirent for the file and then updating its attributes // and time fields. Note that for supersede we replace the file // attributes as opposed to adding to them. //
FatGetDirentFromFcbOrDcb( IrpContext, Fcb, FALSE, &Dirent, &DirentBcb ); // // We should get the dirent since this Fcb is in good condition, verified as // we crawled down the prefix tree. // // Update the appropriate dirent fields, and the fcb fields //
Dirent->FileSize = 0;
FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
if (CreateDisposition == FILE_SUPERSEDE) {
Dirent->Attributes = (UCHAR)FileAttributes;
} else {
Dirent->Attributes |= (UCHAR)FileAttributes; }
Fcb->DirentFatFlags = Dirent->Attributes;
KeQuerySystemTime( &Fcb->LastWriteTime );
(VOID)FatNtTimeToFatTime( IrpContext, &Fcb->LastWriteTime, TRUE, &Dirent->LastWriteTime, NULL );
if (FatData.ChicagoMode) {
Dirent->LastAccessDate = Dirent->LastWriteTime.Date; }
NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE;
// // And now delete the previous Ea set if there was one. //
if (!FatIsFat32(Fcb->Vcb) && Dirent->ExtendedAttributes != 0) {
// // **** SDK fix, we won't fail this if there is // an error in the Ea's, we'll just leave // the orphaned Ea's in the file. //
EaChange = TRUE;
_SEH2_TRY {
FatDeleteEa( IrpContext, Fcb->Vcb, Dirent->ExtendedAttributes, &Fcb->ShortName.Name.Oem );
} _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) {
FatResetExceptionState( IrpContext ); } _SEH2_END; }
// // Update the extended attributes handle in the dirent. //
if (EaChange) {
NT_ASSERT(!FatIsFat32(Fcb->Vcb));
Dirent->ExtendedAttributes = EaHandle;
NotifyFilter |= FILE_NOTIFY_CHANGE_EA; }
// // Now update the dirent to the new ea handle and set the bcb dirty // Once we do this we can no longer back out the Ea //
FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE ); UnwindEa = 0;
// // Indicate that the Eas for this file have changed. //
Ccb->EaModificationCount += Fcb->EaModificationCount;
// // Check to see if we need to notify outstanding Irps for full // changes only (i.e., we haven't added, deleted, or renamed the file). //
FatNotifyReportChange( IrpContext, Fcb->Vcb, Fcb, NotifyFilter, FILE_ACTION_MODIFIED );
// // And set our status to success //
Iosb.Status = STATUS_SUCCESS;
if (CreateDisposition == FILE_SUPERSEDE) {
Iosb.Information = FILE_SUPERSEDED;
} else {
Iosb.Information = FILE_OVERWRITTEN; }
try_exit: NOTHING; } _SEH2_FINALLY {
DebugUnwind( FatSupersedeOfOverwriteFile );
if (ReleasePaging) { ExReleaseResourceLite( Fcb->Header.PagingIoResource ); }
// // If this is an abnormal termination then undo our work. //
if (_SEH2_AbnormalTermination()) {
if (UnwindEa != 0) { FatDeleteEa( IrpContext, Fcb->Vcb, UnwindEa, &Fcb->ShortName.Name.Oem ); } if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } }
FatUnpinBcb( IrpContext, DirentBcb );
ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status); } _SEH2_END;
return Iosb;}
VOIDFatSetFullNameInFcb ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB Fcb, _In_ PUNICODE_STRING FinalName )
/*++
Routine Description:
This routine attempts a quick form of the full FatSetFullFileNameInFcb operation.
NOTE: this routine is probably not worth the code duplication involved, and is not equipped to handle the cases where the parent doesn't have the full name set up.
Arguments:
Fcb - Supplies a pointer to the Fcb
FinalName - Supplies the last component of the path to this Fcb's dirent
Return Value:
None. May silently fail.
--*/
{ PAGED_CODE();
UNREFERENCED_PARAMETER( IrpContext );
NT_ASSERT( Fcb->FullFileName.Buffer == NULL );
// // Prefer the ExactCaseLongName of the file for this operation, if set. In // this way we avoid building the fullname with a short filename. Several // operations assume this - the FinalNameLength in particular is the Lfn // (if existant) length, and we use this to crack the fullname in paths // such as the FsRtlNotify caller. // // If the caller specified a particular name and it is short, it is the // case that the long name was set up. //
if (Fcb->ExactCaseLongName.Buffer) {
NT_ASSERT( Fcb->ExactCaseLongName.Length != 0 ); FinalName = &Fcb->ExactCaseLongName; }
// // Special case the root. //
if (NodeType(Fcb->ParentDcb) == FAT_NTC_ROOT_DCB) {
Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + FinalName->Length;
Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool, Fcb->FullFileName.Length, TAG_FILENAME_BUFFER );
Fcb->FullFileName.Buffer[0] = L'\\';
RtlCopyMemory( &Fcb->FullFileName.Buffer[1], &FinalName->Buffer[0], FinalName->Length );
} else {
PUNICODE_STRING Prefix;
Prefix = &Fcb->ParentDcb->FullFileName;
// // It is possible our parent's full filename is not set. Simply fail // this attempt. //
if (Prefix->Buffer == NULL) {
return; }
Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength = Prefix->Length + sizeof(WCHAR) + FinalName->Length;
Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool, Fcb->FullFileName.Length, TAG_FILENAME_BUFFER );
RtlCopyMemory( &Fcb->FullFileName.Buffer[0], &Prefix->Buffer[0], Prefix->Length );
Fcb->FullFileName.Buffer[Prefix->Length / sizeof(WCHAR)] = L'\\';
RtlCopyMemory( &Fcb->FullFileName.Buffer[(Prefix->Length / sizeof(WCHAR)) + 1], &FinalName->Buffer[0], FinalName->Length );
}}
NTSTATUSFatCheckSystemSecurityAccess ( _In_ PIRP_CONTEXT IrpContext ){ PACCESS_STATE AccessState; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
PAGED_CODE();
// // We check if the caller wants ACCESS_SYSTEM_SECURITY access on this // object and fail the request if he does. //
NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL ); AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
// // Check if the remaining privilege includes ACCESS_SYSTEM_SECURITY. //
if (FlagOn( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY )) {
if (!SeSinglePrivilegeCheck( FatSecurityPrivilege, UserMode )) {
return STATUS_ACCESS_DENIED; }
// // Move this privilege from the Remaining access to Granted access. //
ClearFlag( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY ); SetFlag( AccessState->PreviouslyGrantedAccess, ACCESS_SYSTEM_SECURITY ); }
return STATUS_SUCCESS;}
NTSTATUSFatCheckShareAccess ( _In_ PIRP_CONTEXT IrpContext, _In_ PFILE_OBJECT FileObject, _In_ PFCB FcbOrDcb, _In_ PACCESS_MASK DesiredAccess, _In_ ULONG ShareAccess )
/*++
Routine Description:
This routine checks conditions that may result in a sharing violation.
Arguments:
FileObject - Pointer to the file object of the current open request.
FcbOrDcb - Supplies a pointer to the Fcb/Dcb.
DesiredAccess - Desired access of current open request.
ShareAccess - Shared access requested by current open request.
Return Value:
If the accessor has access to the file, STATUS_SUCCESS is returned. Otherwise, STATUS_SHARING_VIOLATION is returned.
--*/
{ PAGED_CODE();
#if (NTDDI_VERSION >= NTDDI_VISTA) // // Do an extra test for writeable user sections if the user did not allow // write sharing - this is neccessary since a section may exist with no handles // open to the file its based against. //
if ((NodeType( FcbOrDcb ) == FAT_NTC_FCB) && !FlagOn( ShareAccess, FILE_SHARE_WRITE ) && FlagOn( *DesiredAccess, FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE | MAXIMUM_ALLOWED ) && MmDoesFileHaveUserWritableReferences( &FcbOrDcb->NonPaged->SectionObjectPointers )) {
return STATUS_SHARING_VIOLATION; }#endif
// // Check if the Fcb has the proper share access. //
return IoCheckShareAccess( *DesiredAccess, ShareAccess, FileObject, &FcbOrDcb->ShareAccess, FALSE );
UNREFERENCED_PARAMETER( IrpContext );}
//// Lifted from NTFS.//
NTSTATUSFatCallSelfCompletionRoutine ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PVOID Contxt )
{ // // Set the event so that our call will wake up. //
KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
UNREFERENCED_PARAMETER( DeviceObject ); UNREFERENCED_PARAMETER( Irp );
// // If we change this return value then FatIoCallSelf needs to reference the // file object. //
return STATUS_MORE_PROCESSING_REQUIRED;}