1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- iobase.c
- Abstract:
- This module implements the base I/O API (open, close, read, write).
- Author:
- Evan Green 25-Apr-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/intrface/disk.h>
- #include "iop.h"
- #include "pagecach.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define IO_RENAME_ATTEMPTS_MAX 10000
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- IopOpenPagingDevice (
- PDEVICE Device,
- ULONG Access,
- ULONG Flags,
- PPAGING_IO_HANDLE *Handle,
- PULONG IoOffsetAlignment,
- PULONG IoSizeAlignment,
- PULONGLONG IoCapacity
- );
- KSTATUS
- IopClosePagingObject (
- PPAGING_IO_HANDLE Handle
- );
- KSTATUS
- IopCreateAnonymousObject (
- ULONG Access,
- ULONG Flags,
- IO_OBJECT_TYPE TypeOverride,
- PVOID OverrideParameter,
- FILE_PERMISSIONS CreatePermissions,
- PPATH_POINT PathPoint
- );
- KSTATUS
- IopPerformIoOperation (
- PIO_HANDLE Handle,
- PIO_CONTEXT Context
- );
- KSTATUS
- IopPerformPagingIoOperation (
- PPAGING_IO_HANDLE Handle,
- PIO_CONTEXT Context,
- PIRP Irp
- );
- KSTATUS
- IopPerformCharacterDeviceIoOperation (
- PIO_HANDLE Handle,
- PIO_CONTEXT Context
- );
- KSTATUS
- IopPerformDirectoryIoOperation (
- PIO_HANDLE Handle,
- PIO_CONTEXT Context
- );
- KSTATUS
- IopAddRelativeDirectoryEntries (
- PIO_HANDLE Handle,
- PIO_OFFSET Offset,
- PIO_BUFFER IoBuffer,
- UINTN BufferSize,
- PUINTN BytesConsumed
- );
- VOID
- IopFixMountPointDirectoryEntries (
- PIO_HANDLE Handle,
- PIO_BUFFER IoBuffer,
- UINTN BufferSize
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the global I/O statistics.
- //
- IO_GLOBAL_STATISTICS IoGlobalStatistics;
- //
- // Set this boolean to print all open calls.
- //
- BOOL IoDebugPrintOpens;
- //
- // ------------------------------------------------------------------ Functions
- //
- KERNEL_API
- KSTATUS
- IoOpen (
- BOOL FromKernelMode,
- PIO_HANDLE Directory,
- PSTR Path,
- ULONG PathLength,
- ULONG Access,
- ULONG Flags,
- FILE_PERMISSIONS CreatePermissions,
- PIO_HANDLE *Handle
- )
- /*++
- Routine Description:
- This routine opens a file, device, pipe, or other I/O object.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- Directory - Supplies an optional pointer to an open handle to a directory
- for relative paths. Supply NULL to use the current working directory.
- Path - Supplies a pointer to the path to open.
- PathLength - Supplies the length of the path buffer in bytes, including the
- null terminator.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- CreatePermissions - Supplies the permissions to apply for a created file.
- Handle - Supplies a pointer where a pointer to the open I/O handle will be
- returned on success.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- if ((Flags & OPEN_FLAG_SHARED_MEMORY) != 0) {
- Status = IopOpenSharedMemoryObject(Path,
- PathLength,
- Access,
- Flags,
- CreatePermissions,
- Handle);
- } else {
- Status = IopOpen(FromKernelMode,
- Directory,
- Path,
- PathLength,
- Access,
- Flags,
- IoObjectInvalid,
- NULL,
- CreatePermissions,
- Handle);
- }
- if (IoDebugPrintOpens != FALSE) {
- RtlDebugPrint("Open %s: %x\n", Path, Status);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoOpenDevice (
- PDEVICE Device,
- ULONG Access,
- ULONG Flags,
- PIO_HANDLE *Handle,
- PULONG IoOffsetAlignment,
- PULONG IoSizeAlignment,
- PULONGLONG IoCapacity
- )
- /*++
- Routine Description:
- This routine opens a device. If the given device is the device meant to
- hold the page file, this routine does not prepare the returned I/O handle
- for paging operations.
- Arguments:
- Device - Supplies a pointer to a device to open.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- Handle - Supplies a pointer that receives the open I/O handle.
- IoOffsetAlignment - Supplies a pointer where the alignment requirement in
- bytes will be returned for all I/O offsets.
- IoSizeAlignment - Supplies a pointer where the alignment requirement for
- the size of all transfers (the block size) will be returned for all
- I/O requests.
- IoCapacity - Supplies the device's total size, in bytes.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- PIO_HANDLE IoHandle;
- ULONGLONG LocalFileSize;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- IoHandle = NULL;
- if ((Flags & OPEN_FLAG_PAGING_DEVICE) != 0) {
- Status = IopOpenPagingDevice(Device,
- Access,
- Flags,
- (PPAGING_IO_HANDLE *)&IoHandle,
- IoOffsetAlignment,
- IoSizeAlignment,
- IoCapacity);
- } else {
- //
- // Open the device normally.
- //
- Status = IopOpenDevice(Device, Access, Flags, &IoHandle);
- if (!KSUCCESS(Status)) {
- goto OpenDeviceEnd;
- }
- //
- // Return the requested data.
- //
- FileObject = IoHandle->FileObject;
- READ_INT64_SYNC(&(FileObject->Properties.FileSize), &LocalFileSize);
- if (IoOffsetAlignment != NULL) {
- *IoOffsetAlignment = FileObject->Properties.BlockSize;
- }
- if (IoSizeAlignment != NULL) {
- *IoSizeAlignment = FileObject->Properties.BlockSize;
- }
- if (IoCapacity != NULL) {
- *IoCapacity = LocalFileSize;
- }
- Status = STATUS_SUCCESS;
- }
- OpenDeviceEnd:
- ASSERT((KSUCCESS(Status)) || (IoHandle == NULL));
- *Handle = IoHandle;
- return Status;
- }
- KERNEL_API
- BOOL
- IoIsPagingDevice (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine determines whether or not paging is enabled on the given
- device.
- Arguments:
- Device - Supplies a pointer to a device.
- Return Value:
- Returns TRUE if paging is enabled on the device, or FALSE otherwise.
- --*/
- {
- if ((Device->Flags & DEVICE_FLAG_PAGING_DEVICE) != 0) {
- return TRUE;
- }
- return FALSE;
- }
- KERNEL_API
- KSTATUS
- IoClose (
- PIO_HANDLE IoHandle
- )
- /*++
- Routine Description:
- This routine closes a file or device.
- Arguments:
- IoHandle - Supplies a pointer to the I/O handle returned when the file was
- opened.
- Return Value:
- Status code. Close operations can fail if their associated flushes to
- the file system fail.
- --*/
- {
- KSTATUS Status;
- if (IoHandle == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- switch (IoHandle->HandleType) {
- case IoHandleTypeDefault:
- Status = IoIoHandleReleaseReference(IoHandle);
- break;
- case IoHandleTypePaging:
- Status = IopClosePagingObject((PPAGING_IO_HANDLE)IoHandle);
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_HANDLE;
- break;
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoRead (
- PIO_HANDLE Handle,
- PIO_BUFFER IoBuffer,
- UINTN SizeInBytes,
- ULONG Flags,
- ULONG TimeoutInMilliseconds,
- PUINTN BytesCompleted
- )
- /*++
- Routine Description:
- This routine reads from an I/O object.
- Arguments:
- Handle - Supplies the open I/O handle.
- IoBuffer - Supplies a pointer to an I/O buffer where the read data will be
- returned on success.
- SizeInBytes - Supplies the number of bytes to read.
- Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
- definitions.
- TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
- operation should be waited on before timing out. Use
- WAIT_TIME_INDEFINITE to wait forever on the I/O.
- BytesCompleted - Supplies the a pointer where the number of bytes actually
- read will be returned.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- IO_CONTEXT Context;
- PIO_HANDLE ReadHandle;
- KSTATUS Status;
- //
- // No-allocate code paths should not be calling I/O read. They should use
- // the offset-based read routine.
- //
- ASSERT((Flags & IO_FLAG_NO_ALLOCATE) == 0);
- //
- // The special page file no-allocate read operation is not supported by
- // this routine. An offset must be supplied for said reads.
- //
- if ((Flags & IO_FLAG_NO_ALLOCATE) != 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto ReadEnd;
- }
- //
- // Find the correct I/O handle.
- //
- if (Handle->HandleType == IoHandleTypePaging) {
- ReadHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
- } else {
- ReadHandle = Handle;
- }
- Context.IoBuffer = IoBuffer;
- Context.Offset = IO_OFFSET_NONE;
- Context.SizeInBytes = SizeInBytes;
- Context.BytesCompleted = 0;
- Context.Flags = Flags;
- Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
- Context.Write = FALSE;
- Status = IopPerformIoOperation(ReadHandle, &Context);
- *BytesCompleted = Context.BytesCompleted;
- ReadEnd:
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoWrite (
- PIO_HANDLE Handle,
- PIO_BUFFER IoBuffer,
- UINTN SizeInBytes,
- ULONG Flags,
- ULONG TimeoutInMilliseconds,
- PUINTN BytesCompleted
- )
- /*++
- Routine Description:
- This routine writes to an I/O object.
- Arguments:
- Handle - Supplies the open I/O handle.
- IoBuffer - Supplies a pointer to an I/O buffer containing the data to write.
- SizeInBytes - Supplies the number of bytes to write.
- Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
- definitions.
- TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
- operation should be waited on before timing out. Use
- WAIT_TIME_INDEFINITE to wait forever on the I/O.
- BytesCompleted - Supplies the a pointer where the number of bytes actually
- written will be returned.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- IO_CONTEXT Context;
- KSTATUS Status;
- PIO_HANDLE WriteHandle;
- //
- // No-allocate code paths should not be calling I/O write. They should use
- // the offset-based write routine.
- //
- ASSERT((Flags & IO_FLAG_NO_ALLOCATE) == 0);
- //
- // The special page file no-allocate write operation is not supported by
- // this routine. An offset must be supplied for said writes.
- //
- if ((Flags & IO_FLAG_NO_ALLOCATE) != 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto WriteEnd;
- }
- //
- // Find the correct I/O handle.
- //
- if (Handle->HandleType == IoHandleTypePaging) {
- WriteHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
- } else {
- WriteHandle = Handle;
- }
- Context.IoBuffer = IoBuffer;
- Context.Offset = IO_OFFSET_NONE;
- Context.SizeInBytes = SizeInBytes;
- Context.BytesCompleted = 0;
- Context.Flags = Flags;
- Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
- Context.Write = TRUE;
- Status = IopPerformIoOperation(WriteHandle, &Context);
- *BytesCompleted = Context.BytesCompleted;
- WriteEnd:
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoReadAtOffset (
- PIO_HANDLE Handle,
- PIO_BUFFER IoBuffer,
- IO_OFFSET Offset,
- UINTN SizeInBytes,
- ULONG Flags,
- ULONG TimeoutInMilliseconds,
- PUINTN BytesCompleted,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine reads from an I/O object at a specific offset.
- Arguments:
- Handle - Supplies the open I/O handle.
- IoBuffer - Supplies a pointer to an I/O buffer where the read data will be
- returned on success.
- Offset - Supplies the offset from the beginning of the file or device where
- the I/O should be done.
- SizeInBytes - Supplies the number of bytes to read.
- Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
- definitions.
- TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
- operation should be waited on before timing out. Use
- WAIT_TIME_INDEFINITE to wait forever on the I/O.
- BytesCompleted - Supplies the a pointer where the number of bytes actually
- read will be returned.
- Irp - Supplies a pointer to the IRP to use for this I/O. This is required
- when doing operations on the page file.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- IO_CONTEXT Context;
- PIO_HANDLE ReadHandle;
- KSTATUS Status;
- //
- // Determine the correct read handle. Only perform paging I/O operations
- // when operating on the page file. It is not enough to look at the I/O
- // handle's open flags. There could be reads from the page file or paging
- // device that are not in no-allocate code paths. The caller must dictate
- // the no-allocate code path.
- //
- if ((Handle->HandleType == IoHandleTypePaging) &&
- ((Flags & IO_FLAG_NO_ALLOCATE) == 0)) {
- ReadHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
- } else {
- ReadHandle = Handle;
- }
- Context.IoBuffer = IoBuffer;
- Context.Offset = Offset;
- Context.SizeInBytes = SizeInBytes;
- Context.BytesCompleted = 0;
- Context.Flags = Flags;
- Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
- Context.Write = FALSE;
- //
- // Perform the read operation based on the read handle.
- //
- switch (ReadHandle->HandleType) {
- case IoHandleTypeDefault:
- Status = IopPerformIoOperation(ReadHandle, &Context);
- break;
- case IoHandleTypePaging:
- if ((Irp == NULL) || (TimeoutInMilliseconds != WAIT_TIME_INDEFINITE)) {
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- Status = IopPerformPagingIoOperation((PPAGING_IO_HANDLE)ReadHandle,
- &Context,
- Irp);
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_HANDLE;
- break;
- }
- *BytesCompleted = Context.BytesCompleted;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoWriteAtOffset (
- PIO_HANDLE Handle,
- PIO_BUFFER IoBuffer,
- IO_OFFSET Offset,
- UINTN SizeInBytes,
- ULONG Flags,
- ULONG TimeoutInMilliseconds,
- PUINTN BytesCompleted,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine writes to an I/O object at a specific offset.
- Arguments:
- Handle - Supplies the open I/O handle.
- IoBuffer - Supplies a pointer to an I/O buffer containing the data to write.
- Offset - Supplies the offset from the beginning of the file or device where
- the I/O should be done.
- SizeInBytes - Supplies the number of bytes to write.
- Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
- definitions.
- TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
- operation should be waited on before timing out. Use
- WAIT_TIME_INDEFINITE to wait forever on the I/O.
- BytesCompleted - Supplies the a pointer where the number of bytes actually
- written will be returned.
- Irp - Supplies a pointer to the IRP to use for this I/O. This is required
- when doing operations on the page file.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- IO_CONTEXT Context;
- KSTATUS Status;
- PIO_HANDLE WriteHandle;
- //
- // Determine the correct write handle. Only perform paging I/O operations
- // when operating on the page file. It is not enough to look at the I/O
- // handle's open flags. There could be writes to the page file or paging
- // device that are not in no-allocate code paths. The caller must dictate
- // the no-allocate code path.
- //
- if ((Handle->HandleType == IoHandleTypePaging) &&
- ((Flags & IO_FLAG_NO_ALLOCATE) == 0)) {
- WriteHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
- } else {
- WriteHandle = Handle;
- }
- Context.IoBuffer = IoBuffer;
- Context.Offset = Offset;
- Context.SizeInBytes = SizeInBytes;
- Context.BytesCompleted = 0;
- Context.Flags = Flags;
- Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
- Context.Write = TRUE;
- switch (WriteHandle->HandleType) {
- case IoHandleTypeDefault:
- Status = IopPerformIoOperation(WriteHandle, &Context);
- break;
- case IoHandleTypePaging:
- if ((Irp == NULL) || (TimeoutInMilliseconds != WAIT_TIME_INDEFINITE)) {
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- Status = IopPerformPagingIoOperation((PPAGING_IO_HANDLE)WriteHandle,
- &Context,
- Irp);
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_HANDLE;
- break;
- }
- *BytesCompleted = Context.BytesCompleted;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoFlush (
- PIO_HANDLE Handle,
- IO_OFFSET Offset,
- ULONGLONG Size,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine flushes I/O data to its appropriate backing device.
- Arguments:
- Handle - Supplies an open I/O handle. This parameters is not required if
- the FLUSH_FLAG_ALL flag is set.
- Offset - Supplies the offset from the beginning of the file or device where
- the flush should be done.
- Size - Supplies the size, in bytes, of the region to flush. Supply a value
- of -1 to flush from the given offset to the end of the file.
- Flags - Supplies flags regarding the flush operation. See FLUSH_FLAG_*
- definitions.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- ULONG IoFlags;
- KSTATUS Status;
- IoFlags = IO_FLAG_DATA_SYNCHRONIZED | IO_FLAG_METADATA_SYNCHRONIZED;
- //
- // Handle the flush-all synchronous case, where this routine will not
- // return until all dirty data made it out to disk.
- //
- if ((Flags & FLUSH_FLAG_ALL_SYNCHRONOUS) != 0) {
- if (Handle != INVALID_HANDLE) {
- Status = STATUS_INVALID_PARAMETER;
- goto FlushEnd;
- }
- //
- // Flushing synchronously will get all dirty file data and meta-data to
- // its underlying block device. It will also flush any dirty block
- // device data that has no association with the file layer.
- //
- Status = IopFlushFileObjects(0, IoFlags, NULL);
- goto FlushEnd;
- //
- // Handle the flush-all case. Just notify the page cache worker to run and
- // exit. This does not need to wait until the writes complete.
- //
- } else if ((Flags & FLUSH_FLAG_ALL) != 0) {
- //
- // If a handle was provided, something isn't right.
- //
- if (Handle != INVALID_HANDLE) {
- Status = STATUS_INVALID_PARAMETER;
- goto FlushEnd;
- }
- IopSchedulePageCacheThread();
- Status = STATUS_SUCCESS;
- goto FlushEnd;
- }
- //
- // Otherwise, flush the data for the specific handle. If the data for the
- // handle is not in the cache because it's not cacheable, exit successfully.
- //
- FileObject = Handle->FileObject;
- if ((FileObject->Properties.Type == IoObjectTerminalMaster) ||
- (FileObject->Properties.Type == IoObjectTerminalSlave)) {
- Status = IopTerminalFlush(FileObject, Flags);
- if (!KSUCCESS(Status)) {
- goto FlushEnd;
- }
- } else if (IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE) {
- if ((Flags &
- (FLUSH_FLAG_READ | FLUSH_FLAG_WRITE | FLUSH_FLAG_DISCARD)) != 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto FlushEnd;
- }
- Status = IopFlushFileObject(FileObject,
- Offset,
- Size,
- IoFlags,
- TRUE,
- NULL);
- if (!KSUCCESS(Status)) {
- goto FlushEnd;
- }
- } else {
- Status = STATUS_SUCCESS;
- goto FlushEnd;
- }
- FlushEnd:
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoSeek (
- PIO_HANDLE Handle,
- SEEK_COMMAND SeekCommand,
- IO_OFFSET Offset,
- PIO_OFFSET NewOffset
- )
- /*++
- Routine Description:
- This routine seeks to the given position in a file. This routine is only
- relevant for normal file or block based devices.
- Arguments:
- Handle - Supplies the open I/O handle.
- SeekCommand - Supplies the reference point for the seek offset. Usual
- reference points are the beginning of the file, current file position,
- and the end of the file.
- Offset - Supplies the offset from the reference point to move in bytes.
- NewOffset - Supplies an optional pointer where the file position after the
- move will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- IO_OFFSET FileSize;
- IO_OFFSET LocalNewOffset;
- IO_OFFSET OldOffset;
- IO_OFFSET PreviousOffset;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- FileObject = Handle->FileObject;
- switch (FileObject->Properties.Type) {
- case IoObjectRegularFile:
- case IoObjectRegularDirectory:
- case IoObjectBlockDevice:
- case IoObjectObjectDirectory:
- case IoObjectSharedMemoryObject:
- break;
- default:
- return STATUS_NOT_SUPPORTED;
- }
- //
- // Loop trying to perform the update atomically.
- //
- while (TRUE) {
- OldOffset = RtlAtomicOr64((PULONGLONG)&(Handle->CurrentOffset), 0);
- switch (SeekCommand) {
- case SeekCommandNop:
- LocalNewOffset = OldOffset;
- Status = STATUS_SUCCESS;
- goto SeekEnd;
- case SeekCommandFromCurrentOffset:
- LocalNewOffset = OldOffset + Offset;
- break;
- //
- // Add the file size to the offset and then fall through to handle
- // seeking from the end the same as seeking from the beginning.
- //
- case SeekCommandFromEnd:
- READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
- LocalNewOffset = Offset + FileSize;
- break;
- case SeekCommandFromBeginning:
- LocalNewOffset = Offset;
- break;
- default:
- LocalNewOffset = 0;
- Status = STATUS_INVALID_PARAMETER;
- goto SeekEnd;
- }
- if (LocalNewOffset < 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto SeekEnd;
- }
- PreviousOffset = RtlAtomicCompareExchange64(
- (PULONGLONG)&(Handle->CurrentOffset),
- (ULONGLONG)LocalNewOffset,
- (ULONGLONG)OldOffset);
- if (PreviousOffset == OldOffset) {
- break;
- }
- }
- Status = STATUS_SUCCESS;
- SeekEnd:
- if (NewOffset != NULL) {
- *NewOffset = LocalNewOffset;
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoGetFileSize (
- PIO_HANDLE Handle,
- PULONGLONG FileSize
- )
- /*++
- Routine Description:
- This routine returns the current size of the given file or block device.
- Arguments:
- Handle - Supplies the open file handle.
- FileSize - Supplies a pointer where the file size will be returned on
- success.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- ULONGLONG LocalFileSize;
- PPAGING_IO_HANDLE PagingHandle;
- KSTATUS Status;
- if (Handle->HandleType == IoHandleTypePaging) {
- PagingHandle = (PPAGING_IO_HANDLE)Handle;
- Handle = PagingHandle->IoHandle;
- }
- FileObject = Handle->FileObject;
- READ_INT64_SYNC(&(FileObject->Properties.FileSize), &LocalFileSize);
- *FileSize = LocalFileSize;
- Status = STATUS_SUCCESS;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoGetFileInformation (
- PIO_HANDLE Handle,
- PFILE_PROPERTIES FileProperties
- )
- /*++
- Routine Description:
- This routine gets the file properties for the given I/O handle.
- Arguments:
- Handle - Supplies the open file handle.
- FileProperties - Supplies a pointer where the file properties will be
- returned on success.
- Return Value:
- Status code.
- --*/
- {
- SET_FILE_INFORMATION Request;
- KSTATUS Status;
- Request.FieldsToSet = 0;
- Status = IoSetFileInformation(TRUE, Handle, &Request);
- if (KSUCCESS(Status)) {
- RtlCopyMemory(FileProperties,
- &(Request.FileProperties),
- sizeof(FILE_PROPERTIES));
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoSetFileInformation (
- BOOL FromKernelMode,
- PIO_HANDLE Handle,
- PSET_FILE_INFORMATION Request
- )
- /*++
- Routine Description:
- This routine sets the file properties for the given I/O handle.
- Only some properties can be set by this routine.
- Arguments:
- FromKernelMode - Supplies a boolean indicating whether the request
- originated from user mode (FALSE) or kernel mode (TRUE). Kernel mode
- requests bypass permission checks.
- Handle - Supplies the open file handle.
- Request - Supplies a pointer to the get/set information request.
- Return Value:
- Status code.
- --*/
- {
- ULONG FieldsToSet;
- PFILE_OBJECT FileObject;
- BOOL FileOwner;
- PFILE_PROPERTIES FileProperties;
- ULONGLONG FileSize;
- BOOL HasChownPermission;
- BOOL LockHeldExclusive;
- BOOL LockHeldShared;
- BOOL ModifyFileSize;
- ULONGLONG NewFileSize;
- KSTATUS Status;
- BOOL StatusChanged;
- PKTHREAD Thread;
- BOOL Updated;
- LockHeldExclusive = FALSE;
- LockHeldShared = FALSE;
- Thread = KeGetCurrentThread();
- FieldsToSet = Request->FieldsToSet;
- FileProperties = &(Request->FileProperties);
- if (FieldsToSet == 0) {
- RtlZeroMemory(FileProperties, sizeof(FILE_PROPERTIES));
- }
- Updated = FALSE;
- StatusChanged = FALSE;
- //
- // Operate on the file object that was actually opened, not the file object
- // doing all the I/O.
- //
- FileObject = Handle->PathPoint.PathEntry->FileObject;
- if (FromKernelMode == FALSE) {
- FileOwner = FALSE;
- if ((FileProperties->UserId == Thread->Identity.EffectiveUserId) ||
- (KSUCCESS(PsCheckPermission(PERMISSION_FILE_OWNER)))) {
- FileOwner = TRUE;
- }
- //
- // Perform permission checking. Only a privileged user can change the
- // file owner.
- //
- HasChownPermission = FALSE;
- Status = PsCheckPermission(PERMISSION_CHOWN);
- if (KSUCCESS(Status)) {
- HasChownPermission = TRUE;
- }
- Status = STATUS_PERMISSION_DENIED;
- if ((FieldsToSet & FILE_PROPERTY_FIELD_USER_ID) != 0) {
- if (HasChownPermission == FALSE) {
- goto SetFileInformationEnd;
- }
- }
- //
- // An unprivileged user can change the group of a file they own to any
- // group of which they are also a member (ie Mickey can change the file
- // to any of his mouseketeer clubs).
- //
- if ((FieldsToSet & FILE_PROPERTY_FIELD_GROUP_ID) != 0) {
- if (HasChownPermission == FALSE) {
- if (FileOwner == FALSE) {
- goto SetFileInformationEnd;
- }
- if (PsIsUserInGroup(FileProperties->GroupId) == FALSE) {
- goto SetFileInformationEnd;
- }
- }
- }
- //
- // Only the owner of the file may change the permissions and times on
- // it.
- //
- if ((FieldsToSet & FILE_PROPERTY_OWNER_OWNED_FIELDS) != 0) {
- if (FileOwner == FALSE) {
- goto SetFileInformationEnd;
- }
- }
- } else {
- HasChownPermission = TRUE;
- FileOwner = TRUE;
- }
- //
- // Truncating a file requires the caller to be able to write to it.
- //
- if ((FieldsToSet & FILE_PROPERTY_FIELD_FILE_SIZE) != 0) {
- Status = IopCheckPermissions(FromKernelMode,
- &(Handle->PathPoint),
- IO_ACCESS_WRITE);
- if (!KSUCCESS(Status)) {
- goto SetFileInformationEnd;
- }
- }
- ModifyFileSize = FALSE;
- NewFileSize = 0;
- if (FieldsToSet != 0) {
- KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
- LockHeldExclusive = TRUE;
- } else {
- KeAcquireSharedExclusiveLockShared(FileObject->Lock);
- LockHeldShared = TRUE;
- }
- //
- // Not all attributes can be set for symbolic links.
- //
- if (FileObject->Properties.Type == IoObjectSymbolicLink) {
- FieldsToSet &= FILE_PROPERTY_FIELD_USER_ID |
- FILE_PROPERTY_FIELD_GROUP_ID |
- FILE_PROPERTY_FIELD_ACCESS_TIME |
- FILE_PROPERTY_FIELD_MODIFIED_TIME |
- FILE_PROPERTY_FIELD_STATUS_CHANGE_TIME;
- }
- if (FieldsToSet != 0) {
- //
- // Object directories cannot be altered.
- //
- if (FileObject->Properties.Type == IoObjectObjectDirectory) {
- Status = STATUS_NOT_SUPPORTED;
- goto SetFileInformationEnd;
- }
- //
- // If the owner or group are changed by an unprivileged user, the
- // setuid and setgid bits are cleared from the file.
- //
- if (((FieldsToSet &
- (FILE_PROPERTY_FIELD_USER_ID |
- FILE_PROPERTY_FIELD_GROUP_ID)) != 0) &&
- (HasChownPermission == FALSE)) {
- FileObject->Properties.Permissions &=
- ~(FILE_PERMISSION_SET_USER_ID |
- FILE_PERMISSION_SET_GROUP_ID);
- Updated = TRUE;
- StatusChanged = TRUE;
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_USER_ID) != 0) {
- FileObject->Properties.UserId = FileProperties->UserId;
- Updated = TRUE;
- StatusChanged = TRUE;
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_GROUP_ID) != 0) {
- FileObject->Properties.GroupId = FileProperties->GroupId;
- Updated = TRUE;
- StatusChanged = TRUE;
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_PERMISSIONS) != 0) {
- FileObject->Properties.Permissions =
- FileProperties->Permissions & FILE_PERMISSION_MASK;
- Updated = TRUE;
- StatusChanged = TRUE;
- //
- // If the permissions are being changed by an unprivileged
- // owner, and the caller is not a member of the file group, the
- // setgid permission is removed.
- //
- if ((FromKernelMode == FALSE) &&
- (!KSUCCESS(PsCheckPermission(PERMISSION_FILE_OWNER))) &&
- (PsIsUserInGroup(FileObject->Properties.GroupId) ==
- FALSE)) {
- FileObject->Properties.Permissions &=
- ~FILE_PERMISSION_SET_GROUP_ID;
- }
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_ACCESS_TIME) != 0) {
- FileObject->Properties.AccessTime = FileProperties->AccessTime;
- Updated = TRUE;
- StatusChanged = TRUE;
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_MODIFIED_TIME) != 0) {
- FileObject->Properties.ModifiedTime =
- FileProperties->ModifiedTime;
- Updated = TRUE;
- StatusChanged = TRUE;
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_STATUS_CHANGE_TIME) != 0) {
- FileObject->Properties.StatusChangeTime =
- FileProperties->StatusChangeTime;
- Updated = TRUE;
- }
- if ((FieldsToSet & FILE_PROPERTY_FIELD_FILE_SIZE) != 0) {
- //
- // Some types cannot have their file sizes modified.
- //
- switch (FileObject->Properties.Type) {
- case IoObjectRegularFile:
- case IoObjectSharedMemoryObject:
- break;
- default:
- Status = STATUS_PERMISSION_DENIED;
- goto SetFileInformationEnd;
- }
- ModifyFileSize = TRUE;
- READ_INT64_SYNC(&(FileProperties->FileSize), &NewFileSize);
- }
- } else {
- RtlCopyMemory(FileProperties,
- &(FileObject->Properties),
- sizeof(FILE_PROPERTIES));
- READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
- WRITE_INT64_SYNC(&(FileProperties->FileSize), FileSize);
- }
- //
- // If the file status was changed, update the file status change time.
- // Don't do this if the caller explicitly changed the status change
- // time field.
- //
- if ((StatusChanged != FALSE) &&
- ((FieldsToSet & FILE_PROPERTY_FIELD_STATUS_CHANGE_TIME) == 0)) {
- KeGetSystemTime(&(FileObject->Properties.StatusChangeTime));
- }
- if (LockHeldExclusive != FALSE) {
- KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
- LockHeldExclusive = FALSE;
- } else {
- KeReleaseSharedExclusiveLockShared(FileObject->Lock);
- LockHeldShared = FALSE;
- }
- //
- // With the spin lock released, go ahead and modify the file size if
- // requested.
- //
- if (ModifyFileSize != FALSE) {
- Status = IopModifyFileObjectSize(FileObject,
- Handle->DeviceContext,
- NewFileSize);
- if (!KSUCCESS(Status)) {
- goto SetFileInformationEnd;
- }
- }
- if (Updated != FALSE) {
- IopMarkFileObjectPropertiesDirty(FileObject);
- }
- Status = STATUS_SUCCESS;
- SetFileInformationEnd:
- if (LockHeldExclusive != FALSE) {
- KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
- } else if (LockHeldShared != FALSE) {
- KeReleaseSharedExclusiveLockShared(FileObject->Lock);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoDelete (
- BOOL FromKernelMode,
- PIO_HANDLE Directory,
- PSTR Path,
- ULONG PathSize,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine attempts to delete the object at the given path. If the path
- points to a directory, the directory must be empty. If the path points to
- a file object or shared memory object, its hard link count is decremented.
- If the hard link count reaches zero and no processes have the object open,
- the contents of the object are destroyed. If processes have open handles to
- the object, the destruction of the object contents are deferred until the
- last handle to the old file is closed. If the path points to a symbolic
- link, the link itself is removed and not the destination. The removal of
- the entry from the directory is immediate.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- Directory - Supplies an optional pointer to an open handle to a directory
- for relative paths. Supply NULL to use the current working directory.
- Path - Supplies a pointer to the path to delete.
- PathSize - Supplies the length of the path buffer in bytes, including the
- null terminator.
- Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- if ((Flags & DELETE_FLAG_SHARED_MEMORY) != 0) {
- Status = IopDeleteSharedMemoryObject(Path, PathSize);
- } else {
- Status = IopDelete(FromKernelMode, Directory, Path, PathSize, Flags);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoRename (
- BOOL FromKernelMode,
- PIO_HANDLE SourceStartDirectory,
- PSTR SourcePath,
- ULONG SourcePathSize,
- PIO_HANDLE DestinationStartDirectory,
- PSTR DestinationPath,
- ULONG DestinationPathSize
- )
- /*++
- Routine Description:
- This routine attempts to rename the object at the given path. This routine
- operates on symbolic links themselves, not the destinations of symbolic
- links. If the source and destination paths are equal, this routine will do
- nothing and return successfully. If the source path is not a directory, the
- destination path must not be a directory. If the destination file exists,
- it will be deleted. The caller must have write access in both the old and
- new directories. If the source path is a directory, the destination path
- must not exist or be an empty directory. The destination path must not have
- a path prefix of the source (ie it's illegal to move /my/path into
- /my/path/stuff).
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- SourceStartDirectory - Supplies an optional pointer to a handle to the
- directory to start at for relative source paths. If the source path is
- not relative, this parameter is ignored. If this is not supplied, then
- the current working directory of the process is used.
- SourcePath - Supplies a pointer to the path of the file to rename.
- SourcePathSize - Supplies the length of the source path buffer in bytes,
- including the null terminator.
- DestinationStartDirectory - Supplies an optional pointer to the directory
- to start at for relative destination paths. If the destination path is
- not relative, this parameter is ignored. If this is not supplied, then
- the current working directory of the process is used.
- DestinationPath - Supplies a pointer to the path to rename the file to.
- DestinationPathSize - Supplies the size of the destination path buffer in
- bytes, including the null terminator.
- Return Value:
- Status code.
- --*/
- {
- ULONG Attempts;
- BOOL DescendantPath;
- PSTR DestinationDirectory;
- PFILE_OBJECT DestinationDirectoryFileObject;
- PATH_POINT DestinationDirectoryPathPoint;
- ULONG DestinationDirectorySize;
- PSTR DestinationFile;
- PFILE_OBJECT DestinationFileObject;
- ULONG DestinationFileSize;
- PATH_POINT DestinationPathPoint;
- PPATH_POINT DestinationStartPathPoint;
- PDEVICE Device;
- PATH_POINT FoundPathPoint;
- PSTR LocalDestinationPath;
- ULONG LocalDestinationPathSize;
- PSTR LocalSourcePath;
- ULONG LocalSourcePathSize;
- BOOL LocksHeld;
- ULONG NameHash;
- PPATH_ENTRY PathEntry;
- SYSTEM_CONTROL_RENAME RenameRequest;
- PFILE_OBJECT SourceDirectoryFileObject;
- PATH_POINT SourceDirectoryPathPoint;
- PFILE_OBJECT SourceFileObject;
- PATH_POINT SourcePathPoint;
- PPATH_POINT SourceStartPathPoint;
- KSTATUS Status;
- DestinationDirectory = NULL;
- DestinationDirectoryPathPoint.PathEntry = NULL;
- DestinationPathPoint.PathEntry = NULL;
- DestinationFile = NULL;
- DestinationFileObject = NULL;
- DestinationStartPathPoint = NULL;
- FoundPathPoint.PathEntry = NULL;
- LocksHeld = FALSE;
- SourceDirectoryPathPoint.PathEntry = NULL;
- SourceFileObject = NULL;
- SourcePathPoint.PathEntry = NULL;
- SourceStartPathPoint = NULL;
- if ((SourcePathSize <= 1) || (DestinationPathSize <= 1)) {
- Status = STATUS_PATH_NOT_FOUND;
- goto RenameEnd;
- }
- if (SourceStartDirectory != NULL) {
- SourceStartPathPoint = &(SourceStartDirectory->PathPoint);
- if (SourceStartPathPoint->PathEntry->FileObject->Properties.Type !=
- IoObjectRegularDirectory) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto RenameEnd;
- }
- ASSERT(SourceStartDirectory->FileObject ==
- SourceStartPathPoint->PathEntry->FileObject);
- }
- if (DestinationStartDirectory != NULL) {
- DestinationStartPathPoint = &(DestinationStartDirectory->PathPoint);
- if (DestinationStartPathPoint->PathEntry->FileObject->Properties.Type !=
- IoObjectRegularDirectory) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto RenameEnd;
- }
- ASSERT(DestinationStartDirectory->FileObject ==
- DestinationStartPathPoint->PathEntry->FileObject);
- }
- //
- // Loop trying to rename the source to the destination. The loop is
- // necessary because things may change before the appropriate locks are
- // acquired. Once the locks are acquired, the state is checked and if it is
- // not good enough to proceed, the whole process gets restarted.
- //
- Attempts = 0;
- Status = STATUS_TRY_AGAIN;
- while (Attempts < IO_RENAME_ATTEMPTS_MAX) {
- //
- // Get the source file, which must exist.
- //
- LocalSourcePath = SourcePath;
- LocalSourcePathSize = SourcePathSize;
- Status = IopPathWalk(FromKernelMode,
- SourceStartPathPoint,
- &LocalSourcePath,
- &LocalSourcePathSize,
- OPEN_FLAG_SYMBOLIC_LINK | OPEN_FLAG_NO_MOUNT_POINT,
- IoObjectInvalid,
- NULL,
- FILE_PERMISSION_NONE,
- &SourcePathPoint);
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- //
- // Rename is not allowed if the source is mounted anywhere.
- //
- if (SourcePathPoint.PathEntry->MountCount != 0) {
- Status = STATUS_RESOURCE_IN_USE;
- goto RenameEnd;
- }
- //
- // Get the source directory entry and file object.
- //
- IopGetParentPathPoint(NULL,
- &SourcePathPoint,
- &SourceDirectoryPathPoint);
- PathEntry = SourceDirectoryPathPoint.PathEntry;
- SourceDirectoryFileObject = PathEntry->FileObject;
- ASSERT(SourceDirectoryFileObject != NULL);
- ASSERT(SourcePathPoint.MountPoint ==
- SourceDirectoryPathPoint.MountPoint);
- //
- // Check to see that the caller has permission to delete something from
- // the source directory.
- //
- if (FromKernelMode == FALSE) {
- Status = IopCheckDeletePermission(FromKernelMode,
- &SourceDirectoryPathPoint,
- &SourcePathPoint);
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- }
- SourceFileObject = SourcePathPoint.PathEntry->FileObject;
- ASSERT(SourceFileObject->Properties.DeviceId ==
- SourceDirectoryFileObject->Properties.DeviceId);
- //
- // Split the destination path into a file part and a directory part.
- //
- Status = IopPathSplit(DestinationPath,
- DestinationPathSize,
- &DestinationDirectory,
- &DestinationDirectorySize,
- &DestinationFile,
- &DestinationFileSize);
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- //
- // Get the destination file, which may or may not exist.
- //
- LocalDestinationPath = DestinationPath;
- LocalDestinationPathSize = DestinationPathSize;
- Status = IopPathWalk(FromKernelMode,
- DestinationStartPathPoint,
- &LocalDestinationPath,
- &LocalDestinationPathSize,
- OPEN_FLAG_SYMBOLIC_LINK | OPEN_FLAG_NO_MOUNT_POINT,
- IoObjectInvalid,
- NULL,
- FILE_PERMISSION_NONE,
- &DestinationPathPoint);
- if (!KSUCCESS(Status)) {
- if (Status != STATUS_PATH_NOT_FOUND) {
- goto RenameEnd;
- }
- ASSERT(DestinationPathPoint.PathEntry == NULL);
- //
- // Try to find the destination file's directory.
- //
- LocalDestinationPath = DestinationDirectory;
- LocalDestinationPathSize = DestinationDirectorySize;
- if ((LocalDestinationPathSize == 0) ||
- ((LocalDestinationPathSize == 1) &&
- (LocalDestinationPath[0] == '\0'))) {
- LocalDestinationPath = ".";
- LocalDestinationPathSize = sizeof(".");
- }
- Status = IopPathWalk(FromKernelMode,
- DestinationStartPathPoint,
- &LocalDestinationPath,
- &LocalDestinationPathSize,
- OPEN_FLAG_SYMBOLIC_LINK,
- IoObjectInvalid,
- NULL,
- FILE_PERMISSION_NONE,
- &DestinationDirectoryPathPoint);
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- PathEntry = DestinationDirectoryPathPoint.PathEntry;
- DestinationDirectoryFileObject = PathEntry->FileObject;
- //
- // Require write permission on the directory since the destination
- // does not exist.
- //
- Status = IopCheckPermissions(FromKernelMode,
- &DestinationDirectoryPathPoint,
- IO_ACCESS_WRITE);
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- //
- // The destination file exists.
- //
- } else {
- PathEntry = DestinationPathPoint.PathEntry;
- DestinationFileObject = PathEntry->FileObject;
- //
- // If the destination is the same as the source, then it's a no-op.
- //
- if (SourceFileObject == DestinationFileObject) {
- Status = STATUS_SUCCESS;
- goto RenameEnd;
- }
- //
- // If the source is not a directory, the destination cannot be a
- // directory.
- //
- if ((SourceFileObject->Properties.Type !=
- IoObjectRegularDirectory) &&
- (DestinationFileObject->Properties.Type ==
- IoObjectRegularDirectory)) {
- Status = STATUS_FILE_IS_DIRECTORY;
- goto RenameEnd;
- }
- //
- // If the source is a directory, the destination must be a
- // directory. The check for that destination to be empty will be
- // done in the file system.
- //
- if ((SourceFileObject->Properties.Type ==
- IoObjectRegularDirectory) &&
- (DestinationFileObject->Properties.Type !=
- IoObjectRegularDirectory)) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto RenameEnd;
- }
- //
- // Rename is not allowed when the destination is mounted. It does
- // not matter where.
- //
- if (DestinationPathPoint.PathEntry->MountCount != 0) {
- Status = STATUS_RESOURCE_IN_USE;
- goto RenameEnd;
- }
- IopGetParentPathPoint(NULL,
- &DestinationPathPoint,
- &DestinationDirectoryPathPoint);
- PathEntry = DestinationDirectoryPathPoint.PathEntry;
- DestinationDirectoryFileObject = PathEntry->FileObject;
- ASSERT(DestinationPathPoint.PathEntry->FileObject->Device ==
- DestinationDirectoryPathPoint.PathEntry->FileObject->Device);
- ASSERT(DestinationPathPoint.MountPoint ==
- DestinationDirectoryPathPoint.MountPoint);
- ASSERT(DestinationFileObject->Properties.DeviceId ==
- DestinationDirectoryFileObject->Properties.DeviceId);
- //
- // Since there is a destination file, it needs to be deleted.
- // Ensure the caller has that authority.
- //
- Status = IopCheckDeletePermission(FromKernelMode,
- &DestinationDirectoryPathPoint,
- &DestinationPathPoint);
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- }
- //
- // The destination directory should not have a path prefix of the
- // source file. Ignore mount points for this check and only look at
- // the path entries.
- //
- if (SourceFileObject->Properties.Type == IoObjectRegularDirectory) {
- DescendantPath = IopIsDescendantPath(
- SourcePathPoint.PathEntry,
- DestinationDirectoryPathPoint.PathEntry);
- if (DescendantPath != FALSE) {
- Status = STATUS_INVALID_PARAMETER;
- goto RenameEnd;
- }
- }
- //
- // Renames don't work across file systems.
- //
- if (SourcePathPoint.PathEntry->FileObject->Device !=
- DestinationDirectoryPathPoint.PathEntry->FileObject->Device) {
- Status = STATUS_CROSS_DEVICE;
- goto RenameEnd;
- }
- //
- // The object file system does not allow renaming, only devices and
- // volumes can handle it.
- //
- Device = SourcePathPoint.PathEntry->FileObject->Device;
- if ((Device->Header.Type != ObjectDevice) &&
- (Device->Header.Type != ObjectVolume)) {
- Status = STATUS_ACCESS_DENIED;
- goto RenameEnd;
- }
- //
- // Prepare the rename request.
- //
- RenameRequest.Name = DestinationFile;
- RenameRequest.NameSize = DestinationFileSize;
- RenameRequest.DestinationFileUnlinked = FALSE;
- RenameRequest.DestinationDirectorySize = 0;
- RenameRequest.SourceFileProperties = &(SourceFileObject->Properties);
- RenameRequest.SourceDirectoryProperties =
- &(SourceDirectoryFileObject->Properties);
- RenameRequest.DestinationFileProperties = NULL;
- RenameRequest.DestinationDirectoryProperties =
- &(DestinationDirectoryFileObject->Properties);
- //
- // For a rename operation, the source file, the source directory and
- // the destination directory need to be locked. Additionally, if a
- // destination file exists, it needs to be locked to synchronize the
- // unlink operation and write file properties. The source file is
- // locked to synchronize with file property writes. Because the FAT
- // file system writes properties to the parent directory, file property
- // writes always need to be able to find a valid parent directory.
- // Directories are always locked before files.
- //
- IopAcquireFileObjectLocksExclusive(SourceDirectoryFileObject,
- DestinationDirectoryFileObject);
- if (DestinationFileObject != NULL) {
- IopAcquireFileObjectLocksExclusive(SourceFileObject,
- DestinationFileObject);
- } else {
- KeAcquireSharedExclusiveLockExclusive(SourceFileObject->Lock);
- }
- LocksHeld = TRUE;
- //
- // If the source file or destination directory have been unlinked, act
- // like the paths were not found. It's okay if the destination
- // directory has no siblings if it's a mount point, as mount points
- // cannot be unlinked without first being unmounted, and some mounts
- // are just floating path entries without siblings.
- //
- if ((SourcePathPoint.PathEntry->SiblingListEntry.Next == NULL) ||
- ((DestinationDirectoryPathPoint.PathEntry->SiblingListEntry.Next ==
- NULL) &&
- (!IO_IS_MOUNT_POINT(&DestinationDirectoryPathPoint)))) {
- Status = STATUS_PATH_NOT_FOUND;
- break;
- }
- //
- // If the source is still there, the source directory better still be
- // there too.
- //
- ASSERT((SourceDirectoryPathPoint.PathEntry->SiblingListEntry.Next !=
- NULL) ||
- (IO_IS_MOUNT_POINT(&SourceDirectoryPathPoint)));
- //
- // If the destination file was present above and is still in the path
- // hierarchy, then the rename can proceed.
- //
- if ((DestinationPathPoint.PathEntry != NULL) &&
- (DestinationPathPoint.PathEntry->SiblingListEntry.Next != NULL)) {
- ASSERT(DestinationFileObject != NULL);
- ASSERT(DestinationPathPoint.PathEntry->Negative == FALSE);
- ASSERT(DestinationFileObject->Properties.HardLinkCount != 0);
- RenameRequest.DestinationFileProperties =
- &(DestinationFileObject->Properties);
- Status = STATUS_SUCCESS;
- break;
- }
- //
- // Otherwise, now that the destination directory's lock is held, if
- // there is still no file at the destination, then the rename can
- // proceed.
- //
- Status = IopPathLookup(FromKernelMode,
- DestinationStartPathPoint,
- &DestinationDirectoryPathPoint,
- TRUE,
- DestinationFile,
- DestinationFileSize,
- OPEN_FLAG_NO_MOUNT_POINT,
- IoObjectInvalid,
- NULL,
- 0,
- &FoundPathPoint);
- //
- // If no path is found, then either a negative path entry was found or
- // no file path exists. It is then safe to proceed with the rename.
- //
- if (Status == STATUS_PATH_NOT_FOUND) {
- ASSERT(RenameRequest.DestinationFileProperties == NULL);
- Status = STATUS_SUCCESS;
- ASSERT((FoundPathPoint.PathEntry == NULL) ||
- (FoundPathPoint.PathEntry->Negative != FALSE));
- //
- // If there's a negative path entry there, unlink it. The reference
- // will be released when the locks can be dropped.
- //
- if (FoundPathPoint.PathEntry != NULL) {
- IopPathUnlink(FoundPathPoint.PathEntry);
- }
- break;
- //
- // For any other error, just break and fail.
- //
- } else if (!KSUCCESS(Status)) {
- break;
- }
- //
- // If a destination file was found, then the rename must loop back and
- // make another attempt. Due to lock ordering it is not possible to
- // simply acquire this entry's lock now. And once the locks are
- // released, no guarantees can be made about the state of the source
- // or directory.
- //
- ASSERT(FoundPathPoint.PathEntry != NULL);
- ASSERT(FoundPathPoint.PathEntry->SiblingListEntry.Next != NULL);
- //
- // A destination entry was found or it was unlinked after the
- // destination directory lock was acquired. The rename needs to be
- // tried again. Release the locks and any references taken.
- //
- KeReleaseSharedExclusiveLockExclusive(SourceFileObject->Lock);
- if (DestinationFileObject != NULL) {
- KeReleaseSharedExclusiveLockExclusive(DestinationFileObject->Lock);
- }
- KeReleaseSharedExclusiveLockExclusive(SourceDirectoryFileObject->Lock);
- if (DestinationDirectoryFileObject != SourceDirectoryFileObject) {
- KeReleaseSharedExclusiveLockExclusive(
- DestinationDirectoryFileObject->Lock);
- }
- LocksHeld = FALSE;
- IO_PATH_POINT_RELEASE_REFERENCE(&SourcePathPoint);
- SourcePathPoint.PathEntry = NULL;
- IO_PATH_POINT_RELEASE_REFERENCE(&SourceDirectoryPathPoint);
- SourceDirectoryPathPoint.PathEntry = NULL;
- IO_PATH_POINT_RELEASE_REFERENCE(&DestinationDirectoryPathPoint);
- DestinationDirectoryPathPoint.PathEntry = NULL;
- if (DestinationPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&DestinationPathPoint);
- DestinationPathPoint.PathEntry = NULL;
- }
- if (FoundPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&FoundPathPoint);
- FoundPathPoint.PathEntry = NULL;
- }
- MmFreePagedPool(DestinationDirectory);
- DestinationDirectory = NULL;
- MmFreePagedPool(DestinationFile);
- DestinationFile = NULL;
- DestinationFileObject = NULL;
- Attempts += 1;
- }
- if (!KSUCCESS(Status)) {
- goto RenameEnd;
- }
- //
- // Check to make sure that the source and destination file objects did not
- // become mount points since the checks above. A path entry's file object's
- // lock is acquired in shared mode when the mount count is increment,
- // synchronizing with the rename call.
- //
- if ((SourcePathPoint.PathEntry->MountCount != 0) ||
- ((DestinationPathPoint.PathEntry != NULL) &&
- (DestinationPathPoint.PathEntry->MountCount != 0))) {
- Status = STATUS_RESOURCE_IN_USE;
- goto RenameEnd;
- }
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlRename,
- &RenameRequest);
- //
- // Even if the rename failed, the destination file (if it existed and had
- // not already been unlinked) could have been unlinked. If so, decrement
- // it's hard link count and unlink it from this path tree. This must happen
- // while the locks are held.
- //
- if (RenameRequest.DestinationFileUnlinked != FALSE) {
- ASSERT(DestinationPathPoint.PathEntry != NULL);
- ASSERT(DestinationFileObject != NULL);
- IopFileObjectDecrementHardLinkCount(DestinationFileObject);
- IopPathUnlink(DestinationPathPoint.PathEntry);
- //
- // If there's a negative destination entry, remove it. The rename moved
- // the source onto the destination, in which case the file object
- // pointer is incorrectly null.
- //
- } else if ((DestinationPathPoint.PathEntry != NULL) &&
- (DestinationPathPoint.PathEntry->Negative != FALSE)) {
- IopPathUnlink(DestinationPathPoint.PathEntry);
- }
- //
- // If the source file's hard link count changed, then it could now either
- // be in two directories, or in no directories.
- //
- if (RenameRequest.SourceFileHardLinkDelta != 0) {
- //
- // If the delta is 1, then it got added to the destination directory,
- // but was never deleted from the source. Increment the hard link count.
- //
- if (RenameRequest.SourceFileHardLinkDelta == 1) {
- IopFileObjectIncrementHardLinkCount(SourceFileObject);
- IopUpdateFileObjectTime(DestinationDirectoryFileObject,
- FileObjectModifiedTime);
- //
- // Otherwise, the delta is -1. Decrement the hard link count and unlink
- // it from the source path entry. Unfortunately, this rename turned
- // into a delete.
- //
- } else {
- ASSERT(RenameRequest.SourceFileHardLinkDelta == (ULONG)-1);
- IopFileObjectDecrementHardLinkCount(SourceFileObject);
- IopPathUnlink(SourcePathPoint.PathEntry);
- IopUpdateFileObjectTime(SourceDirectoryFileObject,
- FileObjectModifiedTime);
- }
- //
- // Rename succeeded.
- //
- } else if (KSUCCESS(Status)) {
- //
- // Create a path entry at the destination to avoid the painful
- // penalty of having to do a file system lookup on this object next
- // time.
- //
- if (SourcePathPoint.PathEntry->DoNotCache == FALSE) {
- NameHash = IopHashPathString(DestinationFile, DestinationFileSize);
- PathEntry = IopCreatePathEntry(
- DestinationFile,
- DestinationFileSize,
- NameHash,
- DestinationDirectoryPathPoint.PathEntry,
- SourceFileObject);
- if (PathEntry != NULL) {
- INSERT_BEFORE(
- &(PathEntry->SiblingListEntry),
- &(DestinationDirectoryPathPoint.PathEntry->ChildList));
- IopFileObjectAddReference(SourceFileObject);
- }
- }
- //
- // Unlink the source file path from its parent so new paths walks will
- // not find it and so that delete will see that it's too late.
- //
- IopPathUnlink(SourcePathPoint.PathEntry);
- //
- // Also update the size of the destination directory.
- //
- IopUpdateFileObjectFileSize(DestinationDirectoryFileObject,
- RenameRequest.DestinationDirectorySize);
- IopUpdateFileObjectTime(DestinationDirectoryFileObject,
- FileObjectModifiedTime);
- IopUpdateFileObjectTime(SourceDirectoryFileObject,
- FileObjectModifiedTime);
- }
- IopUpdateFileObjectTime(SourceFileObject, FileObjectStatusTime);
- RenameEnd:
- if (LocksHeld != FALSE) {
- KeReleaseSharedExclusiveLockExclusive(SourceFileObject->Lock);
- if (DestinationFileObject != NULL) {
- KeReleaseSharedExclusiveLockExclusive(DestinationFileObject->Lock);
- }
- KeReleaseSharedExclusiveLockExclusive(SourceDirectoryFileObject->Lock);
- if (DestinationDirectoryFileObject != SourceDirectoryFileObject) {
- KeReleaseSharedExclusiveLockExclusive(
- DestinationDirectoryFileObject->Lock);
- }
- }
- if ((KSUCCESS(Status)) && (SourceFileObject != DestinationFileObject)) {
- IopPathCleanCache(SourcePathPoint.PathEntry);
- }
- if (SourcePathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&SourcePathPoint);
- }
- if (SourceDirectoryPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&SourceDirectoryPathPoint);
- }
- if (DestinationPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&DestinationPathPoint);
- }
- if (DestinationDirectoryPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&DestinationDirectoryPathPoint);
- }
- if (FoundPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&FoundPathPoint);
- }
- if (DestinationDirectory != NULL) {
- MmFreePagedPool(DestinationDirectory);
- }
- if (DestinationFile != NULL) {
- MmFreePagedPool(DestinationFile);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoCreateSymbolicLink (
- BOOL FromKernelMode,
- PIO_HANDLE Directory,
- PSTR LinkName,
- ULONG LinkNameSize,
- PSTR LinkTarget,
- ULONG LinkTargetSize
- )
- /*++
- Routine Description:
- This routine attempts to create a new symbolic link at the given path.
- The target of the symbolic link is not required to exist. The link path
- must not already exist.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- Directory - Supplies an optional pointer to an open handle to a directory
- for relative paths. Supply NULL to use the current working directory.
- LinkName - Supplies a pointer to the path of the new link to create.
- LinkNameSize - Supplies the length of the link name buffer in bytes,
- including the null terminator.
- LinkTarget - Supplies a pointer to the target of the link, the location the
- link points to.
- LinkTargetSize - Supplies the size of the link target buffer in bytes,
- including the null terminator.
- Return Value:
- Status code.
- --*/
- {
- UINTN BytesCompleted;
- ULONG Flags;
- PIO_HANDLE Handle;
- IO_BUFFER IoBuffer;
- KSTATUS Status;
- Handle = NULL;
- Flags = OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS | OPEN_FLAG_TRUNCATE |
- OPEN_FLAG_SYMBOLIC_LINK;
- Status = IopOpen(FromKernelMode,
- Directory,
- LinkName,
- LinkNameSize,
- IO_ACCESS_WRITE,
- Flags,
- IoObjectSymbolicLink,
- NULL,
- FILE_PERMISSION_ALL,
- &Handle);
- if (!KSUCCESS(Status)) {
- goto CreateSymbolicLinkEnd;
- }
- Status = MmInitializeIoBuffer(&IoBuffer,
- LinkTarget,
- INVALID_PHYSICAL_ADDRESS,
- LinkTargetSize,
- IO_BUFFER_FLAG_KERNEL_MODE_DATA);
- if (!KSUCCESS(Status)) {
- goto CreateSymbolicLinkEnd;
- }
- Status = IoWriteAtOffset(Handle,
- &IoBuffer,
- 0,
- LinkTargetSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesCompleted,
- NULL);
- if (!KSUCCESS(Status)) {
- goto CreateSymbolicLinkEnd;
- }
- CreateSymbolicLinkEnd:
- if (Handle != NULL) {
- IoClose(Handle);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoReadSymbolicLink (
- PIO_HANDLE Handle,
- ULONG AllocationTag,
- PSTR *LinkTarget,
- PULONG LinkTargetSize
- )
- /*++
- Routine Description:
- This routine reads the destination of a given open symbolic link, and
- returns the information in a newly allocated buffer. It is the caller's
- responsibility to free this memory from paged pool.
- Arguments:
- Handle - Supplies the open file handle to the symbolic link itself.
- AllocationTag - Supplies the paged pool tag to use when creating the
- allocation.
- LinkTarget - Supplies a pointer where a newly allocated string will be
- returned on success containing the target the link is pointing at.
- LinkTargetSize - Supplies a pointer where the size of the link target in
- bytes (including the null terminator) will be returned.
- Return Value:
- STATUS_SUCCESS if the link target was successfully returned.
- STATUS_INSUFFICIENT_RESOURCES on allocation failure.
- STATUS_NOT_READY if the contents of the symbolic link are not valid.
- Other status codes on other failures.
- --*/
- {
- UINTN BytesCompleted;
- FILE_PROPERTIES FileProperties;
- IO_BUFFER IoBuffer;
- ULONGLONG Size;
- KSTATUS Status;
- PSTR TargetBuffer;
- UINTN TargetBufferSize;
- TargetBuffer = NULL;
- //
- // Reading the symbolic link is pretty much just reading the entire
- // contents of the file into paged pool.
- //
- Status = IoGetFileInformation(Handle, &FileProperties);
- if (!KSUCCESS(Status)) {
- goto ReadSymbolicLinkEnd;
- }
- if (FileProperties.Type != IoObjectSymbolicLink) {
- Status = STATUS_INVALID_PARAMETER;
- goto ReadSymbolicLinkEnd;
- }
- READ_INT64_SYNC(&(FileProperties.FileSize), &Size);
- TargetBufferSize = Size;
- if (Size != TargetBufferSize) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadSymbolicLinkEnd;
- }
- if (Size == 0) {
- Status = STATUS_NOT_READY;
- goto ReadSymbolicLinkEnd;
- }
- TargetBuffer = MmAllocatePagedPool(TargetBufferSize + 1, AllocationTag);
- if (TargetBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadSymbolicLinkEnd;
- }
- Status = MmInitializeIoBuffer(&IoBuffer,
- TargetBuffer,
- INVALID_PHYSICAL_ADDRESS,
- TargetBufferSize,
- IO_BUFFER_FLAG_KERNEL_MODE_DATA);
- if (!KSUCCESS(Status)) {
- goto ReadSymbolicLinkEnd;
- }
- Status = IoReadAtOffset(Handle,
- &IoBuffer,
- 0,
- TargetBufferSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesCompleted,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ReadSymbolicLinkEnd;
- }
- if (BytesCompleted != TargetBufferSize) {
- Status = STATUS_NOT_READY;
- goto ReadSymbolicLinkEnd;
- }
- TargetBuffer[TargetBufferSize] = '\0';
- TargetBufferSize += 1;
- Status = STATUS_SUCCESS;
- ReadSymbolicLinkEnd:
- if (!KSUCCESS(Status)) {
- if (TargetBuffer != NULL) {
- MmFreePagedPool(TargetBuffer);
- TargetBuffer = NULL;
- }
- TargetBufferSize = 0;
- }
- *LinkTarget = TargetBuffer;
- *LinkTargetSize = TargetBufferSize;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoUserControl (
- PIO_HANDLE Handle,
- ULONG MinorCode,
- BOOL FromKernelMode,
- PVOID ContextBuffer,
- UINTN ContextBufferSize
- )
- /*++
- Routine Description:
- This routine performs a user control operation.
- Arguments:
- Handle - Supplies the open file handle.
- MinorCode - Supplies the minor code of the request.
- FromKernelMode - Supplies a boolean indicating whether or not this request
- (and the buffer associated with it) originates from user mode (FALSE)
- or kernel mode (TRUE).
- ContextBuffer - Supplies a pointer to the context buffer allocated by the
- caller for the request.
- ContextBufferSize - Supplies the size of the supplied context buffer.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- KSTATUS Status;
- FileObject = Handle->FileObject;
- switch (FileObject->Properties.Type) {
- case IoObjectBlockDevice:
- case IoObjectCharacterDevice:
- Device = FileObject->Device;
- ASSERT(Device->Header.Type == ObjectDevice);
- Status = IopSendUserControlIrp(Device,
- MinorCode,
- FromKernelMode,
- ContextBuffer,
- ContextBufferSize);
- break;
- case IoObjectTerminalMaster:
- case IoObjectTerminalSlave:
- Status = IopTerminalUserControl(Handle,
- MinorCode,
- FromKernelMode,
- ContextBuffer,
- ContextBufferSize);
- break;
- case IoObjectSocket:
- Status = IoSocketUserControl(Handle,
- MinorCode,
- FromKernelMode,
- ContextBuffer,
- ContextBufferSize);
- break;
- default:
- Status = STATUS_NOT_SUPPORTED;
- break;
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoGetDevice (
- PIO_HANDLE Handle,
- PDEVICE *Device
- )
- /*++
- Routine Description:
- This routine returns the actual device backing the given I/O object. Not
- all I/O objects are actually backed by a single device. For file and
- directory objects, this routine will return a pointer to the volume.
- Arguments:
- Handle - Supplies the open file handle.
- Device - Supplies a pointer where the underlying I/O device will be
- returned.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE FileDevice;
- PFILE_OBJECT FileObject;
- PPAGING_IO_HANDLE PagingIoHandle;
- //
- // For paging I/O handles, this routine is called during page in (so it
- // can't fault). Get the device directly out of the paging I/O handle.
- //
- if (Handle->HandleType == IoHandleTypePaging) {
- PagingIoHandle = (PPAGING_IO_HANDLE)Handle;
- *Device = PagingIoHandle->Device;
- if (PagingIoHandle->Device != NULL) {
- return STATUS_SUCCESS;
- }
- return STATUS_INVALID_CONFIGURATION;
- }
- FileObject = Handle->FileObject;
- FileDevice = FileObject->Device;
- if (IS_DEVICE_OR_VOLUME(FileDevice)) {
- *Device = FileDevice;
- return STATUS_SUCCESS;
- }
- return STATUS_INVALID_CONFIGURATION;
- }
- KERNEL_API
- BOOL
- IoIsPageFileAccessSupported (
- PIO_HANDLE Handle
- )
- /*++
- Routine Description:
- This routine determines whether or not page file access is supported on the
- given handle.
- Arguments:
- Handle - Supplies a pointer to the I/O handle.
- Return Value:
- Returns TRUE if the handle supports page file I/O, or FALSE otherwise.
- --*/
- {
- if (Handle->HandleType == IoHandleTypePaging) {
- return TRUE;
- }
- return FALSE;
- }
- KERNEL_API
- KSTATUS
- IoGetGlobalStatistics (
- PIO_GLOBAL_STATISTICS Statistics
- )
- /*++
- Routine Description:
- This routine returns a snap of the global I/O statistics counters.
- Arguments:
- Statistics - Supplies a pointer to the global I/O statistics.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if the version is less than
- IO_GLOBAL_STATISTICS_VERSION.
- --*/
- {
- if ((Statistics->Version < IO_GLOBAL_STATISTICS_VERSION) ||
- (Statistics->Version > IO_GLOBAL_STATISTICS_MAX_VERSION)) {
- return STATUS_INVALID_PARAMETER;
- }
- Statistics->BytesRead = RtlAtomicOr64(&(IoGlobalStatistics.BytesRead), 0);
- Statistics->BytesWritten = RtlAtomicOr64(&(IoGlobalStatistics.BytesWritten),
- 0);
- Statistics->PagingBytesRead =
- RtlAtomicOr64(&(IoGlobalStatistics.PagingBytesRead), 0);
- Statistics->PagingBytesWritten =
- RtlAtomicOr64(&(IoGlobalStatistics.PagingBytesWritten), 0);
- return STATUS_SUCCESS;
- }
- KSTATUS
- IoOpenPageFile (
- PSTR Path,
- ULONG PathSize,
- ULONG Access,
- ULONG Flags,
- PIO_HANDLE *Handle,
- PULONGLONG FileSize
- )
- /*++
- Routine Description:
- This routine opens a page file. This routine is to be used only
- internally by MM.
- Arguments:
- Path - Supplies a pointer to the string containing the file path to open.
- PathSize - Supplies the length of the path buffer in bytes, including
- the null terminator.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- Handle - Supplies a pointer where a pointer to the open I/O handle will be
- returned on success.
- FileSize - Supplies a pointer where the file size in bytes will be returned
- on success.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- PIO_HANDLE IoHandle;
- ULONGLONG LocalFileSize;
- PPAGING_IO_HANDLE NewHandle;
- KSTATUS Status;
- *FileSize = 0;
- *Handle = NULL;
- IoHandle = NULL;
- NewHandle = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Allocate the basic structure.
- //
- NewHandle = MmAllocateNonPagedPool(sizeof(PAGING_IO_HANDLE),
- IO_ALLOCATION_TAG);
- if (NewHandle == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto OpenPageFileEnd;
- }
- RtlZeroMemory(NewHandle, sizeof(PAGING_IO_HANDLE));
- NewHandle->HandleType = IoHandleTypePaging;
- //
- // Open the file normally, but with the page file and non-cached flags set.
- //
- Flags |= OPEN_FLAG_PAGE_FILE | OPEN_FLAG_NON_CACHED;
- Status = IopOpen(TRUE,
- NULL,
- Path,
- PathSize,
- Access,
- Flags,
- IoObjectInvalid,
- NULL,
- 0,
- &IoHandle);
- if (!KSUCCESS(Status)) {
- goto OpenPageFileEnd;
- }
- //
- // Even if a page file exists on this device, it might not be intended for
- // use on this sytem. If the device is not an intended paging device, then
- // return failure.
- //
- FileObject = IoHandle->FileObject;
- Device = FileObject->Device;
- if (!IS_DEVICE_OR_VOLUME(Device)) {
- Status = STATUS_NOT_SUPPORTED;
- goto OpenPageFileEnd;
- }
- if ((Device->Flags & DEVICE_FLAG_PAGING_DEVICE) == 0) {
- Status = STATUS_NO_SUCH_FILE;
- goto OpenPageFileEnd;
- }
- NewHandle->DeviceContext = IoHandle->DeviceContext;
- NewHandle->Device = Device;
- READ_INT64_SYNC(&(FileObject->Properties.FileSize), &LocalFileSize);
- NewHandle->Capacity = LocalFileSize;
- NewHandle->IoHandle = IoHandle;
- NewHandle->OffsetAlignment = FileObject->Properties.BlockSize;
- NewHandle->SizeAlignment = FileObject->Properties.BlockSize;
- *FileSize = NewHandle->Capacity;
- Status = STATUS_SUCCESS;
- OpenPageFileEnd:
- if (!KSUCCESS(Status)) {
- if (IoHandle != NULL) {
- IoClose(IoHandle);
- }
- if (NewHandle != NULL) {
- MmFreeNonPagedPool(NewHandle);
- }
- NewHandle = NULL;
- }
- *Handle = (PIO_HANDLE)NewHandle;
- return Status;
- }
- KSTATUS
- IopOpen (
- BOOL FromKernelMode,
- PIO_HANDLE Directory,
- PSTR Path,
- ULONG PathLength,
- ULONG Access,
- ULONG Flags,
- IO_OBJECT_TYPE TypeOverride,
- PVOID OverrideParameter,
- FILE_PERMISSIONS CreatePermissions,
- PIO_HANDLE *Handle
- )
- /*++
- Routine Description:
- This routine opens a file, device, pipe, or other I/O object.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- Directory - Supplies an optional pointer to a handle to a directory to use
- if the given path is relative. Supply NULL to use the current working
- directory.
- Path - Supplies a pointer to the path to open.
- PathLength - Supplies the length of the path buffer in bytes, including the
- null terminator.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- TypeOverride - Supplies an object type that the regular file should be
- converted to. Supply the invalid object type to specify no override.
- OverrideParameter - Supplies an optional parameter to send along with the
- override type.
- CreatePermissions - Supplies the permissions to apply for created object
- on create operations.
- Handle - Supplies a pointer where a pointer to the open I/O handle will be
- returned on success.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT DirectoryFileObject;
- PPATH_POINT DirectoryPathPoint;
- PFILE_OBJECT FileObject;
- PATH_POINT PathPoint;
- PKPROCESS Process;
- KSTATUS Status;
- DirectoryPathPoint = NULL;
- PathPoint.PathEntry = NULL;
- PathPoint.MountPoint = NULL;
- //
- // If the request is meant to unlink on creation, make sure that the create
- // flag is also set and prepare to fail if the file already exists.
- //
- ASSERT(((Flags & OPEN_FLAG_UNLINK_ON_CREATE) == 0) ||
- ((Flags & (OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS)) ==
- (OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS)));
- //
- // If the caller specified a directory, validate that it is a directory,
- // and perform permission checking if search permissions were not granted
- // upon open.
- //
- if (Directory != NULL) {
- DirectoryFileObject = Directory->FileObject;
- DirectoryPathPoint = &(Directory->PathPoint);
- if (DirectoryFileObject->Properties.Type != IoObjectRegularDirectory) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto OpenEnd;
- }
- ASSERT(DirectoryFileObject ==
- DirectoryPathPoint->PathEntry->FileObject);
- }
- //
- // Apply the umask.
- //
- if ((Flags & OPEN_FLAG_CREATE) != 0) {
- Process = PsGetCurrentProcess();
- CreatePermissions &= ~(Process->Umask);
- }
- //
- // If there is no path, create an anonymous object.
- //
- if (PathLength == 0) {
- Status = IopCreateAnonymousObject(Access,
- Flags,
- TypeOverride,
- OverrideParameter,
- CreatePermissions,
- &PathPoint);
- //
- // There is a path, so walk it to create or open your destiny.
- //
- } else {
- //
- // Change the override if the create flag is on.
- //
- if ((Flags & OPEN_FLAG_CREATE) != 0) {
- if ((Flags & OPEN_FLAG_DIRECTORY) != 0) {
- ASSERT(TypeOverride == IoObjectInvalid);
- TypeOverride = IoObjectRegularDirectory;
- } else if (TypeOverride == IoObjectInvalid) {
- TypeOverride = IoObjectRegularFile;
- }
- }
- Status = IopPathWalk(FromKernelMode,
- DirectoryPathPoint,
- &Path,
- &PathLength,
- Flags,
- TypeOverride,
- OverrideParameter,
- CreatePermissions,
- &PathPoint);
- }
- if (!KSUCCESS(Status)) {
- goto OpenEnd;
- }
- //
- // Check the directory flag against the type.
- //
- FileObject = PathPoint.PathEntry->FileObject;
- //
- // If the directory flag is set, the resulting file object is required to
- // be a directory.
- //
- if ((Flags & OPEN_FLAG_DIRECTORY) != 0) {
- if ((FileObject->Properties.Type != IoObjectRegularDirectory) &&
- (FileObject->Properties.Type != IoObjectObjectDirectory)) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto OpenEnd;
- }
- //
- // Sockets can only be opened if they're being created or just opened for
- // information.
- //
- } else if (FileObject->Properties.Type == IoObjectSocket) {
- if ((TypeOverride != IoObjectSocket) && (Access != 0)) {
- Status = STATUS_NO_SUCH_DEVICE_OR_ADDRESS;
- goto OpenEnd;
- }
- //
- // If the directory flag is not set, then check the override against the
- // object.
- //
- } else {
- //
- // If the object is a directory, then fail if either an override was
- // specified (meaning a create is trying to occur) or the open is for
- // anything other than read. Turns out opening a directory for read is
- // allowed, it's just that no I/O can be performed on it.
- //
- if ((FileObject->Properties.Type == IoObjectRegularDirectory) ||
- (FileObject->Properties.Type == IoObjectObjectDirectory)) {
- if (((Access & (IO_ACCESS_WRITE | IO_ACCESS_EXECUTE)) != 0) ||
- (TypeOverride != IoObjectInvalid)) {
- if (TypeOverride == IoObjectSymbolicLink) {
- Status = STATUS_FILE_EXISTS;
- } else {
- Status = STATUS_FILE_IS_DIRECTORY;
- }
- goto OpenEnd;
- }
- }
- }
- //
- // Check permissions on path entry.
- //
- if (FromKernelMode == FALSE) {
- Status = IopCheckPermissions(FromKernelMode, &PathPoint, Access);
- if (!KSUCCESS(Status)) {
- goto OpenEnd;
- }
- }
- //
- // Open the path point, which upon success takes another reference on the
- // path point.
- //
- Status = IopOpenPathPoint(&PathPoint, Access, Flags, Handle);
- if (!KSUCCESS(Status)) {
- goto OpenEnd;
- }
- Status = STATUS_SUCCESS;
- OpenEnd:
- //
- // Do not use the path point release reference macro here, the mount point
- // may be null if an anonymous object was created.
- //
- if (PathPoint.PathEntry != NULL) {
- IoPathEntryReleaseReference(PathPoint.PathEntry);
- if (PathPoint.MountPoint != NULL) {
- IoMountPointReleaseReference(PathPoint.MountPoint);
- }
- }
- return Status;
- }
- KSTATUS
- IopOpenPathPoint (
- PPATH_POINT PathPoint,
- ULONG Access,
- ULONG Flags,
- PIO_HANDLE *Handle
- )
- /*++
- Routine Description:
- This routine opens a path entry object. This routine must be called
- carefully by internal functions, as it skips all permission checks.
- Arguments:
- PathPoint - Supplies a pointer to the path point to open. Upon success this
- routine will add a reference to the path point's path entry and mount
- point.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- Handle - Supplies a pointer where a pointer to the open I/O handle will be
- returned on success.
- Return Value:
- Status code.
- --*/
- {
- IRP_CLOSE CloseIrp;
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- PIO_HANDLE NewHandle;
- PVOID OldDeviceContext;
- ULONG OldFileObjectFlags;
- IRP_OPEN OpenIrp;
- BOOL OpenIrpSent;
- KSTATUS Status;
- Device = NULL;
- NewHandle = NULL;
- OpenIrpSent = FALSE;
- //
- // Create an I/O handle.
- //
- Status = IopCreateIoHandle(&NewHandle);
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- IO_COPY_PATH_POINT(&(NewHandle->PathPoint), PathPoint);
- NewHandle->OpenFlags = Flags;
- NewHandle->Access = Access;
- FileObject = PathPoint->PathEntry->FileObject;
- NewHandle->FileObject = FileObject;
- switch (FileObject->Properties.Type) {
- case IoObjectRegularFile:
- case IoObjectSymbolicLink:
- case IoObjectBlockDevice:
- RtlZeroMemory(&OpenIrp, sizeof(IRP_OPEN));
- OpenIrp.FileProperties = &(FileObject->Properties);
- OpenIrp.IoState = FileObject->IoState;
- Device = FileObject->Device;
- ASSERT(IS_DEVICE_OR_VOLUME(Device));
- //
- // If the file object is cacheable and has not been opened, call the
- // driver to get a context with full access.
- //
- if ((IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE) &&
- ((FileObject->Flags & FILE_OBJECT_FLAG_OPEN) == 0)) {
- OpenIrp.DesiredAccess = IO_ACCESS_READ | IO_ACCESS_WRITE;
- OpenIrp.OpenFlags = Flags;
- Status = IopSendOpenIrp(Device, &OpenIrp);
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- //
- // If someone wants to replace a cacheable file, think about this.
- //
- ASSERT(OpenIrp.Replacement == NULL);
- //
- // Now try to insert the device context into the file object. First
- // exchange the device context pointer. It is not safe to mark it
- // open until the context is set.
- //
- OldDeviceContext = (PVOID)RtlAtomicCompareExchange(
- (PVOID)&(FileObject->DeviceContext),
- (UINTN)OpenIrp.DeviceContext,
- (UINTN)NULL);
- //
- // If the old context was NULL, then this caller might have won the
- // race to set it. That said, some devices return a NULL context.
- // So additionally try to set the open status. If this race is lost
- // then send the close IRP. The other open won.
- //
- if (OldDeviceContext == NULL) {
- OldFileObjectFlags = RtlAtomicOr32(&(FileObject->Flags),
- FILE_OBJECT_FLAG_OPEN);
- if ((OldFileObjectFlags & FILE_OBJECT_FLAG_OPEN) != 0) {
- CloseIrp.DeviceContext = OpenIrp.DeviceContext;
- IopSendCloseIrp(Device, &CloseIrp);
- }
- //
- // Otherwise, this caller lost the race. It should destroy its
- // context before continuing. It is not safe, however, to assert
- // that the file object is open. The winner of the context race may
- // not have set the open flag yet.
- //
- } else {
- CloseIrp.DeviceContext = OpenIrp.DeviceContext;
- IopSendCloseIrp(Device, &CloseIrp);
- }
- }
- //
- // If the file object is going to be used in the paging path or is not
- // cacheable, open up a device context that will be stored in the I/O
- // handle.
- //
- if ((IO_IS_FILE_OBJECT_CACHEABLE(FileObject) == FALSE) ||
- ((Flags & OPEN_FLAG_PAGE_FILE) != 0) ||
- ((Flags & OPEN_FLAG_PAGING_DEVICE) != 0)) {
- OpenIrp.DesiredAccess = Access;
- OpenIrp.OpenFlags = Flags;
- Status = IopSendOpenIrp(Device, &OpenIrp);
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- ASSERT(OpenIrp.Replacement == NULL);
- OpenIrpSent = TRUE;
- NewHandle->DeviceContext = OpenIrp.DeviceContext;
- }
- //
- // If the caller requested a truncate operation and it is allowed on
- // this object type, modify the file object's size.
- //
- if (((Flags & OPEN_FLAG_TRUNCATE) != 0) &&
- ((Flags & OPEN_FLAG_PAGE_FILE) == 0)) {
- Status = IopModifyFileObjectSize(FileObject,
- NewHandle->DeviceContext,
- 0);
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- }
- Status = STATUS_SUCCESS;
- break;
- case IoObjectCharacterDevice:
- case IoObjectRegularDirectory:
- RtlZeroMemory(&OpenIrp, sizeof(IRP_OPEN));
- OpenIrp.FileProperties = &(FileObject->Properties);
- OpenIrp.IoState = FileObject->IoState;
- OpenIrp.DesiredAccess = Access;
- OpenIrp.OpenFlags = Flags;
- Device = FileObject->Device;
- ASSERT(IS_DEVICE_OR_VOLUME(Device));
- Status = IopSendOpenIrp(Device, &OpenIrp);
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- OpenIrpSent = TRUE;
- NewHandle->DeviceContext = OpenIrp.DeviceContext;
- //
- // If the caller actually wanted to replace this object with something
- // else, overwrite the handle. Directories cannot be replaced,
- // since they are too heavily involved with their path entries, which
- // do not get overwritten.
- //
- if (OpenIrp.Replacement != NULL) {
- ASSERT(FileObject->Properties.Type != IoObjectRegularDirectory);
- IopOverwriteIoHandle(NewHandle, OpenIrp.Replacement);
- }
- break;
- case IoObjectPipe:
- Status = IopOpenPipe(NewHandle);
- break;
- //
- // Object directories don't need anything to be opened.
- //
- case IoObjectObjectDirectory:
- Status = STATUS_SUCCESS;
- break;
- case IoObjectSocket:
- Status = IopOpenSocket(NewHandle);
- break;
- case IoObjectTerminalMaster:
- Status = IopTerminalOpenMaster(NewHandle);
- break;
- case IoObjectTerminalSlave:
- Status = IopTerminalOpenSlave(NewHandle);
- break;
- case IoObjectSharedMemoryObject:
- if ((Flags & OPEN_FLAG_TRUNCATE) != 0) {
- Status = IopModifyFileObjectSize(FileObject, NULL, 0);
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- }
- Status = STATUS_SUCCESS;
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_CONFIGURATION;
- break;
- }
- if (!KSUCCESS(Status)) {
- goto OpenPathEntryEnd;
- }
- //
- // Do not use the default path point add reference macro. An anonymous
- // object does not have a mount point.
- //
- IoPathEntryAddReference(PathPoint->PathEntry);
- if (PathPoint->MountPoint != NULL) {
- IoMountPointAddReference(PathPoint->MountPoint);
- }
- Status = STATUS_SUCCESS;
- OpenPathEntryEnd:
- if (!KSUCCESS(Status)) {
- if (OpenIrpSent != FALSE) {
- CloseIrp.DeviceContext = NewHandle->DeviceContext;
- IopSendCloseIrp(Device, &CloseIrp);
- }
- if (NewHandle != NULL) {
- NewHandle->PathPoint.PathEntry = NULL;
- IoIoHandleReleaseReference(NewHandle);
- NewHandle = NULL;
- }
- }
- ASSERT((NewHandle == NULL) || (NewHandle->PathPoint.PathEntry != NULL));
- *Handle = NewHandle;
- return Status;
- }
- KSTATUS
- IopOpenDevice (
- PDEVICE Device,
- ULONG Access,
- ULONG Flags,
- PIO_HANDLE *Handle
- )
- /*++
- Routine Description:
- This routine opens a device or volume.
- Arguments:
- Device - Supplies a pointer to a device to open.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- Handle - Supplies a pointer where a pointer to the open I/O handle will be
- returned on success.
- Return Value:
- Status code.
- --*/
- {
- PIO_HANDLE NewHandle;
- PCHAR ObjectPath;
- KSTATUS Status;
- ASSERT((Device->Header.Type == ObjectDevice) ||
- (Device->Header.Type == ObjectVolume));
- NewHandle = NULL;
- ObjectPath = ObGetFullPath(Device, DEVICE_ALLOCATION_TAG);
- if (ObjectPath == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto OpenDeviceEnd;
- }
- //
- // Open the device from kernel mode.
- //
- Status = IopOpen(TRUE,
- NULL,
- ObjectPath,
- RtlStringLength(ObjectPath) + 1,
- Access,
- Flags,
- IoObjectInvalid,
- NULL,
- 0,
- &NewHandle);
- if (!KSUCCESS(Status)) {
- goto OpenDeviceEnd;
- }
- OpenDeviceEnd:
- if (ObjectPath != NULL) {
- MmFreePagedPool(ObjectPath);
- }
- *Handle = NewHandle;
- return Status;
- }
- KSTATUS
- IopCreateSpecialIoObject (
- ULONG Flags,
- IO_OBJECT_TYPE Type,
- PVOID OverrideParameter,
- FILE_PERMISSIONS CreatePermissions,
- PFILE_OBJECT *FileObject
- )
- /*++
- Routine Description:
- This routine creates a special file object.
- Arguments:
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- Type - Supplies the type of special object to create.
- OverrideParameter - Supplies an optional parameter to send along with the
- override type.
- CreatePermissions - Supplies the permissions to assign to the new file.
- FileObject - Supplies a pointer where a pointer to the new file object
- will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- switch (Type) {
- case IoObjectPipe:
- Status = IopCreatePipe(NULL, 0, CreatePermissions, FileObject);
- break;
- case IoObjectSocket:
- Status = IopCreateSocket(OverrideParameter,
- CreatePermissions,
- FileObject);
- break;
- case IoObjectTerminalMaster:
- case IoObjectTerminalSlave:
- Status = IopCreateTerminal(Type,
- OverrideParameter,
- CreatePermissions,
- FileObject);
- break;
- case IoObjectSharedMemoryObject:
- Status = IopCreateSharedMemoryObject(NULL,
- 0,
- Flags,
- CreatePermissions,
- FileObject);
- break;
- default:
- ASSERT(FALSE);
- return STATUS_NOT_SUPPORTED;
- }
- return Status;
- }
- KSTATUS
- IopClose (
- PIO_HANDLE IoHandle
- )
- /*++
- Routine Description:
- This routine shuts down an I/O handle that is about to be destroyed.
- Arguments:
- IoHandle - Supplies a pointer to the I/O handle returned when the file was
- opened.
- Return Value:
- Status code.
- --*/
- {
- IRP_CLOSE CloseIrp;
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- KSTATUS Status;
- //
- // Use the file object in the path entry rather than the I/O handle so that
- // opens and closes are balanced.
- //
- FileObject = NULL;
- if (IoHandle->PathPoint.PathEntry != NULL) {
- FileObject = IoHandle->PathPoint.PathEntry->FileObject;
- switch (FileObject->Properties.Type) {
- case IoObjectRegularFile:
- case IoObjectRegularDirectory:
- case IoObjectSymbolicLink:
- case IoObjectBlockDevice:
- case IoObjectCharacterDevice:
- //
- // If the handle received a device context on open, close it.
- //
- if ((IO_IS_FILE_OBJECT_CACHEABLE(FileObject) == FALSE) ||
- ((IoHandle->OpenFlags & OPEN_FLAG_PAGE_FILE) != 0) ||
- ((IoHandle->OpenFlags & OPEN_FLAG_PAGING_DEVICE) != 0)) {
- CloseIrp.DeviceContext = IoHandle->DeviceContext;
- Device = FileObject->Device;
- ASSERT(IS_DEVICE_OR_VOLUME(Device));
- Status = IopSendCloseIrp(Device, &CloseIrp);
- //
- // Otherwise, just report success.
- //
- } else {
- Status = STATUS_SUCCESS;
- }
- break;
- case IoObjectPipe:
- Status = IopClosePipe(IoHandle);
- break;
- case IoObjectSocket:
- Status = IopCloseSocket(IoHandle);
- break;
- case IoObjectTerminalMaster:
- Status = IopTerminalCloseMaster(IoHandle);
- break;
- case IoObjectTerminalSlave:
- Status = IopTerminalCloseSlave(IoHandle);
- break;
- default:
- Status = STATUS_SUCCESS;
- break;
- }
- if (!KSUCCESS(Status)) {
- goto CloseEnd;
- }
- }
- //
- // Clear the asynchronous receiver information from this handle.
- //
- if (IoHandle->Async != NULL) {
- IoSetHandleAsynchronous(IoHandle, 0, FALSE);
- MmFreePagedPool(IoHandle->Async);
- IoHandle->Async = NULL;
- }
- //
- // Let go of the path point, and slide gently into the night. Be careful,
- // as anonymous objects do not have a mount point. Also handles that failed
- // to open do not have a path entry.
- //
- if (IoHandle->PathPoint.PathEntry != NULL) {
- //
- // If the file object in the handle is not the same as the one in the
- // path entry, release the reference on the one in the handle.
- //
- if (FileObject != IoHandle->FileObject) {
- IopFileObjectReleaseReference(IoHandle->FileObject);
- }
- IoPathEntryReleaseReference(IoHandle->PathPoint.PathEntry);
- if (IoHandle->PathPoint.MountPoint != NULL) {
- IoMountPointReleaseReference(IoHandle->PathPoint.MountPoint);
- }
- }
- Status = STATUS_SUCCESS;
- CloseEnd:
- return Status;
- }
- KSTATUS
- IopDelete (
- BOOL FromKernelMode,
- PIO_HANDLE Directory,
- PSTR Path,
- ULONG PathSize,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine attempts to delete the object at the given path. If the path
- points to a directory, the directory must be empty. If the path points to
- a file object or shared memory object, its hard link count is decremented.
- If the hard link count reaches zero and no processes have the object open,
- the contents of the object are destroyed. If processes have open handles to
- the object, the destruction of the object contents are deferred until the
- last handle to the old file is closed. If the path points to a symbolic
- link, the link itself is removed and not the destination. The removal of
- the entry from the directory is immediate.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- Directory - Supplies an optional pointer to an open handle to a directory
- for relative paths. Supply NULL to use the current working directory.
- Path - Supplies a pointer to the path to delete.
- PathSize - Supplies the length of the path buffer in bytes, including the
- null terminator.
- Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
- Return Value:
- Status code.
- --*/
- {
- PPATH_ENTRY DirectoryEntry;
- PFILE_OBJECT DirectoryFileObject;
- PPATH_POINT DirectoryPathPoint;
- PATH_POINT PathPoint;
- KSTATUS Status;
- DirectoryPathPoint = NULL;
- PathPoint.PathEntry = NULL;
- //
- // If the caller specified a directory, validate that it is a directory.
- // Search permission checking for the directory is done in the path walk
- // code.
- //
- if (Directory != NULL) {
- DirectoryPathPoint = &(Directory->PathPoint);
- DirectoryEntry = DirectoryPathPoint->PathEntry;
- DirectoryFileObject = DirectoryEntry->FileObject;
- if (DirectoryFileObject->Properties.Type != IoObjectRegularDirectory) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto DeleteEnd;
- }
- ASSERT(Directory->FileObject == DirectoryFileObject);
- }
- Status = IopPathWalk(FromKernelMode,
- DirectoryPathPoint,
- &Path,
- &PathSize,
- OPEN_FLAG_SYMBOLIC_LINK | OPEN_FLAG_NO_MOUNT_POINT,
- IoObjectInvalid,
- NULL,
- FILE_PERMISSION_NONE,
- &PathPoint);
- if (!KSUCCESS(Status)) {
- goto DeleteEnd;
- }
- Status = IopDeletePathPoint(FromKernelMode, &PathPoint, Flags);
- if (!KSUCCESS(Status)) {
- goto DeleteEnd;
- }
- DeleteEnd:
- if (PathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&PathPoint);
- }
- return Status;
- }
- KSTATUS
- IopDeleteByHandle (
- BOOL FromKernelMode,
- PIO_HANDLE Handle,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine attempts to delete the the object open by the given I/O
- handle. This does not close or invalidate the handle, but it does attempt
- to unlink the object so future path walks will not find it at that location.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- Handle - Supplies the open handle to the device.
- Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- //
- // Fail for anonymous path entries.
- //
- if (Handle->PathPoint.PathEntry->NameSize == 0) {
- return STATUS_PATH_NOT_FOUND;
- }
- Status = IopDeletePathPoint(FromKernelMode, &(Handle->PathPoint), Flags);
- return Status;
- }
- KSTATUS
- IopDeletePathPoint (
- BOOL FromKernelMode,
- PPATH_POINT PathPoint,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine attempts to delete the object at the given path. If the path
- points to a directory, the directory must be empty. If the path point is
- a file object or shared memory object, its hard link count is decremented.
- If the hard link count reaches zero and no processes have the object open,
- the contents of the object are destroyed. If processes have open handles to
- the object, the destruction of the object contents are deferred until the
- last handle to the old file is closed.
- Arguments:
- FromKernelMode - Supplies a boolean indicating the request is coming from
- kernel mode.
- PathPoint - Supplies a pointer to the path point to delete. The caller
- should already have a reference on this path point, which will need to
- be released by the caller when finished.
- Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE Device;
- PFILE_OBJECT DirectoryFileObject;
- PFILE_OBJECT FileObject;
- BOOL LocksHeld;
- PATH_POINT ParentPathPoint;
- BOOL SendUnlinkRequest;
- KSTATUS Status;
- BOOL Unlinked;
- LocksHeld = FALSE;
- ParentPathPoint.PathEntry = NULL;
- //
- // Delete is not allowed if the path entry is mounted. Doesn't matter
- // where.
- //
- if (PathPoint->PathEntry->MountCount != 0) {
- Status = STATUS_RESOURCE_IN_USE;
- goto DeletePathPointEnd;
- }
- //
- // Get the file object for the file to delete, and the path point for the
- // containing directory.
- //
- FileObject = PathPoint->PathEntry->FileObject;
- IopGetParentPathPoint(NULL,
- PathPoint,
- &ParentPathPoint);
- ASSERT(PathPoint->MountPoint == ParentPathPoint.MountPoint);
- //
- // Perform permission checking on the directory in preparation for the
- // directory write operation.
- //
- if (FromKernelMode == FALSE) {
- Status = IopCheckDeletePermission(FromKernelMode,
- &ParentPathPoint,
- PathPoint);
- if (!KSUCCESS(Status)) {
- goto DeletePathPointEnd;
- }
- }
- //
- // The root object cannot be deleted. This is detected by the parent
- // equaling the child.
- //
- if (IO_ARE_PATH_POINTS_EQUAL(PathPoint, &ParentPathPoint) != FALSE) {
- Status = STATUS_NOT_SUPPORTED;
- goto DeletePathPointEnd;
- }
- //
- // Square up with the directory flag.
- //
- if ((Flags & DELETE_FLAG_DIRECTORY) != 0) {
- if (FileObject->Properties.Type != IoObjectRegularDirectory) {
- Status = STATUS_NOT_A_DIRECTORY;
- goto DeletePathPointEnd;
- }
- } else {
- if (FileObject->Properties.Type == IoObjectRegularDirectory) {
- Status = STATUS_FILE_IS_DIRECTORY;
- goto DeletePathPointEnd;
- }
- }
- //
- // The object file system only allows unlinking of shared memory objects,
- // pipes, and terminals by kernel mode callers.
- //
- Device = PathPoint->PathEntry->FileObject->Device;
- SendUnlinkRequest = FALSE;
- if (Device == ObGetRootObject()) {
- if ((FromKernelMode == FALSE) ||
- ((FileObject->Properties.Type != IoObjectSharedMemoryObject) &&
- (FileObject->Properties.Type != IoObjectTerminalMaster) &&
- (FileObject->Properties.Type != IoObjectTerminalSlave) &&
- (FileObject->Properties.Type != IoObjectPipe))) {
- Status = STATUS_ACCESS_DENIED;
- goto DeletePathPointEnd;
- }
- //
- // Otherwise deletes can only be from devices or volumes.
- //
- } else {
- if ((Device->Header.Type != ObjectDevice) &&
- (Device->Header.Type != ObjectVolume)) {
- Status = STATUS_ACCESS_DENIED;
- goto DeletePathPointEnd;
- }
- SendUnlinkRequest = TRUE;
- }
- DirectoryFileObject = ParentPathPoint.PathEntry->FileObject;
- //
- // The unlink operation needs to modify the parent directory and the file
- // properties of the child. Hold both locks exclusively. Directories are
- // always acquired first.
- //
- ASSERT(DirectoryFileObject != FileObject);
- KeAcquireSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
- KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
- LocksHeld = TRUE;
- //
- // With the appropriate locks acquired, check to make sure the file can
- // still be unlinked. If it cannot, act like it was not found.
- //
- if (PathPoint->PathEntry->SiblingListEntry.Next == NULL) {
- Status = STATUS_PATH_NOT_FOUND;
- goto DeletePathPointEnd;
- }
- //
- // Check again to make sure that the path entry did not get mounted on.
- // Mount creation synchronizes with the path entry's file object lock.
- //
- if (PathPoint->PathEntry->MountCount != 0) {
- Status = STATUS_RESOURCE_IN_USE;
- goto DeletePathPointEnd;
- }
- ASSERT(FileObject->Properties.HardLinkCount != 0);
- //
- // If unlink request needs to be sent to a driver, then send it now.
- //
- if (SendUnlinkRequest != FALSE) {
- Status = IopSendUnlinkRequest(Device,
- FileObject,
- DirectoryFileObject,
- PathPoint->PathEntry->Name,
- PathPoint->PathEntry->NameSize,
- &Unlinked);
- //
- // Otherwise just handle the unlink by calling the type specific unlink
- // routine, decrementing the object's hard link count and updating the
- // directory's access time.
- //
- } else {
- if (FileObject->Properties.Type == IoObjectSharedMemoryObject) {
- Status = IopUnlinkSharedMemoryObject(FileObject, &Unlinked);
- } else if (FileObject->Properties.Type == IoObjectPipe) {
- Status = IopUnlinkPipe(FileObject, &Unlinked);
- } else {
- ASSERT((FileObject->Properties.Type == IoObjectTerminalMaster) ||
- (FileObject->Properties.Type == IoObjectTerminalSlave));
- Status = IopUnlinkTerminal(FileObject, &Unlinked);
- }
- if (Unlinked != FALSE) {
- IopFileObjectDecrementHardLinkCount(FileObject);
- IopUpdateFileObjectTime(DirectoryFileObject,
- FileObjectModifiedTime);
- }
- }
- //
- // If the object was successfully unlinked, finish the job even if the call
- // failed. Unlink the path entry from the system's path hierarchy. This
- // needs to be done while the parent's file object I/O lock is held
- // exclusively.
- //
- if (Unlinked != FALSE) {
- IopPathUnlink(PathPoint->PathEntry);
- }
- KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
- KeReleaseSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
- LocksHeld = FALSE;
- //
- // Clean the cached path entries if the path point was successfully
- // unlinked from its parent. The only things that should be there now are
- // negative path entries with a reference count of zero.
- //
- if (Unlinked != FALSE) {
- IopPathCleanCache(PathPoint->PathEntry);
- }
- if (!KSUCCESS(Status)) {
- goto DeletePathPointEnd;
- }
- DeletePathPointEnd:
- if (LocksHeld != FALSE) {
- KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
- KeReleaseSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
- }
- if (ParentPathPoint.PathEntry != NULL) {
- IO_PATH_POINT_RELEASE_REFERENCE(&ParentPathPoint);
- }
- return Status;
- }
- KSTATUS
- IopSendFileOperationIrp (
- IRP_MINOR_CODE MinorCode,
- PFILE_OBJECT FileObject,
- PVOID DeviceContext,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine sends a file operation IRP.
- Arguments:
- MinorCode - Supplies the minor code of the IRP to send.
- FileObject - Supplies a pointer to the file object of the file being
- operated on.
- DeviceContext - Supplies a pointer to the device context to send down.
- Flags - Supplies a bitmask of I/O flags. See IO_FLAG_* for definitions.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE Device;
- SYSTEM_CONTROL_FILE_OPERATION Request;
- KSTATUS Status;
- if ((FileObject->Properties.Type != IoObjectRegularFile) &&
- (FileObject->Properties.Type != IoObjectRegularDirectory) &&
- (FileObject->Properties.Type != IoObjectSymbolicLink) &&
- (FileObject->Properties.Type != IoObjectBlockDevice) &&
- (FileObject->Properties.Type != IoObjectCharacterDevice)) {
- return STATUS_SUCCESS;
- }
- Request.FileProperties = &(FileObject->Properties);
- Request.DeviceContext = DeviceContext;
- Request.Flags = Flags;
- Device = FileObject->Device;
- ASSERT(IS_DEVICE_OR_VOLUME(Device));
- Status = IopSendSystemControlIrp(Device, MinorCode, &Request);
- return Status;
- }
- KSTATUS
- IopSendLookupRequest (
- PDEVICE Device,
- PFILE_OBJECT Directory,
- PSTR FileName,
- ULONG FileNameSize,
- PFILE_PROPERTIES Properties
- )
- /*++
- Routine Description:
- This routine sends a lookup request IRP. This routine assumes that the
- directory's lock is held exclusively.
- Arguments:
- Device - Supplies a pointer to the device to send the request to.
- Directory - Supplies a pointer to the file object of the directory to
- search in.
- FileName - Supplies a pointer to the name of the file, which may not be
- null terminated.
- FileNameSize - Supplies the size of the file name buffer including space
- for a null terminator (which may be a null terminator or may be a
- garbage character).
- Properties - Supplies a pointer where the file properties will be returned
- if the file was found.
- Return Value:
- Status code.
- --*/
- {
- SYSTEM_CONTROL_LOOKUP Request;
- KSTATUS Status;
- ASSERT(KeIsSharedExclusiveLockHeldExclusive(Directory->Lock) != FALSE);
- ASSERT(Directory->Properties.HardLinkCount != 0);
- RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_LOOKUP));
- Request.Root = FALSE;
- Request.DirectoryProperties = &(Directory->Properties);
- Request.FileName = FileName;
- Request.FileNameSize = FileNameSize;
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlLookup,
- &Request);
- RtlCopyMemory(Properties, &(Request.Properties), sizeof(FILE_PROPERTIES));
- return Status;
- }
- KSTATUS
- IopSendRootLookupRequest (
- PDEVICE Device,
- PFILE_PROPERTIES Properties,
- PULONG Flags
- )
- /*++
- Routine Description:
- This routine sends a lookup request IRP for the device's root.
- Arguments:
- Device - Supplies a pointer to the device to send the request to.
- Properties - Supplies the file properties if the file was found.
- Flags - Supplies a pointer that receives the flags returned by the root
- lookup call. See LOOKUP_FLAG_* for definitions.
- Return Value:
- Status code.
- --*/
- {
- SYSTEM_CONTROL_LOOKUP Request;
- KSTATUS Status;
- RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_LOOKUP));
- Request.Root = TRUE;
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlLookup,
- &Request);
- RtlCopyMemory(Properties, &(Request.Properties), sizeof(FILE_PROPERTIES));
- *Flags = Request.Flags;
- return Status;
- }
- KSTATUS
- IopSendCreateRequest (
- PDEVICE Device,
- PFILE_OBJECT Directory,
- PSTR Name,
- ULONG NameSize,
- PFILE_PROPERTIES Properties
- )
- /*++
- Routine Description:
- This routine sends a creation request to the device. This routine assumes
- that the directory's lock is held exclusively.
- Arguments:
- Device - Supplies a pointer to the device to send the request to.
- Directory - Supplies a pointer to the file object of the directory to
- create the file in.
- Name - Supplies a pointer to the name of the file or directory to create,
- which may not be null terminated.
- NameSize - Supplies the size of the name buffer including space for a null
- terminator (which may be a null terminator or may be a garbage
- character).
- Properties - Supplies a pointer to the file properties of the created file
- on success. The permissions, object type, user ID, group ID, and access
- times are all valid from the system.
- Return Value:
- Status code.
- --*/
- {
- SYSTEM_CONTROL_CREATE Request;
- KSTATUS Status;
- ASSERT(KeIsSharedExclusiveLockHeldExclusive(Directory->Lock) != FALSE);
- ASSERT(Directory->Properties.HardLinkCount != 0);
- RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_CREATE));
- Request.DirectoryProperties = &(Directory->Properties);
- Request.Name = Name;
- Request.NameSize = NameSize;
- RtlCopyMemory(&(Request.FileProperties),
- Properties,
- sizeof(FILE_PROPERTIES));
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlCreate,
- &Request);
- RtlCopyMemory(Properties,
- &(Request.FileProperties),
- sizeof(FILE_PROPERTIES));
- //
- // Update the access time and modified time if file was created.
- //
- if (KSUCCESS(Status)) {
- IopUpdateFileObjectTime(Directory, FileObjectModifiedTime);
- IopUpdateFileObjectFileSize(Directory, Request.DirectorySize);
- }
- return Status;
- }
- KSTATUS
- IopSendUnlinkRequest (
- PDEVICE Device,
- PFILE_OBJECT FileObject,
- PFILE_OBJECT DirectoryObject,
- PSTR Name,
- ULONG NameSize,
- PBOOL Unlinked
- )
- /*++
- Routine Description:
- This routine sends an unlink request to the device. This routine assumes
- that the directory's lock is held exclusively.
- Arguments:
- Device - Supplies a pointer to the device to send the request to.
- FileObject - Supplies a pointer to the file object of the file that is to
- be unlinked.
- DirectoryObject - Supplies a pointer to the file object of the directory
- from which the file will be unlinked.
- Name - Supplies a pointer to the name of the file or directory to create,
- which may not be null terminated.
- NameSize - Supplies the size of the name buffer including space for a null
- terminator (which may be a null terminator or may be a garbage
- character).
- Unlinked - Supplies a boolean that receives whether or not the file was
- unlinked. The file may be unlinked even if the call fails.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- SYSTEM_CONTROL_UNLINK UnlinkRequest;
- ASSERT(KeIsSharedExclusiveLockHeldExclusive(DirectoryObject->Lock));
- ASSERT(DirectoryObject->Properties.HardLinkCount != 0);
- UnlinkRequest.DirectoryProperties = &(DirectoryObject->Properties);
- UnlinkRequest.FileProperties = &(FileObject->Properties);
- UnlinkRequest.Name = Name;
- UnlinkRequest.NameSize = NameSize;
- UnlinkRequest.Unlinked = FALSE;
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlUnlink,
- &UnlinkRequest);
- //
- // If the file was successfully unlinked, finish the job even if the IRP
- // failed.
- //
- if (UnlinkRequest.Unlinked != FALSE) {
- //
- // Decrement the hard link count of the file being deleted.
- //
- IopFileObjectDecrementHardLinkCount(FileObject);
- //
- // The directory was modified, update its times.
- //
- IopUpdateFileObjectTime(DirectoryObject, FileObjectModifiedTime);
- }
- *Unlinked = UnlinkRequest.Unlinked;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoGetFileBlockInformation (
- PIO_HANDLE Handle,
- PFILE_BLOCK_INFORMATION *FileBlockInformation
- )
- /*++
- Routine Description:
- This routine gets a list of logical block offsets for the given file or
- partition, comprising the runs of contiguous disk space taken up by the
- file or partition.
- Arguments:
- Handle - Supplies an I/O handle for the file or partition.
- FileBlockInformation - Supplies a pointer that receives a pointer to the
- block information for the file or partition. If this is non-null and a
- partition is queried, then the partition will update the offsets in the
- block information to be logical block offsets for the parent disk.
- Return Value:
- Status code.
- --*/
- {
- SYSTEM_CONTROL_GET_BLOCK_INFORMATION BlockInformation;
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- PIRP Irp;
- PPAGING_IO_HANDLE PagingHandle;
- KSTATUS Status;
- Irp = NULL;
- Status = IoGetDevice(Handle, &Device);
- if (!KSUCCESS(Status)) {
- goto GetBlockInformationEnd;
- }
- if (Handle->HandleType == IoHandleTypePaging) {
- PagingHandle = (PPAGING_IO_HANDLE)Handle;
- Handle = PagingHandle->IoHandle;
- }
- FileObject = Handle->FileObject;
- Irp = IoCreateIrp(Device, IrpMajorSystemControl, 0);
- if (Irp == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetBlockInformationEnd;
- }
- BlockInformation.FileProperties = &(FileObject->Properties);
- BlockInformation.FileBlockInformation = *FileBlockInformation;
- Irp->MinorCode = IrpMinorSystemControlGetBlockInformation;
- Irp->U.SystemControl.SystemContext = &BlockInformation;
- Status = IoSendSynchronousIrp(Irp);
- if (!KSUCCESS(Status)) {
- goto GetBlockInformationEnd;
- }
- Status = IoGetIrpStatus(Irp);
- if (!KSUCCESS(Status)) {
- goto GetBlockInformationEnd;
- }
- *FileBlockInformation = BlockInformation.FileBlockInformation;
- GetBlockInformationEnd:
- if (Irp != NULL) {
- IoDestroyIrp(Irp);
- }
- return Status;
- }
- KERNEL_API
- VOID
- IoDestroyFileBlockInformation (
- PFILE_BLOCK_INFORMATION FileBlockInformation
- )
- /*++
- Routine Description:
- This routine destroys file block information for a file or partition.
- Arguments:
- FileBlockInformation - Supplies a pointer to file block information to be
- destroyed.
- Return Value:
- Status code.
- --*/
- {
- PFILE_BLOCK_ENTRY BlockEntry;
- while (LIST_EMPTY(&(FileBlockInformation->BlockList)) == FALSE) {
- BlockEntry = LIST_VALUE(FileBlockInformation->BlockList.Next,
- FILE_BLOCK_ENTRY,
- ListEntry);
- LIST_REMOVE(&(BlockEntry->ListEntry));
- MmFreeNonPagedPool(BlockEntry);
- }
- MmFreeNonPagedPool(FileBlockInformation);
- return;
- }
- KSTATUS
- IoWriteFileBlocks (
- PFILE_BLOCK_IO_CONTEXT FileContext,
- PIO_BUFFER IoBuffer,
- ULONGLONG Offset,
- UINTN SizeInBytes,
- PUINTN BytesCompleted
- )
- /*++
- Routine Description:
- This routine writes data directly to a file's disk blocks, bypassing the
- filesystem. It is meant for critical code paths, such as writing out the
- crash dump file during a system failure.
- Arguments:
- FileContext - Supplies a pointer to the file block context, including the
- file's block information, the device's block level I/O routines and
- block information.
- IoBuffer - Supplies a pointer to an I/O buffer with the data to write.
- Offset - Supplies the offset, in bytes, into the file where the data is to
- be written.
- SizeInBytes - Supplies the size of the data to write, in bytes.
- BytesCompleted - Supplies a pointer that receives the total number of bytes
- written to the disk.
- Return Value:
- Status code.
- --*/
- {
- UINTN AlignedSize;
- ULONGLONG BlockCount;
- PLIST_ENTRY BlockList;
- ULONGLONG BlockOffset;
- PFILE_BLOCK_ENTRY BlockRun;
- ULONGLONG BlockRunOffset;
- UINTN BlocksCompleted;
- ULONG BlockShift;
- UINTN BlocksRemaining;
- ULONGLONG BlocksThisRound;
- PDISK_BLOCK_IO_WRITE BlockWrite;
- PLIST_ENTRY CurrentEntry;
- KSTATUS Status;
- ASSERT(POWER_OF_2(FileContext->BlockSize) != FALSE);
- BlockWrite = (PDISK_BLOCK_IO_WRITE)FileContext->BlockIoWrite;
- //
- // Align the size up to full blocks. The I/O buffer should be able to
- // handle it.
- //
- AlignedSize = ALIGN_RANGE_UP(SizeInBytes, FileContext->BlockSize);
- ASSERT(MmGetIoBufferSize(IoBuffer) >= AlignedSize);
- //
- // The I/O buffer should be mapped.
- //
- ASSERT(KSUCCESS(MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE)));
- //
- // TODO: Support partial block writes to crash dump files.
- //
- ASSERT(IS_ALIGNED(Offset, FileContext->BlockSize) != FALSE);
- BlockList = &(FileContext->FileBlockInformation->BlockList);
- BlockShift = RtlCountTrailingZeros32(FileContext->BlockSize);
- BlockOffset = Offset >> BlockShift;
- //
- // Find the first block run that this write is targeting.
- //
- BlockCount = 0;
- BlockRun = NULL;
- BlockRunOffset = 0;
- CurrentEntry = BlockList->Next;
- while (CurrentEntry != BlockList) {
- BlockRun = LIST_VALUE(CurrentEntry, FILE_BLOCK_ENTRY, ListEntry);
- if (BlockOffset < (BlockCount + BlockRun->Count)) {
- ASSERT(BlockOffset >= BlockCount);
- BlockRunOffset = BlockOffset - BlockCount;
- break;
- }
- BlockCount += BlockRun->Count;
- CurrentEntry = CurrentEntry->Next;
- BlockRun = NULL;
- }
- //
- // Trusted callers really shouldn't be going beyond the end of the file or
- // the buffer.
- //
- ASSERT(BlockRun != NULL);
- //
- // Loop writing each fragment of the I/O buffer to as many contiguous
- // blocks as possible.
- //
- BlocksRemaining = AlignedSize >> BlockShift;
- while (BlocksRemaining != 0) {
- //
- // Determine how many contiguous blocks can be written this round.
- //
- BlocksThisRound = BlockRun->Count - BlockRunOffset;
- if (BlocksRemaining < BlocksThisRound) {
- BlocksThisRound = BlocksRemaining;
- }
- ASSERT(BlocksThisRound != 0);
- //
- // Send this write down to the disk.
- //
- Status = BlockWrite(FileContext->DiskToken,
- IoBuffer,
- BlockRun->Address + BlockRunOffset,
- (UINTN)BlocksThisRound,
- &BlocksCompleted);
- if (!KSUCCESS(Status)) {
- goto WriteFileBlocksEnd;
- }
- //
- // Update the I/O buffer offset so the next run starts where this left
- // off.
- //
- MmIoBufferIncrementOffset(IoBuffer, BlocksCompleted << BlockShift);
- BlocksRemaining -= BlocksCompleted;
- if (BlocksCompleted != BlocksThisRound) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto WriteFileBlocksEnd;
- }
- //
- // Move to the next block run if this run is exhausted.
- //
- BlockRunOffset += BlocksThisRound;
- if (BlockRunOffset == BlockRun->Count) {
- CurrentEntry = CurrentEntry->Next;
- if (CurrentEntry == BlockList) {
- break;
- }
- BlockRun = LIST_VALUE(CurrentEntry, FILE_BLOCK_ENTRY, ListEntry);
- BlockRunOffset = 0;
- }
- }
- if (BlocksRemaining != 0) {
- Status = STATUS_END_OF_FILE;
- goto WriteFileBlocksEnd;
- }
- Status = STATUS_SUCCESS;
- WriteFileBlocksEnd:
- BlocksCompleted = (AlignedSize >> BlockShift) - BlocksRemaining;
- *BytesCompleted = BlocksCompleted << BlockShift;
- if (*BytesCompleted > SizeInBytes) {
- *BytesCompleted = SizeInBytes;
- }
- if (*BytesCompleted != 0) {
- MmIoBufferDecrementOffset(IoBuffer, *BytesCompleted);
- }
- return Status;
- }
- KSTATUS
- IopSynchronizeBlockDevice (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine sends a sync request to a block device to ensure all data is
- written out to permanent storage.
- Arguments:
- Device - Supplies a pointer to the device to send the synchronize request
- to.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlSynchronize,
- NULL);
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoLoadFile (
- PSTR Path,
- ULONG PathLength,
- PLOAD_FILE_COMPLETION_ROUTINE CompletionRoutine,
- PVOID CompletionContext
- )
- /*++
- Routine Description:
- This routine asynchronously loads the file at the given path. The path can
- either be absolute or relative. For the kernel process, relative paths are
- in relative to the system volume's drivers directory. The supplied
- completion routine is invoked when the load finishes.
- Arguments:
- Path - Supplies a pointer to the path to the file. It can either be an
- absolute or relative path. Relative paths for the kernel process are
- relative to the system partition's drivers directory.
- PathLength - Supplies the length of the path buffer in bytes, including the
- null terminator.
- CompletionRoutine - Supplies a pointer to the callback routine to notify
- when the load is complete.
- CompletionContext - Supplies a pointer to an opaque context that will be
- passed to the completion routine along with the loaded file.
- Return Value:
- Status code.
- --*/
- {
- UINTN BytesCompleted;
- ULONGLONG FileSize;
- PLOADED_FILE NewFile;
- KSTATUS Status;
- NewFile = NULL;
- //
- // Fail if the path is NULL or has no length.
- //
- if ((Path == NULL) || (PathLength < 2)) {
- Status = STATUS_INVALID_PARAMETER;
- goto LoadFileEnd;
- }
- //
- // Allocate a new file structure to store the loaded file information.
- //
- NewFile = MmAllocatePagedPool(sizeof(LOADED_FILE), IO_ALLOCATION_TAG);
- if (NewFile == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto LoadFileEnd;
- }
- RtlZeroMemory(NewFile, sizeof(LOADED_FILE));
- NewFile->Version = LOADED_FILE_VERSION;
- //
- // Open the file using the given path. If it is a relative path, then it
- // will search in the process's current directory. For the kernel, that
- // is the drivers directory on the system partition.
- //
- Status = IoOpen(TRUE,
- NULL,
- Path,
- PathLength,
- IO_ACCESS_READ | IO_ACCESS_EXECUTE,
- 0,
- FILE_PERMISSION_NONE,
- &(NewFile->IoHandle));
- if (!KSUCCESS(Status)) {
- goto LoadFileEnd;
- }
- //
- // Get the file size and allocate an I/O buffer to contain it.
- //
- Status = IoGetFileSize(NewFile->IoHandle, &FileSize);
- if (!KSUCCESS(Status)) {
- goto LoadFileEnd;
- }
- if (FileSize > MAX_UINTN) {
- Status = STATUS_NOT_SUPPORTED;
- goto LoadFileEnd;
- }
- NewFile->Length = (UINTN)FileSize;
- //
- // Create an I/O buffer that can support the read.
- //
- NewFile->IoBuffer = MmAllocateUninitializedIoBuffer(NewFile->Length, 0);
- if (NewFile->IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto LoadFileEnd;
- }
- //
- // TODO: Convert file load reads to asynchronous I/O.
- //
- Status = IoReadAtOffset(NewFile->IoHandle,
- NewFile->IoBuffer,
- 0,
- NewFile->Length,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesCompleted,
- NULL);
- if (!KSUCCESS(Status)) {
- goto LoadFileEnd;
- }
- if (BytesCompleted != NewFile->Length) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto LoadFileEnd;
- }
- //
- // With success on the horizon, call the callback to signal completion.
- //
- CompletionRoutine(CompletionContext, NewFile);
- LoadFileEnd:
- if (!KSUCCESS(Status)) {
- if (NewFile != NULL) {
- IoUnloadFile(NewFile);
- NewFile = NULL;
- }
- }
- return Status;
- }
- KERNEL_API
- VOID
- IoUnloadFile (
- PLOADED_FILE File
- )
- /*++
- Routine Description:
- This routine unloads the given file.
- Arguments:
- File - Supplies a pointer to the file to unload.
- Return Value:
- None.
- --*/
- {
- if (File->IoBuffer != NULL) {
- MmFreeIoBuffer(File->IoBuffer);
- }
- if (File->IoHandle != NULL) {
- IoClose(File->IoHandle);
- }
- MmFreePagedPool(File);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- IopOpenPagingDevice (
- PDEVICE Device,
- ULONG Access,
- ULONG Flags,
- PPAGING_IO_HANDLE *Handle,
- PULONG IoOffsetAlignment,
- PULONG IoSizeAlignment,
- PULONGLONG IoCapacity
- )
- /*++
- Routine Description:
- This routine opens a block device for paging.
- Arguments:
- Device - Supplies a pointer to the device to open.
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- Handle - Supplies a pointer where a pointer to the open I/O handle will be
- returned on success.
- IoOffsetAlignment - Supplies a pointer where the alignment requirement in
- bytes will be returned for all I/O offsets.
- IoSizeAlignment - Supplies a pointer where the alignment requirement for
- the size of all transfers (the block size) will be returned for all
- I/O requests.
- IoCapacity - Supplies the device's total size, in bytes.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- PIO_HANDLE IoHandle;
- PPAGING_IO_HANDLE PagingHandle;
- KSTATUS Status;
- IoHandle = NULL;
- PagingHandle = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Allocate the basic structure.
- //
- PagingHandle = MmAllocateNonPagedPool(sizeof(PAGING_IO_HANDLE),
- IO_ALLOCATION_TAG);
- if (PagingHandle == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto OpenPagingDeviceEnd;
- }
- RtlZeroMemory(PagingHandle, sizeof(PAGING_IO_HANDLE));
- PagingHandle->HandleType = IoHandleTypePaging;
- //
- // Open the device normally.
- //
- Status = IopOpenDevice(Device, Access, Flags, &IoHandle);
- if (!KSUCCESS(Status)) {
- goto OpenPagingDeviceEnd;
- }
- //
- // Grab some needed parameters from the paged file object structure.
- //
- FileObject = IoHandle->FileObject;
- PagingHandle->IoHandle = IoHandle;
- PagingHandle->Device = FileObject->Device;
- PagingHandle->DeviceContext = IoHandle->DeviceContext;
- READ_INT64_SYNC(&(FileObject->Properties.FileSize),
- &(PagingHandle->Capacity));
- PagingHandle->OffsetAlignment = FileObject->Properties.BlockSize;
- PagingHandle->SizeAlignment = PagingHandle->OffsetAlignment;
- *IoOffsetAlignment = PagingHandle->OffsetAlignment;
- *IoSizeAlignment = PagingHandle->SizeAlignment;
- *IoCapacity = PagingHandle->Capacity;
- Status = STATUS_SUCCESS;
- OpenPagingDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (IoHandle != NULL) {
- IoClose(IoHandle);
- }
- if (PagingHandle != NULL) {
- MmFreeNonPagedPool(PagingHandle);
- }
- PagingHandle = NULL;
- }
- *Handle = PagingHandle;
- return Status;
- }
- KSTATUS
- IopClosePagingObject (
- PPAGING_IO_HANDLE Handle
- )
- /*++
- Routine Description:
- This routine closes a page file or device.
- Arguments:
- Handle - Supplies the handle returned upon opening the page file or device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- //
- // This routine is called from IoClose, but assert here that it will not
- // recurse more than once.
- //
- ASSERT(Handle->HandleType == IoHandleTypePaging);
- ASSERT(Handle->IoHandle->HandleType == IoHandleTypeDefault);
- Status = IoClose(Handle->IoHandle);
- if (!KSUCCESS(Status)) {
- goto ClosePagingObjectEnd;
- }
- MmFreeNonPagedPool(Handle);
- Status = STATUS_SUCCESS;
- ClosePagingObjectEnd:
- return Status;
- }
- KSTATUS
- IopCreateAnonymousObject (
- ULONG Access,
- ULONG Flags,
- IO_OBJECT_TYPE TypeOverride,
- PVOID OverrideParameter,
- FILE_PERMISSIONS CreatePermissions,
- PPATH_POINT PathPoint
- )
- /*++
- Routine Description:
- This routine creates an anonymous I/O object, one that is not visible
- in the global path system.
- Arguments:
- Access - Supplies the desired access permissions to the object. See
- IO_ACCESS_* definitions.
- Flags - Supplies a bitfield of flags governing the behavior of the handle.
- See OPEN_FLAG_* definitions.
- TypeOverride - Supplies an object type that the regular file should be
- converted to. Supply the invalid object type to specify no override.
- OverrideParameter - Supplies an optional parameter to send along with the
- override type.
- CreatePermissions - Supplies the initial permissions to create the entry
- with.
- PathPoint - Supplies a pointer that receives the path entry and mount point
- of the newly minted path point.
- Return Value:
- Status code.
- --*/
- {
- PFILE_OBJECT FileObject;
- PPATH_ENTRY PathEntry;
- KSTATUS Status;
- FileObject = NULL;
- PathEntry = NULL;
- Status = IopCreateSpecialIoObject(Flags,
- TypeOverride,
- OverrideParameter,
- CreatePermissions,
- &FileObject);
- if (!KSUCCESS(Status)) {
- goto CreateAnonymousObjectEnd;
- }
- //
- // Create an anonymous path entry for this object.
- //
- PathEntry = IopCreateAnonymousPathEntry(FileObject);
- if (PathEntry == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateAnonymousObjectEnd;
- }
- FileObject = NULL;
- CreateAnonymousObjectEnd:
- if (!KSUCCESS(Status)) {
- if (PathEntry != NULL) {
- IoPathEntryReleaseReference(PathEntry);
- PathEntry = NULL;
- }
- }
- if (FileObject != NULL) {
- IopFileObjectReleaseReference(FileObject);
- }
- PathPoint->PathEntry = PathEntry;
- PathPoint->MountPoint = NULL;
- return Status;
- }
- KSTATUS
- IopPerformIoOperation (
- PIO_HANDLE Handle,
- PIO_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine reads from or writes to a file or device.
- Arguments:
- Handle - Supplies the open I/O handle.
- Context - Supplies a pointer to the I/O context.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- PFILE_OBJECT FileObject;
- KSTATUS Status;
- ASSERT((Context->Flags & IO_FLAG_NO_ALLOCATE) == 0);
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(Context->BytesCompleted == 0);
- ASSERT(Context->IoBuffer != NULL);
- FileObject = Handle->FileObject;
- if (FileObject == NULL) {
- Status = STATUS_NO_SUCH_DEVICE;
- goto PerformIoOperationEnd;
- }
- //
- // Non-blocking handles always have a timeout of zero.
- //
- if ((Handle->OpenFlags & OPEN_FLAG_NON_BLOCKING) != 0) {
- Context->TimeoutInMilliseconds = 0;
- }
- if ((Handle->OpenFlags & OPEN_FLAG_SYNCHRONIZED) != 0) {
- Context->Flags |= IO_FLAG_DATA_SYNCHRONIZED;
- }
- //
- // Fail if the caller hadn't opened the file with the correct access.
- //
- if (Context->Write != FALSE) {
- if ((Handle->Access & IO_ACCESS_WRITE) == 0) {
- Status = STATUS_INVALID_HANDLE;
- goto PerformIoOperationEnd;
- }
- } else {
- if ((Handle->Access & (IO_ACCESS_READ | IO_ACCESS_EXECUTE)) == 0) {
- Status = STATUS_INVALID_HANDLE;
- goto PerformIoOperationEnd;
- }
- }
- //
- // Perform the operation based on the file object type.
- //
- switch (FileObject->Properties.Type) {
- case IoObjectBlockDevice:
- case IoObjectRegularFile:
- case IoObjectSharedMemoryObject:
- case IoObjectSymbolicLink:
- Status = IopPerformCacheableIoOperation(Handle, Context);
- break;
- case IoObjectCharacterDevice:
- Status = IopPerformCharacterDeviceIoOperation(Handle, Context);
- break;
- case IoObjectRegularDirectory:
- Status = IopPerformDirectoryIoOperation(Handle, Context);
- break;
- case IoObjectPipe:
- Status = IopPerformPipeIoOperation(Handle, Context);
- break;
- case IoObjectSocket:
- Status = IopPerformSocketIoOperation(Handle, Context);
- break;
- case IoObjectTerminalMaster:
- Status = IopPerformTerminalMasterIoOperation(Handle, Context);
- break;
- case IoObjectTerminalSlave:
- Status = IopPerformTerminalSlaveIoOperation(Handle, Context);
- break;
- case IoObjectObjectDirectory:
- Status = IopPerformObjectIoOperation(Handle, Context);
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_NOT_SUPPORTED;
- goto PerformIoOperationEnd;
- }
- PerformIoOperationEnd:
- ASSERT(Context->BytesCompleted <= Context->SizeInBytes);
- return Status;
- }
- KSTATUS
- IopPerformPagingIoOperation (
- PPAGING_IO_HANDLE Handle,
- PIO_CONTEXT Context,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine reads from or writes to a file or device.
- Arguments:
- Handle - Supplies the open I/O handle.
- Context - Supplies a pointer to the paging I/O context.
- Irp - Supplies a pointer to the IRP to use for this I/O.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- KSTATUS Status;
- //
- // Reset the paging IRP. The IRP should never be null.
- //
- ASSERT(Irp != NULL);
- ASSERT(Context->BytesCompleted == 0);
- ASSERT(Handle->HandleType == IoHandleTypePaging);
- ASSERT(Context->IoBuffer != NULL);
- ASSERT(IS_ALIGNED(Context->SizeInBytes, MmPageSize()) != FALSE);
- IoInitializeIrp(Irp);
- ASSERT(Irp->MajorCode == IrpMajorIo);
- if (Context->Write != FALSE) {
- Irp->MinorCode = IrpMinorIoWrite;
- } else {
- Irp->MinorCode = IrpMinorIoRead;
- }
- ASSERT((Context->Offset + Context->SizeInBytes) <= Handle->Capacity);
- //
- // Use the supplied I/O buffer directly. This code path should only be
- // reached by trusted callers. The buffer should be properly aligned, etc.
- //
- Irp->U.ReadWrite.IoBuffer = Context->IoBuffer;
- Irp->U.ReadWrite.DeviceContext = Handle->DeviceContext;
- Irp->U.ReadWrite.IoFlags = Context->Flags;
- Irp->U.ReadWrite.TimeoutInMilliseconds = WAIT_TIME_INDEFINITE;
- Irp->U.ReadWrite.IoOffset = Context->Offset;
- Irp->U.ReadWrite.IoSizeInBytes = Context->SizeInBytes;
- Irp->U.ReadWrite.IoBytesCompleted = 0;
- Status = IoSendSynchronousIrp(Irp);
- if (!KSUCCESS(Status)) {
- goto PerformPageFileIoOperationEnd;
- }
- //
- // Update the global statistics.
- //
- if (Handle->Device->Header.Type == ObjectDevice) {
- if (Context->Write != FALSE) {
- RtlAtomicAdd64(&(IoGlobalStatistics.PagingBytesWritten),
- Irp->U.ReadWrite.IoBytesCompleted);
- } else {
- RtlAtomicAdd64(&(IoGlobalStatistics.PagingBytesRead),
- Irp->U.ReadWrite.IoBytesCompleted);
- }
- }
- if (Irp->U.ReadWrite.IoBytesCompleted != Irp->U.ReadWrite.IoSizeInBytes) {
- ASSERT(FALSE);
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto PerformPageFileIoOperationEnd;
- }
- Status = IoGetIrpStatus(Irp);
- PerformPageFileIoOperationEnd:
- Context->BytesCompleted = Irp->U.ReadWrite.IoBytesCompleted;
- return Status;
- }
- KSTATUS
- IopPerformCharacterDeviceIoOperation (
- PIO_HANDLE Handle,
- PIO_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine performeds read and write I/O to a character device.
- Arguments:
- Handle - Supplies a pointer to the I/O handle.
- Context - Supplies a pointer to the I/O context.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- IRP_MINOR_CODE MinorCode;
- IRP_READ_WRITE Parameters;
- KSTATUS Status;
- ASSERT(Context->IoBuffer != NULL);
- FileObject = Handle->FileObject;
- ASSERT(FileObject->Properties.Type == IoObjectCharacterDevice);
- //
- // Initialize the parameters for the I/O IRP. The offset does not matter
- // for character devices. Set it to 0, always.
- //
- Parameters.IoBuffer = Context->IoBuffer;
- Parameters.DeviceContext = Handle->DeviceContext;
- Parameters.IoFlags = Context->Flags;
- Parameters.TimeoutInMilliseconds = Context->TimeoutInMilliseconds;
- Parameters.IoSizeInBytes = Context->SizeInBytes;
- Parameters.IoBytesCompleted = 0;
- Parameters.IoOffset = 0;
- Parameters.NewIoOffset = 0;
- Parameters.FileProperties = &(FileObject->Properties);
- Device = FileObject->Device;
- ASSERT(IS_DEVICE_OR_VOLUME(Device));
- if (Context->Write != FALSE) {
- MinorCode = IrpMinorIoWrite;
- } else {
- MinorCode = IrpMinorIoRead;
- }
- //
- // Fire off the I/O.
- //
- Status = IopSendIoIrp(Device, MinorCode, &Parameters);
- Context->BytesCompleted = Parameters.IoBytesCompleted;
- return Status;
- }
- KSTATUS
- IopPerformDirectoryIoOperation (
- PIO_HANDLE Handle,
- PIO_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine performs I/O operations on regular directory handles. Only
- read operations should be requested from a directory handle. It is
- important to note that the supplied offset is a directory entry offset and
- not a byte offset.
- Arguments:
- Handle - Supplies a pointer to the I/O handle.
- Context - Supplies a pointer to the I/O context.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- PDEVICE Device;
- PFILE_OBJECT FileObject;
- BOOL LockHeldExclusive;
- IRP_READ_WRITE Parameters;
- KSTATUS Status;
- ASSERT(Context->IoBuffer != NULL);
- ASSERT((Context->Write == FALSE) && (Context->Flags == 0));
- Context->BytesCompleted = 0;
- Parameters.IoBytesCompleted = Context->BytesCompleted;
- FileObject = Handle->FileObject;
- ASSERT(FileObject != NULL);
- KeAcquireSharedExclusiveLockShared(FileObject->Lock);
- LockHeldExclusive = FALSE;
- if (Context->Offset != IO_OFFSET_NONE) {
- Parameters.IoOffset = Context->Offset;
- } else {
- Parameters.IoOffset =
- RtlAtomicOr64((PULONGLONG)&(Handle->CurrentOffset), 0);
- }
- Parameters.NewIoOffset = Parameters.IoOffset;
- if ((Handle->OpenFlags & OPEN_FLAG_DIRECTORY) == 0) {
- Status = STATUS_FILE_IS_DIRECTORY;
- goto PerformDirectoryIoOperationEnd;
- }
- //
- // If this was a directory, add the relative entries.
- //
- Status = IopAddRelativeDirectoryEntries(Handle,
- &(Parameters.IoOffset),
- Context->IoBuffer,
- Context->SizeInBytes,
- &(Parameters.IoBytesCompleted));
- Parameters.NewIoOffset = Parameters.IoOffset;
- if (!KSUCCESS(Status)) {
- goto PerformDirectoryIoOperationEnd;
- }
- //
- // On success, both relative directory entries were added. Now off to the
- // driver to add more.
- //
- ASSERT(Parameters.IoOffset >= DIRECTORY_CONTENTS_OFFSET);
- //
- // This I/O buffer does not need to be locked in memory at the moment.
- // If some future file system requires use of the physical addresses,
- // then it needs to be locked in memory.
- //
- Parameters.IoBuffer = Context->IoBuffer;
- Parameters.DeviceContext = Handle->DeviceContext;
- Parameters.IoFlags = Context->Flags;
- Parameters.TimeoutInMilliseconds = Context->TimeoutInMilliseconds;
- Parameters.IoSizeInBytes = Context->SizeInBytes;
- Parameters.FileProperties = &(FileObject->Properties);
- //
- // Acquire the file lock in shared mode and fire off the I/O!
- //
- Device = FileObject->Device;
- ASSERT(IS_DEVICE_OR_VOLUME(Device));
- Status = IopSendIoIrp(Device, IrpMinorIoRead, &Parameters);
- if (KSUCCESS(Status) || (Status == STATUS_END_OF_FILE)) {
- if ((Handle->OpenFlags & OPEN_FLAG_NO_ACCESS_TIME) == 0) {
- ASSERT(LockHeldExclusive == FALSE);
- KeSharedExclusiveLockConvertToExclusive(FileObject->Lock);
- LockHeldExclusive = TRUE;
- IopUpdateFileObjectTime(FileObject, FileObjectAccessTime);
- }
- }
- PerformDirectoryIoOperationEnd:
- //
- // Adjust the current offset.
- //
- if (Context->Offset == IO_OFFSET_NONE) {
- RtlAtomicExchange64((PULONGLONG)&(Handle->CurrentOffset),
- Parameters.NewIoOffset);
- }
- if (LockHeldExclusive != FALSE) {
- KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
- } else {
- KeReleaseSharedExclusiveLockShared(FileObject->Lock);
- }
- //
- // Modify the file IDs of any directory entries that are mount points.
- // This needs to happen for any directory entries read from disk.
- //
- if (Parameters.IoBytesCompleted != 0) {
- IopFixMountPointDirectoryEntries(Handle,
- Context->IoBuffer,
- Parameters.IoBytesCompleted);
- }
- Context->BytesCompleted = Parameters.IoBytesCompleted;
- return Status;
- }
- KSTATUS
- IopAddRelativeDirectoryEntries (
- PIO_HANDLE Handle,
- PIO_OFFSET Offset,
- PIO_BUFFER IoBuffer,
- UINTN BufferSize,
- PUINTN BytesConsumed
- )
- /*++
- Routine Description:
- This routine adds the relative . and .. directory entries to a directory
- read operation.
- Arguments:
- Handle - Supplies the open I/O handle.
- Offset - Supplies a pointer to the offset to read from. On return contains
- the new offset.
- IoBuffer - Supplies a pointer to the I/O buffer that will contain the added
- relative directory entries on output.
- BufferSize - Supplies the size of the I/O buffer, in bytes.
- BytesConsumed - Supplies the a pointer that on input contains the number
- of bytes in the buffer that have already been used. On output, it will
- contain the updated number of bytes used.
- Return Value:
- Status code. A failing status code does not necessarily mean no I/O made it
- in or out. Check the bytes completed value to find out how much occurred.
- --*/
- {
- UINTN BytesAvailable;
- PDIRECTORY_ENTRY Entry;
- ULONG EntrySize;
- PFILE_OBJECT FileObject;
- IO_OFFSET FileOffset;
- UCHAR LocalBuffer[sizeof(DIRECTORY_ENTRY) + sizeof("..") + 8];
- PATH_POINT Parent;
- PKPROCESS Process;
- PPATH_POINT Root;
- KSTATUS Status;
- ASSERT(BufferSize >= *BytesConsumed);
- BytesAvailable = BufferSize - *BytesConsumed;
- FileOffset = *Offset;
- Entry = (PDIRECTORY_ENTRY)LocalBuffer;
- Status = STATUS_MORE_PROCESSING_REQUIRED;
- //
- // Tack on a . and a .. entry. Use reserved file offsets to remember
- // which directory entries were reported.
- //
- if (FileOffset == DIRECTORY_OFFSET_DOT) {
- EntrySize = ALIGN_RANGE_UP(sizeof(DIRECTORY_ENTRY) + sizeof("."), 8);
- if (BytesAvailable > EntrySize) {
- Entry->Size = EntrySize;
- Entry->Type = IoObjectRegularDirectory;
- Entry->NextOffset = DIRECTORY_OFFSET_DOT_DOT;
- FileObject = Handle->FileObject;
- ASSERT(FileObject == Handle->PathPoint.PathEntry->FileObject);
- Entry->FileId = FileObject->Properties.FileId;
- RtlCopyMemory(Entry + 1, ".", sizeof("."));
- Status = MmCopyIoBufferData(IoBuffer,
- Entry,
- *BytesConsumed,
- EntrySize,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto AddRelativeDirectoryEntriesEnd;
- }
- *BytesConsumed += EntrySize;
- BytesAvailable -= EntrySize;
- FileOffset = Entry->NextOffset;
- }
- }
- if (FileOffset == DIRECTORY_OFFSET_DOT_DOT) {
- EntrySize = ALIGN_RANGE_UP(sizeof(DIRECTORY_ENTRY) + sizeof(".."), 8);
- if (BytesAvailable > EntrySize) {
- Entry->Size = EntrySize;
- Entry->Type = IoObjectRegularDirectory;
- Entry->NextOffset = DIRECTORY_CONTENTS_OFFSET;
- //
- // Get the parent path point. Provide the process root to prevent
- // leaking a file ID outside of the root. This does not need to
- // hold the process' path locks because changing roots is required
- // to be a single-threaded operation.
- //
- Root = NULL;
- Process = PsGetCurrentProcess();
- if (Process->Paths.Root.PathEntry != NULL) {
- Root = (PPATH_POINT)&(Process->Paths.Root);
- }
- IopGetParentPathPoint(Root, &(Handle->PathPoint), &Parent);
- FileObject = Parent.PathEntry->FileObject;
- IO_PATH_POINT_RELEASE_REFERENCE(&Parent);
- Entry->FileId = FileObject->Properties.FileId;
- RtlCopyMemory(Entry + 1, "..", sizeof(".."));
- Status = MmCopyIoBufferData(IoBuffer,
- Entry,
- *BytesConsumed,
- EntrySize,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto AddRelativeDirectoryEntriesEnd;
- }
- *BytesConsumed += EntrySize;
- BytesAvailable -= EntrySize;
- FileOffset = Entry->NextOffset;
- }
- }
- if (FileOffset >= DIRECTORY_CONTENTS_OFFSET) {
- Status = STATUS_SUCCESS;
- }
- AddRelativeDirectoryEntriesEnd:
- *Offset = FileOffset;
- return Status;
- }
- VOID
- IopFixMountPointDirectoryEntries (
- PIO_HANDLE Handle,
- PIO_BUFFER IoBuffer,
- UINTN BufferSize
- )
- /*++
- Routine Description:
- This routine searches for mount points within the provided directory and
- patches up the directory entries in the buffer to reflect those mount
- points.
- Arguments:
- Handle - Supplies the open I/O handle.
- IoBuffer - Supplies a pointer to the buffer filled with directory entries.
- BufferSize - Supplies the size of the directory entries buffer.
- Return Value:
- None.
- --*/
- {
- UINTN BytesRemaining;
- PLIST_ENTRY CurrentEntry;
- DIRECTORY_ENTRY DirectoryEntry;
- BOOL FixRequired;
- PMOUNT_POINT MountPoint;
- UINTN Offset;
- FILE_ID OriginalFileId;
- PFILE_OBJECT OriginalFileObject;
- PPATH_POINT PathPoint;
- KSTATUS Status;
- FILE_ID TargetFileId;
- PFILE_OBJECT TargetFileObject;
- PathPoint = &(Handle->PathPoint);
- //
- // If the current mount point has no children, then there is nothing to
- // patch.
- //
- if (LIST_EMPTY(&(PathPoint->MountPoint->ChildListHead)) != FALSE) {
- return;
- }
- //
- // The current mount point has child mounts, but their root path entries
- // are not necessarily children of the given current path entry. Check to
- // make sure at least one fix up is required.
- //
- FixRequired = FALSE;
- KeAcquireSharedExclusiveLockShared(IoMountLock);
- CurrentEntry = PathPoint->MountPoint->ChildListHead.Next;
- while (CurrentEntry != &(PathPoint->MountPoint->ChildListHead)) {
- MountPoint = LIST_VALUE(CurrentEntry, MOUNT_POINT, SiblingListEntry);
- if (MountPoint->MountEntry->Parent == PathPoint->PathEntry) {
- FixRequired = TRUE;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // If no mount points were direct children of the current path, then exit.
- //
- if (FixRequired == FALSE) {
- goto FixMountPointDirectoryEntriesEnd;
- }
- //
- // Otherwise, bite the bullet and iterate over the whole directory. Keep in
- // mind that the mount point's child list may contain multiple entries that
- // mount on top of the same file, so it should not be the primary loop.
- //
- Offset = 0;
- BytesRemaining = BufferSize;
- while (BytesRemaining >= sizeof(DIRECTORY_ENTRY)) {
- Status = MmCopyIoBufferData(IoBuffer,
- &DirectoryEntry,
- Offset,
- sizeof(DIRECTORY_ENTRY),
- FALSE);
- if (!KSUCCESS(Status)) {
- goto FixMountPointDirectoryEntriesEnd;
- }
- OriginalFileId = DirectoryEntry.FileId;
- TargetFileObject = NULL;
- CurrentEntry = PathPoint->MountPoint->ChildListHead.Next;
- while (CurrentEntry != &(PathPoint->MountPoint->ChildListHead)) {
- MountPoint = LIST_VALUE(CurrentEntry,
- MOUNT_POINT,
- SiblingListEntry);
- OriginalFileObject = MountPoint->MountEntry->FileObject;
- if (OriginalFileObject->Properties.FileId == OriginalFileId) {
- TargetFileObject = MountPoint->TargetEntry->FileObject;
- TargetFileId = TargetFileObject->Properties.FileId;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (TargetFileObject != NULL) {
- DirectoryEntry.FileId = TargetFileId;
- MmCopyIoBufferData(IoBuffer,
- &DirectoryEntry,
- Offset,
- sizeof(DIRECTORY_ENTRY),
- TRUE);
- }
- Offset += DirectoryEntry.Size;
- //
- // Assert that the subtraction will not underflow.
- //
- ASSERT((BufferSize - Offset) <= BytesRemaining);
- BytesRemaining = BufferSize - Offset;
- }
- FixMountPointDirectoryEntriesEnd:
- KeReleaseSharedExclusiveLockShared(IoMountLock);
- return;
- }
|