iobase.c 157 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. iobase.c
  5. Abstract:
  6. This module implements the base I/O API (open, close, read, write).
  7. Author:
  8. Evan Green 25-Apr-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include <minoca/intrface/disk.h>
  17. #include "iop.h"
  18. #include "pagecach.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. #define IO_RENAME_ATTEMPTS_MAX 10000
  23. //
  24. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. //
  27. // ----------------------------------------------- Internal Function Prototypes
  28. //
  29. KSTATUS
  30. IopOpenPagingDevice (
  31. PDEVICE Device,
  32. ULONG Access,
  33. ULONG Flags,
  34. PPAGING_IO_HANDLE *Handle,
  35. PULONG IoOffsetAlignment,
  36. PULONG IoSizeAlignment,
  37. PULONGLONG IoCapacity
  38. );
  39. KSTATUS
  40. IopClosePagingObject (
  41. PPAGING_IO_HANDLE Handle
  42. );
  43. KSTATUS
  44. IopCreateAnonymousObject (
  45. ULONG Access,
  46. ULONG Flags,
  47. IO_OBJECT_TYPE TypeOverride,
  48. PVOID OverrideParameter,
  49. FILE_PERMISSIONS CreatePermissions,
  50. PPATH_POINT PathPoint
  51. );
  52. KSTATUS
  53. IopPerformIoOperation (
  54. PIO_HANDLE Handle,
  55. PIO_CONTEXT Context
  56. );
  57. KSTATUS
  58. IopPerformPagingIoOperation (
  59. PPAGING_IO_HANDLE Handle,
  60. PIO_CONTEXT Context,
  61. PIRP Irp
  62. );
  63. KSTATUS
  64. IopPerformCharacterDeviceIoOperation (
  65. PIO_HANDLE Handle,
  66. PIO_CONTEXT Context
  67. );
  68. KSTATUS
  69. IopPerformDirectoryIoOperation (
  70. PIO_HANDLE Handle,
  71. PIO_CONTEXT Context
  72. );
  73. KSTATUS
  74. IopAddRelativeDirectoryEntries (
  75. PIO_HANDLE Handle,
  76. PIO_OFFSET Offset,
  77. PIO_BUFFER IoBuffer,
  78. UINTN BufferSize,
  79. PUINTN BytesConsumed
  80. );
  81. VOID
  82. IopFixMountPointDirectoryEntries (
  83. PIO_HANDLE Handle,
  84. PIO_BUFFER IoBuffer,
  85. UINTN BufferSize
  86. );
  87. //
  88. // -------------------------------------------------------------------- Globals
  89. //
  90. //
  91. // Store the global I/O statistics.
  92. //
  93. IO_GLOBAL_STATISTICS IoGlobalStatistics;
  94. //
  95. // Set this boolean to print all open calls.
  96. //
  97. BOOL IoDebugPrintOpens;
  98. //
  99. // ------------------------------------------------------------------ Functions
  100. //
  101. KERNEL_API
  102. KSTATUS
  103. IoOpen (
  104. BOOL FromKernelMode,
  105. PIO_HANDLE Directory,
  106. PSTR Path,
  107. ULONG PathLength,
  108. ULONG Access,
  109. ULONG Flags,
  110. FILE_PERMISSIONS CreatePermissions,
  111. PIO_HANDLE *Handle
  112. )
  113. /*++
  114. Routine Description:
  115. This routine opens a file, device, pipe, or other I/O object.
  116. Arguments:
  117. FromKernelMode - Supplies a boolean indicating the request is coming from
  118. kernel mode.
  119. Directory - Supplies an optional pointer to an open handle to a directory
  120. for relative paths. Supply NULL to use the current working directory.
  121. Path - Supplies a pointer to the path to open.
  122. PathLength - Supplies the length of the path buffer in bytes, including the
  123. null terminator.
  124. Access - Supplies the desired access permissions to the object. See
  125. IO_ACCESS_* definitions.
  126. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  127. See OPEN_FLAG_* definitions.
  128. CreatePermissions - Supplies the permissions to apply for a created file.
  129. Handle - Supplies a pointer where a pointer to the open I/O handle will be
  130. returned on success.
  131. Return Value:
  132. Status code.
  133. --*/
  134. {
  135. KSTATUS Status;
  136. if ((Flags & OPEN_FLAG_SHARED_MEMORY) != 0) {
  137. Status = IopOpenSharedMemoryObject(Path,
  138. PathLength,
  139. Access,
  140. Flags,
  141. CreatePermissions,
  142. Handle);
  143. } else {
  144. Status = IopOpen(FromKernelMode,
  145. Directory,
  146. Path,
  147. PathLength,
  148. Access,
  149. Flags,
  150. IoObjectInvalid,
  151. NULL,
  152. CreatePermissions,
  153. Handle);
  154. }
  155. if (IoDebugPrintOpens != FALSE) {
  156. RtlDebugPrint("Open %s: %x\n", Path, Status);
  157. }
  158. return Status;
  159. }
  160. KERNEL_API
  161. KSTATUS
  162. IoOpenDevice (
  163. PDEVICE Device,
  164. ULONG Access,
  165. ULONG Flags,
  166. PIO_HANDLE *Handle,
  167. PULONG IoOffsetAlignment,
  168. PULONG IoSizeAlignment,
  169. PULONGLONG IoCapacity
  170. )
  171. /*++
  172. Routine Description:
  173. This routine opens a device. If the given device is the device meant to
  174. hold the page file, this routine does not prepare the returned I/O handle
  175. for paging operations.
  176. Arguments:
  177. Device - Supplies a pointer to a device to open.
  178. Access - Supplies the desired access permissions to the object. See
  179. IO_ACCESS_* definitions.
  180. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  181. See OPEN_FLAG_* definitions.
  182. Handle - Supplies a pointer that receives the open I/O handle.
  183. IoOffsetAlignment - Supplies a pointer where the alignment requirement in
  184. bytes will be returned for all I/O offsets.
  185. IoSizeAlignment - Supplies a pointer where the alignment requirement for
  186. the size of all transfers (the block size) will be returned for all
  187. I/O requests.
  188. IoCapacity - Supplies the device's total size, in bytes.
  189. Return Value:
  190. Status code.
  191. --*/
  192. {
  193. PFILE_OBJECT FileObject;
  194. PIO_HANDLE IoHandle;
  195. ULONGLONG LocalFileSize;
  196. KSTATUS Status;
  197. ASSERT(KeGetRunLevel() == RunLevelLow);
  198. IoHandle = NULL;
  199. if ((Flags & OPEN_FLAG_PAGING_DEVICE) != 0) {
  200. Status = IopOpenPagingDevice(Device,
  201. Access,
  202. Flags,
  203. (PPAGING_IO_HANDLE *)&IoHandle,
  204. IoOffsetAlignment,
  205. IoSizeAlignment,
  206. IoCapacity);
  207. } else {
  208. //
  209. // Open the device normally.
  210. //
  211. Status = IopOpenDevice(Device, Access, Flags, &IoHandle);
  212. if (!KSUCCESS(Status)) {
  213. goto OpenDeviceEnd;
  214. }
  215. //
  216. // Return the requested data.
  217. //
  218. FileObject = IoHandle->FileObject;
  219. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &LocalFileSize);
  220. if (IoOffsetAlignment != NULL) {
  221. *IoOffsetAlignment = FileObject->Properties.BlockSize;
  222. }
  223. if (IoSizeAlignment != NULL) {
  224. *IoSizeAlignment = FileObject->Properties.BlockSize;
  225. }
  226. if (IoCapacity != NULL) {
  227. *IoCapacity = LocalFileSize;
  228. }
  229. Status = STATUS_SUCCESS;
  230. }
  231. OpenDeviceEnd:
  232. ASSERT((KSUCCESS(Status)) || (IoHandle == NULL));
  233. *Handle = IoHandle;
  234. return Status;
  235. }
  236. KERNEL_API
  237. BOOL
  238. IoIsPagingDevice (
  239. PDEVICE Device
  240. )
  241. /*++
  242. Routine Description:
  243. This routine determines whether or not paging is enabled on the given
  244. device.
  245. Arguments:
  246. Device - Supplies a pointer to a device.
  247. Return Value:
  248. Returns TRUE if paging is enabled on the device, or FALSE otherwise.
  249. --*/
  250. {
  251. if ((Device->Flags & DEVICE_FLAG_PAGING_DEVICE) != 0) {
  252. return TRUE;
  253. }
  254. return FALSE;
  255. }
  256. KERNEL_API
  257. KSTATUS
  258. IoClose (
  259. PIO_HANDLE IoHandle
  260. )
  261. /*++
  262. Routine Description:
  263. This routine closes a file or device.
  264. Arguments:
  265. IoHandle - Supplies a pointer to the I/O handle returned when the file was
  266. opened.
  267. Return Value:
  268. Status code. Close operations can fail if their associated flushes to
  269. the file system fail.
  270. --*/
  271. {
  272. KSTATUS Status;
  273. if (IoHandle == NULL) {
  274. return STATUS_INVALID_PARAMETER;
  275. }
  276. switch (IoHandle->HandleType) {
  277. case IoHandleTypeDefault:
  278. Status = IoIoHandleReleaseReference(IoHandle);
  279. break;
  280. case IoHandleTypePaging:
  281. Status = IopClosePagingObject((PPAGING_IO_HANDLE)IoHandle);
  282. break;
  283. default:
  284. ASSERT(FALSE);
  285. Status = STATUS_INVALID_HANDLE;
  286. break;
  287. }
  288. return Status;
  289. }
  290. KERNEL_API
  291. KSTATUS
  292. IoRead (
  293. PIO_HANDLE Handle,
  294. PIO_BUFFER IoBuffer,
  295. UINTN SizeInBytes,
  296. ULONG Flags,
  297. ULONG TimeoutInMilliseconds,
  298. PUINTN BytesCompleted
  299. )
  300. /*++
  301. Routine Description:
  302. This routine reads from an I/O object.
  303. Arguments:
  304. Handle - Supplies the open I/O handle.
  305. IoBuffer - Supplies a pointer to an I/O buffer where the read data will be
  306. returned on success.
  307. SizeInBytes - Supplies the number of bytes to read.
  308. Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
  309. definitions.
  310. TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
  311. operation should be waited on before timing out. Use
  312. WAIT_TIME_INDEFINITE to wait forever on the I/O.
  313. BytesCompleted - Supplies the a pointer where the number of bytes actually
  314. read will be returned.
  315. Return Value:
  316. Status code. A failing status code does not necessarily mean no I/O made it
  317. in or out. Check the bytes completed value to find out how much occurred.
  318. --*/
  319. {
  320. IO_CONTEXT Context;
  321. PIO_HANDLE ReadHandle;
  322. KSTATUS Status;
  323. //
  324. // No-allocate code paths should not be calling I/O read. They should use
  325. // the offset-based read routine.
  326. //
  327. ASSERT((Flags & IO_FLAG_NO_ALLOCATE) == 0);
  328. //
  329. // The special page file no-allocate read operation is not supported by
  330. // this routine. An offset must be supplied for said reads.
  331. //
  332. if ((Flags & IO_FLAG_NO_ALLOCATE) != 0) {
  333. Status = STATUS_INVALID_PARAMETER;
  334. goto ReadEnd;
  335. }
  336. //
  337. // Find the correct I/O handle.
  338. //
  339. if (Handle->HandleType == IoHandleTypePaging) {
  340. ReadHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
  341. } else {
  342. ReadHandle = Handle;
  343. }
  344. Context.IoBuffer = IoBuffer;
  345. Context.Offset = IO_OFFSET_NONE;
  346. Context.SizeInBytes = SizeInBytes;
  347. Context.BytesCompleted = 0;
  348. Context.Flags = Flags;
  349. Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
  350. Context.Write = FALSE;
  351. Status = IopPerformIoOperation(ReadHandle, &Context);
  352. *BytesCompleted = Context.BytesCompleted;
  353. ReadEnd:
  354. return Status;
  355. }
  356. KERNEL_API
  357. KSTATUS
  358. IoWrite (
  359. PIO_HANDLE Handle,
  360. PIO_BUFFER IoBuffer,
  361. UINTN SizeInBytes,
  362. ULONG Flags,
  363. ULONG TimeoutInMilliseconds,
  364. PUINTN BytesCompleted
  365. )
  366. /*++
  367. Routine Description:
  368. This routine writes to an I/O object.
  369. Arguments:
  370. Handle - Supplies the open I/O handle.
  371. IoBuffer - Supplies a pointer to an I/O buffer containing the data to write.
  372. SizeInBytes - Supplies the number of bytes to write.
  373. Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
  374. definitions.
  375. TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
  376. operation should be waited on before timing out. Use
  377. WAIT_TIME_INDEFINITE to wait forever on the I/O.
  378. BytesCompleted - Supplies the a pointer where the number of bytes actually
  379. written will be returned.
  380. Return Value:
  381. Status code. A failing status code does not necessarily mean no I/O made it
  382. in or out. Check the bytes completed value to find out how much occurred.
  383. --*/
  384. {
  385. IO_CONTEXT Context;
  386. KSTATUS Status;
  387. PIO_HANDLE WriteHandle;
  388. //
  389. // No-allocate code paths should not be calling I/O write. They should use
  390. // the offset-based write routine.
  391. //
  392. ASSERT((Flags & IO_FLAG_NO_ALLOCATE) == 0);
  393. //
  394. // The special page file no-allocate write operation is not supported by
  395. // this routine. An offset must be supplied for said writes.
  396. //
  397. if ((Flags & IO_FLAG_NO_ALLOCATE) != 0) {
  398. Status = STATUS_INVALID_PARAMETER;
  399. goto WriteEnd;
  400. }
  401. //
  402. // Find the correct I/O handle.
  403. //
  404. if (Handle->HandleType == IoHandleTypePaging) {
  405. WriteHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
  406. } else {
  407. WriteHandle = Handle;
  408. }
  409. Context.IoBuffer = IoBuffer;
  410. Context.Offset = IO_OFFSET_NONE;
  411. Context.SizeInBytes = SizeInBytes;
  412. Context.BytesCompleted = 0;
  413. Context.Flags = Flags;
  414. Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
  415. Context.Write = TRUE;
  416. Status = IopPerformIoOperation(WriteHandle, &Context);
  417. *BytesCompleted = Context.BytesCompleted;
  418. WriteEnd:
  419. return Status;
  420. }
  421. KERNEL_API
  422. KSTATUS
  423. IoReadAtOffset (
  424. PIO_HANDLE Handle,
  425. PIO_BUFFER IoBuffer,
  426. IO_OFFSET Offset,
  427. UINTN SizeInBytes,
  428. ULONG Flags,
  429. ULONG TimeoutInMilliseconds,
  430. PUINTN BytesCompleted,
  431. PIRP Irp
  432. )
  433. /*++
  434. Routine Description:
  435. This routine reads from an I/O object at a specific offset.
  436. Arguments:
  437. Handle - Supplies the open I/O handle.
  438. IoBuffer - Supplies a pointer to an I/O buffer where the read data will be
  439. returned on success.
  440. Offset - Supplies the offset from the beginning of the file or device where
  441. the I/O should be done.
  442. SizeInBytes - Supplies the number of bytes to read.
  443. Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
  444. definitions.
  445. TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
  446. operation should be waited on before timing out. Use
  447. WAIT_TIME_INDEFINITE to wait forever on the I/O.
  448. BytesCompleted - Supplies the a pointer where the number of bytes actually
  449. read will be returned.
  450. Irp - Supplies a pointer to the IRP to use for this I/O. This is required
  451. when doing operations on the page file.
  452. Return Value:
  453. Status code. A failing status code does not necessarily mean no I/O made it
  454. in or out. Check the bytes completed value to find out how much occurred.
  455. --*/
  456. {
  457. IO_CONTEXT Context;
  458. PIO_HANDLE ReadHandle;
  459. KSTATUS Status;
  460. //
  461. // Determine the correct read handle. Only perform paging I/O operations
  462. // when operating on the page file. It is not enough to look at the I/O
  463. // handle's open flags. There could be reads from the page file or paging
  464. // device that are not in no-allocate code paths. The caller must dictate
  465. // the no-allocate code path.
  466. //
  467. if ((Handle->HandleType == IoHandleTypePaging) &&
  468. ((Flags & IO_FLAG_NO_ALLOCATE) == 0)) {
  469. ReadHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
  470. } else {
  471. ReadHandle = Handle;
  472. }
  473. Context.IoBuffer = IoBuffer;
  474. Context.Offset = Offset;
  475. Context.SizeInBytes = SizeInBytes;
  476. Context.BytesCompleted = 0;
  477. Context.Flags = Flags;
  478. Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
  479. Context.Write = FALSE;
  480. //
  481. // Perform the read operation based on the read handle.
  482. //
  483. switch (ReadHandle->HandleType) {
  484. case IoHandleTypeDefault:
  485. Status = IopPerformIoOperation(ReadHandle, &Context);
  486. break;
  487. case IoHandleTypePaging:
  488. if ((Irp == NULL) || (TimeoutInMilliseconds != WAIT_TIME_INDEFINITE)) {
  489. Status = STATUS_INVALID_PARAMETER;
  490. break;
  491. }
  492. Status = IopPerformPagingIoOperation((PPAGING_IO_HANDLE)ReadHandle,
  493. &Context,
  494. Irp);
  495. break;
  496. default:
  497. ASSERT(FALSE);
  498. Status = STATUS_INVALID_HANDLE;
  499. break;
  500. }
  501. *BytesCompleted = Context.BytesCompleted;
  502. return Status;
  503. }
  504. KERNEL_API
  505. KSTATUS
  506. IoWriteAtOffset (
  507. PIO_HANDLE Handle,
  508. PIO_BUFFER IoBuffer,
  509. IO_OFFSET Offset,
  510. UINTN SizeInBytes,
  511. ULONG Flags,
  512. ULONG TimeoutInMilliseconds,
  513. PUINTN BytesCompleted,
  514. PIRP Irp
  515. )
  516. /*++
  517. Routine Description:
  518. This routine writes to an I/O object at a specific offset.
  519. Arguments:
  520. Handle - Supplies the open I/O handle.
  521. IoBuffer - Supplies a pointer to an I/O buffer containing the data to write.
  522. Offset - Supplies the offset from the beginning of the file or device where
  523. the I/O should be done.
  524. SizeInBytes - Supplies the number of bytes to write.
  525. Flags - Supplies flags regarding the I/O operation. See IO_FLAG_*
  526. definitions.
  527. TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
  528. operation should be waited on before timing out. Use
  529. WAIT_TIME_INDEFINITE to wait forever on the I/O.
  530. BytesCompleted - Supplies the a pointer where the number of bytes actually
  531. written will be returned.
  532. Irp - Supplies a pointer to the IRP to use for this I/O. This is required
  533. when doing operations on the page file.
  534. Return Value:
  535. Status code. A failing status code does not necessarily mean no I/O made it
  536. in or out. Check the bytes completed value to find out how much occurred.
  537. --*/
  538. {
  539. IO_CONTEXT Context;
  540. KSTATUS Status;
  541. PIO_HANDLE WriteHandle;
  542. //
  543. // Determine the correct write handle. Only perform paging I/O operations
  544. // when operating on the page file. It is not enough to look at the I/O
  545. // handle's open flags. There could be writes to the page file or paging
  546. // device that are not in no-allocate code paths. The caller must dictate
  547. // the no-allocate code path.
  548. //
  549. if ((Handle->HandleType == IoHandleTypePaging) &&
  550. ((Flags & IO_FLAG_NO_ALLOCATE) == 0)) {
  551. WriteHandle = ((PPAGING_IO_HANDLE)Handle)->IoHandle;
  552. } else {
  553. WriteHandle = Handle;
  554. }
  555. Context.IoBuffer = IoBuffer;
  556. Context.Offset = Offset;
  557. Context.SizeInBytes = SizeInBytes;
  558. Context.BytesCompleted = 0;
  559. Context.Flags = Flags;
  560. Context.TimeoutInMilliseconds = TimeoutInMilliseconds;
  561. Context.Write = TRUE;
  562. switch (WriteHandle->HandleType) {
  563. case IoHandleTypeDefault:
  564. Status = IopPerformIoOperation(WriteHandle, &Context);
  565. break;
  566. case IoHandleTypePaging:
  567. if ((Irp == NULL) || (TimeoutInMilliseconds != WAIT_TIME_INDEFINITE)) {
  568. Status = STATUS_INVALID_PARAMETER;
  569. break;
  570. }
  571. Status = IopPerformPagingIoOperation((PPAGING_IO_HANDLE)WriteHandle,
  572. &Context,
  573. Irp);
  574. break;
  575. default:
  576. ASSERT(FALSE);
  577. Status = STATUS_INVALID_HANDLE;
  578. break;
  579. }
  580. *BytesCompleted = Context.BytesCompleted;
  581. return Status;
  582. }
  583. KERNEL_API
  584. KSTATUS
  585. IoFlush (
  586. PIO_HANDLE Handle,
  587. IO_OFFSET Offset,
  588. ULONGLONG Size,
  589. ULONG Flags
  590. )
  591. /*++
  592. Routine Description:
  593. This routine flushes I/O data to its appropriate backing device.
  594. Arguments:
  595. Handle - Supplies an open I/O handle. This parameters is not required if
  596. the FLUSH_FLAG_ALL flag is set.
  597. Offset - Supplies the offset from the beginning of the file or device where
  598. the flush should be done.
  599. Size - Supplies the size, in bytes, of the region to flush. Supply a value
  600. of -1 to flush from the given offset to the end of the file.
  601. Flags - Supplies flags regarding the flush operation. See FLUSH_FLAG_*
  602. definitions.
  603. Return Value:
  604. Status code.
  605. --*/
  606. {
  607. PFILE_OBJECT FileObject;
  608. ULONG IoFlags;
  609. KSTATUS Status;
  610. IoFlags = IO_FLAG_DATA_SYNCHRONIZED | IO_FLAG_METADATA_SYNCHRONIZED;
  611. //
  612. // Handle the flush-all synchronous case, where this routine will not
  613. // return until all dirty data made it out to disk.
  614. //
  615. if ((Flags & FLUSH_FLAG_ALL_SYNCHRONOUS) != 0) {
  616. if (Handle != INVALID_HANDLE) {
  617. Status = STATUS_INVALID_PARAMETER;
  618. goto FlushEnd;
  619. }
  620. //
  621. // Flushing synchronously will get all dirty file data and meta-data to
  622. // its underlying block device. It will also flush any dirty block
  623. // device data that has no association with the file layer.
  624. //
  625. Status = IopFlushFileObjects(0, IoFlags, NULL);
  626. goto FlushEnd;
  627. //
  628. // Handle the flush-all case. Just notify the page cache worker to run and
  629. // exit. This does not need to wait until the writes complete.
  630. //
  631. } else if ((Flags & FLUSH_FLAG_ALL) != 0) {
  632. //
  633. // If a handle was provided, something isn't right.
  634. //
  635. if (Handle != INVALID_HANDLE) {
  636. Status = STATUS_INVALID_PARAMETER;
  637. goto FlushEnd;
  638. }
  639. IopSchedulePageCacheThread();
  640. Status = STATUS_SUCCESS;
  641. goto FlushEnd;
  642. }
  643. //
  644. // Otherwise, flush the data for the specific handle. If the data for the
  645. // handle is not in the cache because it's not cacheable, exit successfully.
  646. //
  647. FileObject = Handle->FileObject;
  648. if ((FileObject->Properties.Type == IoObjectTerminalMaster) ||
  649. (FileObject->Properties.Type == IoObjectTerminalSlave)) {
  650. Status = IopTerminalFlush(FileObject, Flags);
  651. if (!KSUCCESS(Status)) {
  652. goto FlushEnd;
  653. }
  654. } else if (IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE) {
  655. if ((Flags &
  656. (FLUSH_FLAG_READ | FLUSH_FLAG_WRITE | FLUSH_FLAG_DISCARD)) != 0) {
  657. Status = STATUS_INVALID_PARAMETER;
  658. goto FlushEnd;
  659. }
  660. Status = IopFlushFileObject(FileObject,
  661. Offset,
  662. Size,
  663. IoFlags,
  664. TRUE,
  665. NULL);
  666. if (!KSUCCESS(Status)) {
  667. goto FlushEnd;
  668. }
  669. } else {
  670. Status = STATUS_SUCCESS;
  671. goto FlushEnd;
  672. }
  673. FlushEnd:
  674. return Status;
  675. }
  676. KERNEL_API
  677. KSTATUS
  678. IoSeek (
  679. PIO_HANDLE Handle,
  680. SEEK_COMMAND SeekCommand,
  681. IO_OFFSET Offset,
  682. PIO_OFFSET NewOffset
  683. )
  684. /*++
  685. Routine Description:
  686. This routine seeks to the given position in a file. This routine is only
  687. relevant for normal file or block based devices.
  688. Arguments:
  689. Handle - Supplies the open I/O handle.
  690. SeekCommand - Supplies the reference point for the seek offset. Usual
  691. reference points are the beginning of the file, current file position,
  692. and the end of the file.
  693. Offset - Supplies the offset from the reference point to move in bytes.
  694. NewOffset - Supplies an optional pointer where the file position after the
  695. move will be returned on success.
  696. Return Value:
  697. Status code.
  698. --*/
  699. {
  700. PFILE_OBJECT FileObject;
  701. IO_OFFSET FileSize;
  702. IO_OFFSET LocalNewOffset;
  703. IO_OFFSET OldOffset;
  704. IO_OFFSET PreviousOffset;
  705. KSTATUS Status;
  706. ASSERT(KeGetRunLevel() == RunLevelLow);
  707. FileObject = Handle->FileObject;
  708. switch (FileObject->Properties.Type) {
  709. case IoObjectRegularFile:
  710. case IoObjectRegularDirectory:
  711. case IoObjectBlockDevice:
  712. case IoObjectObjectDirectory:
  713. case IoObjectSharedMemoryObject:
  714. break;
  715. default:
  716. return STATUS_NOT_SUPPORTED;
  717. }
  718. //
  719. // Loop trying to perform the update atomically.
  720. //
  721. while (TRUE) {
  722. OldOffset = RtlAtomicOr64((PULONGLONG)&(Handle->CurrentOffset), 0);
  723. switch (SeekCommand) {
  724. case SeekCommandNop:
  725. LocalNewOffset = OldOffset;
  726. Status = STATUS_SUCCESS;
  727. goto SeekEnd;
  728. case SeekCommandFromCurrentOffset:
  729. LocalNewOffset = OldOffset + Offset;
  730. break;
  731. //
  732. // Add the file size to the offset and then fall through to handle
  733. // seeking from the end the same as seeking from the beginning.
  734. //
  735. case SeekCommandFromEnd:
  736. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
  737. LocalNewOffset = Offset + FileSize;
  738. break;
  739. case SeekCommandFromBeginning:
  740. LocalNewOffset = Offset;
  741. break;
  742. default:
  743. LocalNewOffset = 0;
  744. Status = STATUS_INVALID_PARAMETER;
  745. goto SeekEnd;
  746. }
  747. if (LocalNewOffset < 0) {
  748. Status = STATUS_INVALID_PARAMETER;
  749. goto SeekEnd;
  750. }
  751. PreviousOffset = RtlAtomicCompareExchange64(
  752. (PULONGLONG)&(Handle->CurrentOffset),
  753. (ULONGLONG)LocalNewOffset,
  754. (ULONGLONG)OldOffset);
  755. if (PreviousOffset == OldOffset) {
  756. break;
  757. }
  758. }
  759. Status = STATUS_SUCCESS;
  760. SeekEnd:
  761. if (NewOffset != NULL) {
  762. *NewOffset = LocalNewOffset;
  763. }
  764. return Status;
  765. }
  766. KERNEL_API
  767. KSTATUS
  768. IoGetFileSize (
  769. PIO_HANDLE Handle,
  770. PULONGLONG FileSize
  771. )
  772. /*++
  773. Routine Description:
  774. This routine returns the current size of the given file or block device.
  775. Arguments:
  776. Handle - Supplies the open file handle.
  777. FileSize - Supplies a pointer where the file size will be returned on
  778. success.
  779. Return Value:
  780. Status code.
  781. --*/
  782. {
  783. PFILE_OBJECT FileObject;
  784. ULONGLONG LocalFileSize;
  785. PPAGING_IO_HANDLE PagingHandle;
  786. KSTATUS Status;
  787. if (Handle->HandleType == IoHandleTypePaging) {
  788. PagingHandle = (PPAGING_IO_HANDLE)Handle;
  789. Handle = PagingHandle->IoHandle;
  790. }
  791. FileObject = Handle->FileObject;
  792. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &LocalFileSize);
  793. *FileSize = LocalFileSize;
  794. Status = STATUS_SUCCESS;
  795. return Status;
  796. }
  797. KERNEL_API
  798. KSTATUS
  799. IoGetFileInformation (
  800. PIO_HANDLE Handle,
  801. PFILE_PROPERTIES FileProperties
  802. )
  803. /*++
  804. Routine Description:
  805. This routine gets the file properties for the given I/O handle.
  806. Arguments:
  807. Handle - Supplies the open file handle.
  808. FileProperties - Supplies a pointer where the file properties will be
  809. returned on success.
  810. Return Value:
  811. Status code.
  812. --*/
  813. {
  814. SET_FILE_INFORMATION Request;
  815. KSTATUS Status;
  816. Request.FieldsToSet = 0;
  817. Status = IoSetFileInformation(TRUE, Handle, &Request);
  818. if (KSUCCESS(Status)) {
  819. RtlCopyMemory(FileProperties,
  820. &(Request.FileProperties),
  821. sizeof(FILE_PROPERTIES));
  822. }
  823. return Status;
  824. }
  825. KERNEL_API
  826. KSTATUS
  827. IoSetFileInformation (
  828. BOOL FromKernelMode,
  829. PIO_HANDLE Handle,
  830. PSET_FILE_INFORMATION Request
  831. )
  832. /*++
  833. Routine Description:
  834. This routine sets the file properties for the given I/O handle.
  835. Only some properties can be set by this routine.
  836. Arguments:
  837. FromKernelMode - Supplies a boolean indicating whether the request
  838. originated from user mode (FALSE) or kernel mode (TRUE). Kernel mode
  839. requests bypass permission checks.
  840. Handle - Supplies the open file handle.
  841. Request - Supplies a pointer to the get/set information request.
  842. Return Value:
  843. Status code.
  844. --*/
  845. {
  846. ULONG FieldsToSet;
  847. PFILE_OBJECT FileObject;
  848. BOOL FileOwner;
  849. PFILE_PROPERTIES FileProperties;
  850. ULONGLONG FileSize;
  851. BOOL HasChownPermission;
  852. BOOL LockHeldExclusive;
  853. BOOL LockHeldShared;
  854. BOOL ModifyFileSize;
  855. ULONGLONG NewFileSize;
  856. KSTATUS Status;
  857. BOOL StatusChanged;
  858. PKTHREAD Thread;
  859. BOOL Updated;
  860. LockHeldExclusive = FALSE;
  861. LockHeldShared = FALSE;
  862. Thread = KeGetCurrentThread();
  863. FieldsToSet = Request->FieldsToSet;
  864. FileProperties = &(Request->FileProperties);
  865. if (FieldsToSet == 0) {
  866. RtlZeroMemory(FileProperties, sizeof(FILE_PROPERTIES));
  867. }
  868. Updated = FALSE;
  869. StatusChanged = FALSE;
  870. //
  871. // Operate on the file object that was actually opened, not the file object
  872. // doing all the I/O.
  873. //
  874. FileObject = Handle->PathPoint.PathEntry->FileObject;
  875. if (FromKernelMode == FALSE) {
  876. FileOwner = FALSE;
  877. if ((FileProperties->UserId == Thread->Identity.EffectiveUserId) ||
  878. (KSUCCESS(PsCheckPermission(PERMISSION_FILE_OWNER)))) {
  879. FileOwner = TRUE;
  880. }
  881. //
  882. // Perform permission checking. Only a privileged user can change the
  883. // file owner.
  884. //
  885. HasChownPermission = FALSE;
  886. Status = PsCheckPermission(PERMISSION_CHOWN);
  887. if (KSUCCESS(Status)) {
  888. HasChownPermission = TRUE;
  889. }
  890. Status = STATUS_PERMISSION_DENIED;
  891. if ((FieldsToSet & FILE_PROPERTY_FIELD_USER_ID) != 0) {
  892. if (HasChownPermission == FALSE) {
  893. goto SetFileInformationEnd;
  894. }
  895. }
  896. //
  897. // An unprivileged user can change the group of a file they own to any
  898. // group of which they are also a member (ie Mickey can change the file
  899. // to any of his mouseketeer clubs).
  900. //
  901. if ((FieldsToSet & FILE_PROPERTY_FIELD_GROUP_ID) != 0) {
  902. if (HasChownPermission == FALSE) {
  903. if (FileOwner == FALSE) {
  904. goto SetFileInformationEnd;
  905. }
  906. if (PsIsUserInGroup(FileProperties->GroupId) == FALSE) {
  907. goto SetFileInformationEnd;
  908. }
  909. }
  910. }
  911. //
  912. // Only the owner of the file may change the permissions and times on
  913. // it.
  914. //
  915. if ((FieldsToSet & FILE_PROPERTY_OWNER_OWNED_FIELDS) != 0) {
  916. if (FileOwner == FALSE) {
  917. goto SetFileInformationEnd;
  918. }
  919. }
  920. } else {
  921. HasChownPermission = TRUE;
  922. FileOwner = TRUE;
  923. }
  924. //
  925. // Truncating a file requires the caller to be able to write to it.
  926. //
  927. if ((FieldsToSet & FILE_PROPERTY_FIELD_FILE_SIZE) != 0) {
  928. Status = IopCheckPermissions(FromKernelMode,
  929. &(Handle->PathPoint),
  930. IO_ACCESS_WRITE);
  931. if (!KSUCCESS(Status)) {
  932. goto SetFileInformationEnd;
  933. }
  934. }
  935. ModifyFileSize = FALSE;
  936. NewFileSize = 0;
  937. if (FieldsToSet != 0) {
  938. KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
  939. LockHeldExclusive = TRUE;
  940. } else {
  941. KeAcquireSharedExclusiveLockShared(FileObject->Lock);
  942. LockHeldShared = TRUE;
  943. }
  944. //
  945. // Not all attributes can be set for symbolic links.
  946. //
  947. if (FileObject->Properties.Type == IoObjectSymbolicLink) {
  948. FieldsToSet &= FILE_PROPERTY_FIELD_USER_ID |
  949. FILE_PROPERTY_FIELD_GROUP_ID |
  950. FILE_PROPERTY_FIELD_ACCESS_TIME |
  951. FILE_PROPERTY_FIELD_MODIFIED_TIME |
  952. FILE_PROPERTY_FIELD_STATUS_CHANGE_TIME;
  953. }
  954. if (FieldsToSet != 0) {
  955. //
  956. // Object directories cannot be altered.
  957. //
  958. if (FileObject->Properties.Type == IoObjectObjectDirectory) {
  959. Status = STATUS_NOT_SUPPORTED;
  960. goto SetFileInformationEnd;
  961. }
  962. //
  963. // If the owner or group are changed by an unprivileged user, the
  964. // setuid and setgid bits are cleared from the file.
  965. //
  966. if (((FieldsToSet &
  967. (FILE_PROPERTY_FIELD_USER_ID |
  968. FILE_PROPERTY_FIELD_GROUP_ID)) != 0) &&
  969. (HasChownPermission == FALSE)) {
  970. FileObject->Properties.Permissions &=
  971. ~(FILE_PERMISSION_SET_USER_ID |
  972. FILE_PERMISSION_SET_GROUP_ID);
  973. Updated = TRUE;
  974. StatusChanged = TRUE;
  975. }
  976. if ((FieldsToSet & FILE_PROPERTY_FIELD_USER_ID) != 0) {
  977. FileObject->Properties.UserId = FileProperties->UserId;
  978. Updated = TRUE;
  979. StatusChanged = TRUE;
  980. }
  981. if ((FieldsToSet & FILE_PROPERTY_FIELD_GROUP_ID) != 0) {
  982. FileObject->Properties.GroupId = FileProperties->GroupId;
  983. Updated = TRUE;
  984. StatusChanged = TRUE;
  985. }
  986. if ((FieldsToSet & FILE_PROPERTY_FIELD_PERMISSIONS) != 0) {
  987. FileObject->Properties.Permissions =
  988. FileProperties->Permissions & FILE_PERMISSION_MASK;
  989. Updated = TRUE;
  990. StatusChanged = TRUE;
  991. //
  992. // If the permissions are being changed by an unprivileged
  993. // owner, and the caller is not a member of the file group, the
  994. // setgid permission is removed.
  995. //
  996. if ((FromKernelMode == FALSE) &&
  997. (!KSUCCESS(PsCheckPermission(PERMISSION_FILE_OWNER))) &&
  998. (PsIsUserInGroup(FileObject->Properties.GroupId) ==
  999. FALSE)) {
  1000. FileObject->Properties.Permissions &=
  1001. ~FILE_PERMISSION_SET_GROUP_ID;
  1002. }
  1003. }
  1004. if ((FieldsToSet & FILE_PROPERTY_FIELD_ACCESS_TIME) != 0) {
  1005. FileObject->Properties.AccessTime = FileProperties->AccessTime;
  1006. Updated = TRUE;
  1007. StatusChanged = TRUE;
  1008. }
  1009. if ((FieldsToSet & FILE_PROPERTY_FIELD_MODIFIED_TIME) != 0) {
  1010. FileObject->Properties.ModifiedTime =
  1011. FileProperties->ModifiedTime;
  1012. Updated = TRUE;
  1013. StatusChanged = TRUE;
  1014. }
  1015. if ((FieldsToSet & FILE_PROPERTY_FIELD_STATUS_CHANGE_TIME) != 0) {
  1016. FileObject->Properties.StatusChangeTime =
  1017. FileProperties->StatusChangeTime;
  1018. Updated = TRUE;
  1019. }
  1020. if ((FieldsToSet & FILE_PROPERTY_FIELD_FILE_SIZE) != 0) {
  1021. //
  1022. // Some types cannot have their file sizes modified.
  1023. //
  1024. switch (FileObject->Properties.Type) {
  1025. case IoObjectRegularFile:
  1026. case IoObjectSharedMemoryObject:
  1027. break;
  1028. default:
  1029. Status = STATUS_PERMISSION_DENIED;
  1030. goto SetFileInformationEnd;
  1031. }
  1032. ModifyFileSize = TRUE;
  1033. READ_INT64_SYNC(&(FileProperties->FileSize), &NewFileSize);
  1034. }
  1035. } else {
  1036. RtlCopyMemory(FileProperties,
  1037. &(FileObject->Properties),
  1038. sizeof(FILE_PROPERTIES));
  1039. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
  1040. WRITE_INT64_SYNC(&(FileProperties->FileSize), FileSize);
  1041. }
  1042. //
  1043. // If the file status was changed, update the file status change time.
  1044. // Don't do this if the caller explicitly changed the status change
  1045. // time field.
  1046. //
  1047. if ((StatusChanged != FALSE) &&
  1048. ((FieldsToSet & FILE_PROPERTY_FIELD_STATUS_CHANGE_TIME) == 0)) {
  1049. KeGetSystemTime(&(FileObject->Properties.StatusChangeTime));
  1050. }
  1051. if (LockHeldExclusive != FALSE) {
  1052. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  1053. LockHeldExclusive = FALSE;
  1054. } else {
  1055. KeReleaseSharedExclusiveLockShared(FileObject->Lock);
  1056. LockHeldShared = FALSE;
  1057. }
  1058. //
  1059. // With the spin lock released, go ahead and modify the file size if
  1060. // requested.
  1061. //
  1062. if (ModifyFileSize != FALSE) {
  1063. Status = IopModifyFileObjectSize(FileObject,
  1064. Handle->DeviceContext,
  1065. NewFileSize);
  1066. if (!KSUCCESS(Status)) {
  1067. goto SetFileInformationEnd;
  1068. }
  1069. }
  1070. if (Updated != FALSE) {
  1071. IopMarkFileObjectPropertiesDirty(FileObject);
  1072. }
  1073. Status = STATUS_SUCCESS;
  1074. SetFileInformationEnd:
  1075. if (LockHeldExclusive != FALSE) {
  1076. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  1077. } else if (LockHeldShared != FALSE) {
  1078. KeReleaseSharedExclusiveLockShared(FileObject->Lock);
  1079. }
  1080. return Status;
  1081. }
  1082. KERNEL_API
  1083. KSTATUS
  1084. IoDelete (
  1085. BOOL FromKernelMode,
  1086. PIO_HANDLE Directory,
  1087. PSTR Path,
  1088. ULONG PathSize,
  1089. ULONG Flags
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. This routine attempts to delete the object at the given path. If the path
  1094. points to a directory, the directory must be empty. If the path points to
  1095. a file object or shared memory object, its hard link count is decremented.
  1096. If the hard link count reaches zero and no processes have the object open,
  1097. the contents of the object are destroyed. If processes have open handles to
  1098. the object, the destruction of the object contents are deferred until the
  1099. last handle to the old file is closed. If the path points to a symbolic
  1100. link, the link itself is removed and not the destination. The removal of
  1101. the entry from the directory is immediate.
  1102. Arguments:
  1103. FromKernelMode - Supplies a boolean indicating the request is coming from
  1104. kernel mode.
  1105. Directory - Supplies an optional pointer to an open handle to a directory
  1106. for relative paths. Supply NULL to use the current working directory.
  1107. Path - Supplies a pointer to the path to delete.
  1108. PathSize - Supplies the length of the path buffer in bytes, including the
  1109. null terminator.
  1110. Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
  1111. Return Value:
  1112. Status code.
  1113. --*/
  1114. {
  1115. KSTATUS Status;
  1116. if ((Flags & DELETE_FLAG_SHARED_MEMORY) != 0) {
  1117. Status = IopDeleteSharedMemoryObject(Path, PathSize);
  1118. } else {
  1119. Status = IopDelete(FromKernelMode, Directory, Path, PathSize, Flags);
  1120. }
  1121. return Status;
  1122. }
  1123. KERNEL_API
  1124. KSTATUS
  1125. IoRename (
  1126. BOOL FromKernelMode,
  1127. PIO_HANDLE SourceStartDirectory,
  1128. PSTR SourcePath,
  1129. ULONG SourcePathSize,
  1130. PIO_HANDLE DestinationStartDirectory,
  1131. PSTR DestinationPath,
  1132. ULONG DestinationPathSize
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. This routine attempts to rename the object at the given path. This routine
  1137. operates on symbolic links themselves, not the destinations of symbolic
  1138. links. If the source and destination paths are equal, this routine will do
  1139. nothing and return successfully. If the source path is not a directory, the
  1140. destination path must not be a directory. If the destination file exists,
  1141. it will be deleted. The caller must have write access in both the old and
  1142. new directories. If the source path is a directory, the destination path
  1143. must not exist or be an empty directory. The destination path must not have
  1144. a path prefix of the source (ie it's illegal to move /my/path into
  1145. /my/path/stuff).
  1146. Arguments:
  1147. FromKernelMode - Supplies a boolean indicating the request is coming from
  1148. kernel mode.
  1149. SourceStartDirectory - Supplies an optional pointer to a handle to the
  1150. directory to start at for relative source paths. If the source path is
  1151. not relative, this parameter is ignored. If this is not supplied, then
  1152. the current working directory of the process is used.
  1153. SourcePath - Supplies a pointer to the path of the file to rename.
  1154. SourcePathSize - Supplies the length of the source path buffer in bytes,
  1155. including the null terminator.
  1156. DestinationStartDirectory - Supplies an optional pointer to the directory
  1157. to start at for relative destination paths. If the destination path is
  1158. not relative, this parameter is ignored. If this is not supplied, then
  1159. the current working directory of the process is used.
  1160. DestinationPath - Supplies a pointer to the path to rename the file to.
  1161. DestinationPathSize - Supplies the size of the destination path buffer in
  1162. bytes, including the null terminator.
  1163. Return Value:
  1164. Status code.
  1165. --*/
  1166. {
  1167. ULONG Attempts;
  1168. BOOL DescendantPath;
  1169. PSTR DestinationDirectory;
  1170. PFILE_OBJECT DestinationDirectoryFileObject;
  1171. PATH_POINT DestinationDirectoryPathPoint;
  1172. ULONG DestinationDirectorySize;
  1173. PSTR DestinationFile;
  1174. PFILE_OBJECT DestinationFileObject;
  1175. ULONG DestinationFileSize;
  1176. PATH_POINT DestinationPathPoint;
  1177. PPATH_POINT DestinationStartPathPoint;
  1178. PDEVICE Device;
  1179. PATH_POINT FoundPathPoint;
  1180. PSTR LocalDestinationPath;
  1181. ULONG LocalDestinationPathSize;
  1182. PSTR LocalSourcePath;
  1183. ULONG LocalSourcePathSize;
  1184. BOOL LocksHeld;
  1185. ULONG NameHash;
  1186. PPATH_ENTRY PathEntry;
  1187. SYSTEM_CONTROL_RENAME RenameRequest;
  1188. PFILE_OBJECT SourceDirectoryFileObject;
  1189. PATH_POINT SourceDirectoryPathPoint;
  1190. PFILE_OBJECT SourceFileObject;
  1191. PATH_POINT SourcePathPoint;
  1192. PPATH_POINT SourceStartPathPoint;
  1193. KSTATUS Status;
  1194. DestinationDirectory = NULL;
  1195. DestinationDirectoryPathPoint.PathEntry = NULL;
  1196. DestinationPathPoint.PathEntry = NULL;
  1197. DestinationFile = NULL;
  1198. DestinationFileObject = NULL;
  1199. DestinationStartPathPoint = NULL;
  1200. FoundPathPoint.PathEntry = NULL;
  1201. LocksHeld = FALSE;
  1202. SourceDirectoryPathPoint.PathEntry = NULL;
  1203. SourceFileObject = NULL;
  1204. SourcePathPoint.PathEntry = NULL;
  1205. SourceStartPathPoint = NULL;
  1206. if ((SourcePathSize <= 1) || (DestinationPathSize <= 1)) {
  1207. Status = STATUS_PATH_NOT_FOUND;
  1208. goto RenameEnd;
  1209. }
  1210. if (SourceStartDirectory != NULL) {
  1211. SourceStartPathPoint = &(SourceStartDirectory->PathPoint);
  1212. if (SourceStartPathPoint->PathEntry->FileObject->Properties.Type !=
  1213. IoObjectRegularDirectory) {
  1214. Status = STATUS_NOT_A_DIRECTORY;
  1215. goto RenameEnd;
  1216. }
  1217. ASSERT(SourceStartDirectory->FileObject ==
  1218. SourceStartPathPoint->PathEntry->FileObject);
  1219. }
  1220. if (DestinationStartDirectory != NULL) {
  1221. DestinationStartPathPoint = &(DestinationStartDirectory->PathPoint);
  1222. if (DestinationStartPathPoint->PathEntry->FileObject->Properties.Type !=
  1223. IoObjectRegularDirectory) {
  1224. Status = STATUS_NOT_A_DIRECTORY;
  1225. goto RenameEnd;
  1226. }
  1227. ASSERT(DestinationStartDirectory->FileObject ==
  1228. DestinationStartPathPoint->PathEntry->FileObject);
  1229. }
  1230. //
  1231. // Loop trying to rename the source to the destination. The loop is
  1232. // necessary because things may change before the appropriate locks are
  1233. // acquired. Once the locks are acquired, the state is checked and if it is
  1234. // not good enough to proceed, the whole process gets restarted.
  1235. //
  1236. Attempts = 0;
  1237. Status = STATUS_TRY_AGAIN;
  1238. while (Attempts < IO_RENAME_ATTEMPTS_MAX) {
  1239. //
  1240. // Get the source file, which must exist.
  1241. //
  1242. LocalSourcePath = SourcePath;
  1243. LocalSourcePathSize = SourcePathSize;
  1244. Status = IopPathWalk(FromKernelMode,
  1245. SourceStartPathPoint,
  1246. &LocalSourcePath,
  1247. &LocalSourcePathSize,
  1248. OPEN_FLAG_SYMBOLIC_LINK | OPEN_FLAG_NO_MOUNT_POINT,
  1249. IoObjectInvalid,
  1250. NULL,
  1251. FILE_PERMISSION_NONE,
  1252. &SourcePathPoint);
  1253. if (!KSUCCESS(Status)) {
  1254. goto RenameEnd;
  1255. }
  1256. //
  1257. // Rename is not allowed if the source is mounted anywhere.
  1258. //
  1259. if (SourcePathPoint.PathEntry->MountCount != 0) {
  1260. Status = STATUS_RESOURCE_IN_USE;
  1261. goto RenameEnd;
  1262. }
  1263. //
  1264. // Get the source directory entry and file object.
  1265. //
  1266. IopGetParentPathPoint(NULL,
  1267. &SourcePathPoint,
  1268. &SourceDirectoryPathPoint);
  1269. PathEntry = SourceDirectoryPathPoint.PathEntry;
  1270. SourceDirectoryFileObject = PathEntry->FileObject;
  1271. ASSERT(SourceDirectoryFileObject != NULL);
  1272. ASSERT(SourcePathPoint.MountPoint ==
  1273. SourceDirectoryPathPoint.MountPoint);
  1274. //
  1275. // Check to see that the caller has permission to delete something from
  1276. // the source directory.
  1277. //
  1278. if (FromKernelMode == FALSE) {
  1279. Status = IopCheckDeletePermission(FromKernelMode,
  1280. &SourceDirectoryPathPoint,
  1281. &SourcePathPoint);
  1282. if (!KSUCCESS(Status)) {
  1283. goto RenameEnd;
  1284. }
  1285. }
  1286. SourceFileObject = SourcePathPoint.PathEntry->FileObject;
  1287. ASSERT(SourceFileObject->Properties.DeviceId ==
  1288. SourceDirectoryFileObject->Properties.DeviceId);
  1289. //
  1290. // Split the destination path into a file part and a directory part.
  1291. //
  1292. Status = IopPathSplit(DestinationPath,
  1293. DestinationPathSize,
  1294. &DestinationDirectory,
  1295. &DestinationDirectorySize,
  1296. &DestinationFile,
  1297. &DestinationFileSize);
  1298. if (!KSUCCESS(Status)) {
  1299. goto RenameEnd;
  1300. }
  1301. //
  1302. // Get the destination file, which may or may not exist.
  1303. //
  1304. LocalDestinationPath = DestinationPath;
  1305. LocalDestinationPathSize = DestinationPathSize;
  1306. Status = IopPathWalk(FromKernelMode,
  1307. DestinationStartPathPoint,
  1308. &LocalDestinationPath,
  1309. &LocalDestinationPathSize,
  1310. OPEN_FLAG_SYMBOLIC_LINK | OPEN_FLAG_NO_MOUNT_POINT,
  1311. IoObjectInvalid,
  1312. NULL,
  1313. FILE_PERMISSION_NONE,
  1314. &DestinationPathPoint);
  1315. if (!KSUCCESS(Status)) {
  1316. if (Status != STATUS_PATH_NOT_FOUND) {
  1317. goto RenameEnd;
  1318. }
  1319. ASSERT(DestinationPathPoint.PathEntry == NULL);
  1320. //
  1321. // Try to find the destination file's directory.
  1322. //
  1323. LocalDestinationPath = DestinationDirectory;
  1324. LocalDestinationPathSize = DestinationDirectorySize;
  1325. if ((LocalDestinationPathSize == 0) ||
  1326. ((LocalDestinationPathSize == 1) &&
  1327. (LocalDestinationPath[0] == '\0'))) {
  1328. LocalDestinationPath = ".";
  1329. LocalDestinationPathSize = sizeof(".");
  1330. }
  1331. Status = IopPathWalk(FromKernelMode,
  1332. DestinationStartPathPoint,
  1333. &LocalDestinationPath,
  1334. &LocalDestinationPathSize,
  1335. OPEN_FLAG_SYMBOLIC_LINK,
  1336. IoObjectInvalid,
  1337. NULL,
  1338. FILE_PERMISSION_NONE,
  1339. &DestinationDirectoryPathPoint);
  1340. if (!KSUCCESS(Status)) {
  1341. goto RenameEnd;
  1342. }
  1343. PathEntry = DestinationDirectoryPathPoint.PathEntry;
  1344. DestinationDirectoryFileObject = PathEntry->FileObject;
  1345. //
  1346. // Require write permission on the directory since the destination
  1347. // does not exist.
  1348. //
  1349. Status = IopCheckPermissions(FromKernelMode,
  1350. &DestinationDirectoryPathPoint,
  1351. IO_ACCESS_WRITE);
  1352. if (!KSUCCESS(Status)) {
  1353. goto RenameEnd;
  1354. }
  1355. //
  1356. // The destination file exists.
  1357. //
  1358. } else {
  1359. PathEntry = DestinationPathPoint.PathEntry;
  1360. DestinationFileObject = PathEntry->FileObject;
  1361. //
  1362. // If the destination is the same as the source, then it's a no-op.
  1363. //
  1364. if (SourceFileObject == DestinationFileObject) {
  1365. Status = STATUS_SUCCESS;
  1366. goto RenameEnd;
  1367. }
  1368. //
  1369. // If the source is not a directory, the destination cannot be a
  1370. // directory.
  1371. //
  1372. if ((SourceFileObject->Properties.Type !=
  1373. IoObjectRegularDirectory) &&
  1374. (DestinationFileObject->Properties.Type ==
  1375. IoObjectRegularDirectory)) {
  1376. Status = STATUS_FILE_IS_DIRECTORY;
  1377. goto RenameEnd;
  1378. }
  1379. //
  1380. // If the source is a directory, the destination must be a
  1381. // directory. The check for that destination to be empty will be
  1382. // done in the file system.
  1383. //
  1384. if ((SourceFileObject->Properties.Type ==
  1385. IoObjectRegularDirectory) &&
  1386. (DestinationFileObject->Properties.Type !=
  1387. IoObjectRegularDirectory)) {
  1388. Status = STATUS_NOT_A_DIRECTORY;
  1389. goto RenameEnd;
  1390. }
  1391. //
  1392. // Rename is not allowed when the destination is mounted. It does
  1393. // not matter where.
  1394. //
  1395. if (DestinationPathPoint.PathEntry->MountCount != 0) {
  1396. Status = STATUS_RESOURCE_IN_USE;
  1397. goto RenameEnd;
  1398. }
  1399. IopGetParentPathPoint(NULL,
  1400. &DestinationPathPoint,
  1401. &DestinationDirectoryPathPoint);
  1402. PathEntry = DestinationDirectoryPathPoint.PathEntry;
  1403. DestinationDirectoryFileObject = PathEntry->FileObject;
  1404. ASSERT(DestinationPathPoint.PathEntry->FileObject->Device ==
  1405. DestinationDirectoryPathPoint.PathEntry->FileObject->Device);
  1406. ASSERT(DestinationPathPoint.MountPoint ==
  1407. DestinationDirectoryPathPoint.MountPoint);
  1408. ASSERT(DestinationFileObject->Properties.DeviceId ==
  1409. DestinationDirectoryFileObject->Properties.DeviceId);
  1410. //
  1411. // Since there is a destination file, it needs to be deleted.
  1412. // Ensure the caller has that authority.
  1413. //
  1414. Status = IopCheckDeletePermission(FromKernelMode,
  1415. &DestinationDirectoryPathPoint,
  1416. &DestinationPathPoint);
  1417. if (!KSUCCESS(Status)) {
  1418. goto RenameEnd;
  1419. }
  1420. }
  1421. //
  1422. // The destination directory should not have a path prefix of the
  1423. // source file. Ignore mount points for this check and only look at
  1424. // the path entries.
  1425. //
  1426. if (SourceFileObject->Properties.Type == IoObjectRegularDirectory) {
  1427. DescendantPath = IopIsDescendantPath(
  1428. SourcePathPoint.PathEntry,
  1429. DestinationDirectoryPathPoint.PathEntry);
  1430. if (DescendantPath != FALSE) {
  1431. Status = STATUS_INVALID_PARAMETER;
  1432. goto RenameEnd;
  1433. }
  1434. }
  1435. //
  1436. // Renames don't work across file systems.
  1437. //
  1438. if (SourcePathPoint.PathEntry->FileObject->Device !=
  1439. DestinationDirectoryPathPoint.PathEntry->FileObject->Device) {
  1440. Status = STATUS_CROSS_DEVICE;
  1441. goto RenameEnd;
  1442. }
  1443. //
  1444. // The object file system does not allow renaming, only devices and
  1445. // volumes can handle it.
  1446. //
  1447. Device = SourcePathPoint.PathEntry->FileObject->Device;
  1448. if ((Device->Header.Type != ObjectDevice) &&
  1449. (Device->Header.Type != ObjectVolume)) {
  1450. Status = STATUS_ACCESS_DENIED;
  1451. goto RenameEnd;
  1452. }
  1453. //
  1454. // Prepare the rename request.
  1455. //
  1456. RenameRequest.Name = DestinationFile;
  1457. RenameRequest.NameSize = DestinationFileSize;
  1458. RenameRequest.DestinationFileUnlinked = FALSE;
  1459. RenameRequest.DestinationDirectorySize = 0;
  1460. RenameRequest.SourceFileProperties = &(SourceFileObject->Properties);
  1461. RenameRequest.SourceDirectoryProperties =
  1462. &(SourceDirectoryFileObject->Properties);
  1463. RenameRequest.DestinationFileProperties = NULL;
  1464. RenameRequest.DestinationDirectoryProperties =
  1465. &(DestinationDirectoryFileObject->Properties);
  1466. //
  1467. // For a rename operation, the source file, the source directory and
  1468. // the destination directory need to be locked. Additionally, if a
  1469. // destination file exists, it needs to be locked to synchronize the
  1470. // unlink operation and write file properties. The source file is
  1471. // locked to synchronize with file property writes. Because the FAT
  1472. // file system writes properties to the parent directory, file property
  1473. // writes always need to be able to find a valid parent directory.
  1474. // Directories are always locked before files.
  1475. //
  1476. IopAcquireFileObjectLocksExclusive(SourceDirectoryFileObject,
  1477. DestinationDirectoryFileObject);
  1478. if (DestinationFileObject != NULL) {
  1479. IopAcquireFileObjectLocksExclusive(SourceFileObject,
  1480. DestinationFileObject);
  1481. } else {
  1482. KeAcquireSharedExclusiveLockExclusive(SourceFileObject->Lock);
  1483. }
  1484. LocksHeld = TRUE;
  1485. //
  1486. // If the source file or destination directory have been unlinked, act
  1487. // like the paths were not found. It's okay if the destination
  1488. // directory has no siblings if it's a mount point, as mount points
  1489. // cannot be unlinked without first being unmounted, and some mounts
  1490. // are just floating path entries without siblings.
  1491. //
  1492. if ((SourcePathPoint.PathEntry->SiblingListEntry.Next == NULL) ||
  1493. ((DestinationDirectoryPathPoint.PathEntry->SiblingListEntry.Next ==
  1494. NULL) &&
  1495. (!IO_IS_MOUNT_POINT(&DestinationDirectoryPathPoint)))) {
  1496. Status = STATUS_PATH_NOT_FOUND;
  1497. break;
  1498. }
  1499. //
  1500. // If the source is still there, the source directory better still be
  1501. // there too.
  1502. //
  1503. ASSERT((SourceDirectoryPathPoint.PathEntry->SiblingListEntry.Next !=
  1504. NULL) ||
  1505. (IO_IS_MOUNT_POINT(&SourceDirectoryPathPoint)));
  1506. //
  1507. // If the destination file was present above and is still in the path
  1508. // hierarchy, then the rename can proceed.
  1509. //
  1510. if ((DestinationPathPoint.PathEntry != NULL) &&
  1511. (DestinationPathPoint.PathEntry->SiblingListEntry.Next != NULL)) {
  1512. ASSERT(DestinationFileObject != NULL);
  1513. ASSERT(DestinationPathPoint.PathEntry->Negative == FALSE);
  1514. ASSERT(DestinationFileObject->Properties.HardLinkCount != 0);
  1515. RenameRequest.DestinationFileProperties =
  1516. &(DestinationFileObject->Properties);
  1517. Status = STATUS_SUCCESS;
  1518. break;
  1519. }
  1520. //
  1521. // Otherwise, now that the destination directory's lock is held, if
  1522. // there is still no file at the destination, then the rename can
  1523. // proceed.
  1524. //
  1525. Status = IopPathLookup(FromKernelMode,
  1526. DestinationStartPathPoint,
  1527. &DestinationDirectoryPathPoint,
  1528. TRUE,
  1529. DestinationFile,
  1530. DestinationFileSize,
  1531. OPEN_FLAG_NO_MOUNT_POINT,
  1532. IoObjectInvalid,
  1533. NULL,
  1534. 0,
  1535. &FoundPathPoint);
  1536. //
  1537. // If no path is found, then either a negative path entry was found or
  1538. // no file path exists. It is then safe to proceed with the rename.
  1539. //
  1540. if (Status == STATUS_PATH_NOT_FOUND) {
  1541. ASSERT(RenameRequest.DestinationFileProperties == NULL);
  1542. Status = STATUS_SUCCESS;
  1543. ASSERT((FoundPathPoint.PathEntry == NULL) ||
  1544. (FoundPathPoint.PathEntry->Negative != FALSE));
  1545. //
  1546. // If there's a negative path entry there, unlink it. The reference
  1547. // will be released when the locks can be dropped.
  1548. //
  1549. if (FoundPathPoint.PathEntry != NULL) {
  1550. IopPathUnlink(FoundPathPoint.PathEntry);
  1551. }
  1552. break;
  1553. //
  1554. // For any other error, just break and fail.
  1555. //
  1556. } else if (!KSUCCESS(Status)) {
  1557. break;
  1558. }
  1559. //
  1560. // If a destination file was found, then the rename must loop back and
  1561. // make another attempt. Due to lock ordering it is not possible to
  1562. // simply acquire this entry's lock now. And once the locks are
  1563. // released, no guarantees can be made about the state of the source
  1564. // or directory.
  1565. //
  1566. ASSERT(FoundPathPoint.PathEntry != NULL);
  1567. ASSERT(FoundPathPoint.PathEntry->SiblingListEntry.Next != NULL);
  1568. //
  1569. // A destination entry was found or it was unlinked after the
  1570. // destination directory lock was acquired. The rename needs to be
  1571. // tried again. Release the locks and any references taken.
  1572. //
  1573. KeReleaseSharedExclusiveLockExclusive(SourceFileObject->Lock);
  1574. if (DestinationFileObject != NULL) {
  1575. KeReleaseSharedExclusiveLockExclusive(DestinationFileObject->Lock);
  1576. }
  1577. KeReleaseSharedExclusiveLockExclusive(SourceDirectoryFileObject->Lock);
  1578. if (DestinationDirectoryFileObject != SourceDirectoryFileObject) {
  1579. KeReleaseSharedExclusiveLockExclusive(
  1580. DestinationDirectoryFileObject->Lock);
  1581. }
  1582. LocksHeld = FALSE;
  1583. IO_PATH_POINT_RELEASE_REFERENCE(&SourcePathPoint);
  1584. SourcePathPoint.PathEntry = NULL;
  1585. IO_PATH_POINT_RELEASE_REFERENCE(&SourceDirectoryPathPoint);
  1586. SourceDirectoryPathPoint.PathEntry = NULL;
  1587. IO_PATH_POINT_RELEASE_REFERENCE(&DestinationDirectoryPathPoint);
  1588. DestinationDirectoryPathPoint.PathEntry = NULL;
  1589. if (DestinationPathPoint.PathEntry != NULL) {
  1590. IO_PATH_POINT_RELEASE_REFERENCE(&DestinationPathPoint);
  1591. DestinationPathPoint.PathEntry = NULL;
  1592. }
  1593. if (FoundPathPoint.PathEntry != NULL) {
  1594. IO_PATH_POINT_RELEASE_REFERENCE(&FoundPathPoint);
  1595. FoundPathPoint.PathEntry = NULL;
  1596. }
  1597. MmFreePagedPool(DestinationDirectory);
  1598. DestinationDirectory = NULL;
  1599. MmFreePagedPool(DestinationFile);
  1600. DestinationFile = NULL;
  1601. DestinationFileObject = NULL;
  1602. Attempts += 1;
  1603. }
  1604. if (!KSUCCESS(Status)) {
  1605. goto RenameEnd;
  1606. }
  1607. //
  1608. // Check to make sure that the source and destination file objects did not
  1609. // become mount points since the checks above. A path entry's file object's
  1610. // lock is acquired in shared mode when the mount count is increment,
  1611. // synchronizing with the rename call.
  1612. //
  1613. if ((SourcePathPoint.PathEntry->MountCount != 0) ||
  1614. ((DestinationPathPoint.PathEntry != NULL) &&
  1615. (DestinationPathPoint.PathEntry->MountCount != 0))) {
  1616. Status = STATUS_RESOURCE_IN_USE;
  1617. goto RenameEnd;
  1618. }
  1619. Status = IopSendSystemControlIrp(Device,
  1620. IrpMinorSystemControlRename,
  1621. &RenameRequest);
  1622. //
  1623. // Even if the rename failed, the destination file (if it existed and had
  1624. // not already been unlinked) could have been unlinked. If so, decrement
  1625. // it's hard link count and unlink it from this path tree. This must happen
  1626. // while the locks are held.
  1627. //
  1628. if (RenameRequest.DestinationFileUnlinked != FALSE) {
  1629. ASSERT(DestinationPathPoint.PathEntry != NULL);
  1630. ASSERT(DestinationFileObject != NULL);
  1631. IopFileObjectDecrementHardLinkCount(DestinationFileObject);
  1632. IopPathUnlink(DestinationPathPoint.PathEntry);
  1633. //
  1634. // If there's a negative destination entry, remove it. The rename moved
  1635. // the source onto the destination, in which case the file object
  1636. // pointer is incorrectly null.
  1637. //
  1638. } else if ((DestinationPathPoint.PathEntry != NULL) &&
  1639. (DestinationPathPoint.PathEntry->Negative != FALSE)) {
  1640. IopPathUnlink(DestinationPathPoint.PathEntry);
  1641. }
  1642. //
  1643. // If the source file's hard link count changed, then it could now either
  1644. // be in two directories, or in no directories.
  1645. //
  1646. if (RenameRequest.SourceFileHardLinkDelta != 0) {
  1647. //
  1648. // If the delta is 1, then it got added to the destination directory,
  1649. // but was never deleted from the source. Increment the hard link count.
  1650. //
  1651. if (RenameRequest.SourceFileHardLinkDelta == 1) {
  1652. IopFileObjectIncrementHardLinkCount(SourceFileObject);
  1653. IopUpdateFileObjectTime(DestinationDirectoryFileObject,
  1654. FileObjectModifiedTime);
  1655. //
  1656. // Otherwise, the delta is -1. Decrement the hard link count and unlink
  1657. // it from the source path entry. Unfortunately, this rename turned
  1658. // into a delete.
  1659. //
  1660. } else {
  1661. ASSERT(RenameRequest.SourceFileHardLinkDelta == (ULONG)-1);
  1662. IopFileObjectDecrementHardLinkCount(SourceFileObject);
  1663. IopPathUnlink(SourcePathPoint.PathEntry);
  1664. IopUpdateFileObjectTime(SourceDirectoryFileObject,
  1665. FileObjectModifiedTime);
  1666. }
  1667. //
  1668. // Rename succeeded.
  1669. //
  1670. } else if (KSUCCESS(Status)) {
  1671. //
  1672. // Create a path entry at the destination to avoid the painful
  1673. // penalty of having to do a file system lookup on this object next
  1674. // time.
  1675. //
  1676. if (SourcePathPoint.PathEntry->DoNotCache == FALSE) {
  1677. NameHash = IopHashPathString(DestinationFile, DestinationFileSize);
  1678. PathEntry = IopCreatePathEntry(
  1679. DestinationFile,
  1680. DestinationFileSize,
  1681. NameHash,
  1682. DestinationDirectoryPathPoint.PathEntry,
  1683. SourceFileObject);
  1684. if (PathEntry != NULL) {
  1685. INSERT_BEFORE(
  1686. &(PathEntry->SiblingListEntry),
  1687. &(DestinationDirectoryPathPoint.PathEntry->ChildList));
  1688. IopFileObjectAddReference(SourceFileObject);
  1689. }
  1690. }
  1691. //
  1692. // Unlink the source file path from its parent so new paths walks will
  1693. // not find it and so that delete will see that it's too late.
  1694. //
  1695. IopPathUnlink(SourcePathPoint.PathEntry);
  1696. //
  1697. // Also update the size of the destination directory.
  1698. //
  1699. IopUpdateFileObjectFileSize(DestinationDirectoryFileObject,
  1700. RenameRequest.DestinationDirectorySize);
  1701. IopUpdateFileObjectTime(DestinationDirectoryFileObject,
  1702. FileObjectModifiedTime);
  1703. IopUpdateFileObjectTime(SourceDirectoryFileObject,
  1704. FileObjectModifiedTime);
  1705. }
  1706. IopUpdateFileObjectTime(SourceFileObject, FileObjectStatusTime);
  1707. RenameEnd:
  1708. if (LocksHeld != FALSE) {
  1709. KeReleaseSharedExclusiveLockExclusive(SourceFileObject->Lock);
  1710. if (DestinationFileObject != NULL) {
  1711. KeReleaseSharedExclusiveLockExclusive(DestinationFileObject->Lock);
  1712. }
  1713. KeReleaseSharedExclusiveLockExclusive(SourceDirectoryFileObject->Lock);
  1714. if (DestinationDirectoryFileObject != SourceDirectoryFileObject) {
  1715. KeReleaseSharedExclusiveLockExclusive(
  1716. DestinationDirectoryFileObject->Lock);
  1717. }
  1718. }
  1719. if ((KSUCCESS(Status)) && (SourceFileObject != DestinationFileObject)) {
  1720. IopPathCleanCache(SourcePathPoint.PathEntry);
  1721. }
  1722. if (SourcePathPoint.PathEntry != NULL) {
  1723. IO_PATH_POINT_RELEASE_REFERENCE(&SourcePathPoint);
  1724. }
  1725. if (SourceDirectoryPathPoint.PathEntry != NULL) {
  1726. IO_PATH_POINT_RELEASE_REFERENCE(&SourceDirectoryPathPoint);
  1727. }
  1728. if (DestinationPathPoint.PathEntry != NULL) {
  1729. IO_PATH_POINT_RELEASE_REFERENCE(&DestinationPathPoint);
  1730. }
  1731. if (DestinationDirectoryPathPoint.PathEntry != NULL) {
  1732. IO_PATH_POINT_RELEASE_REFERENCE(&DestinationDirectoryPathPoint);
  1733. }
  1734. if (FoundPathPoint.PathEntry != NULL) {
  1735. IO_PATH_POINT_RELEASE_REFERENCE(&FoundPathPoint);
  1736. }
  1737. if (DestinationDirectory != NULL) {
  1738. MmFreePagedPool(DestinationDirectory);
  1739. }
  1740. if (DestinationFile != NULL) {
  1741. MmFreePagedPool(DestinationFile);
  1742. }
  1743. return Status;
  1744. }
  1745. KERNEL_API
  1746. KSTATUS
  1747. IoCreateSymbolicLink (
  1748. BOOL FromKernelMode,
  1749. PIO_HANDLE Directory,
  1750. PSTR LinkName,
  1751. ULONG LinkNameSize,
  1752. PSTR LinkTarget,
  1753. ULONG LinkTargetSize
  1754. )
  1755. /*++
  1756. Routine Description:
  1757. This routine attempts to create a new symbolic link at the given path.
  1758. The target of the symbolic link is not required to exist. The link path
  1759. must not already exist.
  1760. Arguments:
  1761. FromKernelMode - Supplies a boolean indicating the request is coming from
  1762. kernel mode.
  1763. Directory - Supplies an optional pointer to an open handle to a directory
  1764. for relative paths. Supply NULL to use the current working directory.
  1765. LinkName - Supplies a pointer to the path of the new link to create.
  1766. LinkNameSize - Supplies the length of the link name buffer in bytes,
  1767. including the null terminator.
  1768. LinkTarget - Supplies a pointer to the target of the link, the location the
  1769. link points to.
  1770. LinkTargetSize - Supplies the size of the link target buffer in bytes,
  1771. including the null terminator.
  1772. Return Value:
  1773. Status code.
  1774. --*/
  1775. {
  1776. UINTN BytesCompleted;
  1777. ULONG Flags;
  1778. PIO_HANDLE Handle;
  1779. IO_BUFFER IoBuffer;
  1780. KSTATUS Status;
  1781. Handle = NULL;
  1782. Flags = OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS | OPEN_FLAG_TRUNCATE |
  1783. OPEN_FLAG_SYMBOLIC_LINK;
  1784. Status = IopOpen(FromKernelMode,
  1785. Directory,
  1786. LinkName,
  1787. LinkNameSize,
  1788. IO_ACCESS_WRITE,
  1789. Flags,
  1790. IoObjectSymbolicLink,
  1791. NULL,
  1792. FILE_PERMISSION_ALL,
  1793. &Handle);
  1794. if (!KSUCCESS(Status)) {
  1795. goto CreateSymbolicLinkEnd;
  1796. }
  1797. Status = MmInitializeIoBuffer(&IoBuffer,
  1798. LinkTarget,
  1799. INVALID_PHYSICAL_ADDRESS,
  1800. LinkTargetSize,
  1801. IO_BUFFER_FLAG_KERNEL_MODE_DATA);
  1802. if (!KSUCCESS(Status)) {
  1803. goto CreateSymbolicLinkEnd;
  1804. }
  1805. Status = IoWriteAtOffset(Handle,
  1806. &IoBuffer,
  1807. 0,
  1808. LinkTargetSize,
  1809. 0,
  1810. WAIT_TIME_INDEFINITE,
  1811. &BytesCompleted,
  1812. NULL);
  1813. if (!KSUCCESS(Status)) {
  1814. goto CreateSymbolicLinkEnd;
  1815. }
  1816. CreateSymbolicLinkEnd:
  1817. if (Handle != NULL) {
  1818. IoClose(Handle);
  1819. }
  1820. return Status;
  1821. }
  1822. KERNEL_API
  1823. KSTATUS
  1824. IoReadSymbolicLink (
  1825. PIO_HANDLE Handle,
  1826. ULONG AllocationTag,
  1827. PSTR *LinkTarget,
  1828. PULONG LinkTargetSize
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. This routine reads the destination of a given open symbolic link, and
  1833. returns the information in a newly allocated buffer. It is the caller's
  1834. responsibility to free this memory from paged pool.
  1835. Arguments:
  1836. Handle - Supplies the open file handle to the symbolic link itself.
  1837. AllocationTag - Supplies the paged pool tag to use when creating the
  1838. allocation.
  1839. LinkTarget - Supplies a pointer where a newly allocated string will be
  1840. returned on success containing the target the link is pointing at.
  1841. LinkTargetSize - Supplies a pointer where the size of the link target in
  1842. bytes (including the null terminator) will be returned.
  1843. Return Value:
  1844. STATUS_SUCCESS if the link target was successfully returned.
  1845. STATUS_INSUFFICIENT_RESOURCES on allocation failure.
  1846. STATUS_NOT_READY if the contents of the symbolic link are not valid.
  1847. Other status codes on other failures.
  1848. --*/
  1849. {
  1850. UINTN BytesCompleted;
  1851. FILE_PROPERTIES FileProperties;
  1852. IO_BUFFER IoBuffer;
  1853. ULONGLONG Size;
  1854. KSTATUS Status;
  1855. PSTR TargetBuffer;
  1856. UINTN TargetBufferSize;
  1857. TargetBuffer = NULL;
  1858. //
  1859. // Reading the symbolic link is pretty much just reading the entire
  1860. // contents of the file into paged pool.
  1861. //
  1862. Status = IoGetFileInformation(Handle, &FileProperties);
  1863. if (!KSUCCESS(Status)) {
  1864. goto ReadSymbolicLinkEnd;
  1865. }
  1866. if (FileProperties.Type != IoObjectSymbolicLink) {
  1867. Status = STATUS_INVALID_PARAMETER;
  1868. goto ReadSymbolicLinkEnd;
  1869. }
  1870. READ_INT64_SYNC(&(FileProperties.FileSize), &Size);
  1871. TargetBufferSize = Size;
  1872. if (Size != TargetBufferSize) {
  1873. Status = STATUS_INSUFFICIENT_RESOURCES;
  1874. goto ReadSymbolicLinkEnd;
  1875. }
  1876. if (Size == 0) {
  1877. Status = STATUS_NOT_READY;
  1878. goto ReadSymbolicLinkEnd;
  1879. }
  1880. TargetBuffer = MmAllocatePagedPool(TargetBufferSize + 1, AllocationTag);
  1881. if (TargetBuffer == NULL) {
  1882. Status = STATUS_INSUFFICIENT_RESOURCES;
  1883. goto ReadSymbolicLinkEnd;
  1884. }
  1885. Status = MmInitializeIoBuffer(&IoBuffer,
  1886. TargetBuffer,
  1887. INVALID_PHYSICAL_ADDRESS,
  1888. TargetBufferSize,
  1889. IO_BUFFER_FLAG_KERNEL_MODE_DATA);
  1890. if (!KSUCCESS(Status)) {
  1891. goto ReadSymbolicLinkEnd;
  1892. }
  1893. Status = IoReadAtOffset(Handle,
  1894. &IoBuffer,
  1895. 0,
  1896. TargetBufferSize,
  1897. 0,
  1898. WAIT_TIME_INDEFINITE,
  1899. &BytesCompleted,
  1900. NULL);
  1901. if (!KSUCCESS(Status)) {
  1902. goto ReadSymbolicLinkEnd;
  1903. }
  1904. if (BytesCompleted != TargetBufferSize) {
  1905. Status = STATUS_NOT_READY;
  1906. goto ReadSymbolicLinkEnd;
  1907. }
  1908. TargetBuffer[TargetBufferSize] = '\0';
  1909. TargetBufferSize += 1;
  1910. Status = STATUS_SUCCESS;
  1911. ReadSymbolicLinkEnd:
  1912. if (!KSUCCESS(Status)) {
  1913. if (TargetBuffer != NULL) {
  1914. MmFreePagedPool(TargetBuffer);
  1915. TargetBuffer = NULL;
  1916. }
  1917. TargetBufferSize = 0;
  1918. }
  1919. *LinkTarget = TargetBuffer;
  1920. *LinkTargetSize = TargetBufferSize;
  1921. return Status;
  1922. }
  1923. KERNEL_API
  1924. KSTATUS
  1925. IoUserControl (
  1926. PIO_HANDLE Handle,
  1927. ULONG MinorCode,
  1928. BOOL FromKernelMode,
  1929. PVOID ContextBuffer,
  1930. UINTN ContextBufferSize
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. This routine performs a user control operation.
  1935. Arguments:
  1936. Handle - Supplies the open file handle.
  1937. MinorCode - Supplies the minor code of the request.
  1938. FromKernelMode - Supplies a boolean indicating whether or not this request
  1939. (and the buffer associated with it) originates from user mode (FALSE)
  1940. or kernel mode (TRUE).
  1941. ContextBuffer - Supplies a pointer to the context buffer allocated by the
  1942. caller for the request.
  1943. ContextBufferSize - Supplies the size of the supplied context buffer.
  1944. Return Value:
  1945. Status code.
  1946. --*/
  1947. {
  1948. PDEVICE Device;
  1949. PFILE_OBJECT FileObject;
  1950. KSTATUS Status;
  1951. FileObject = Handle->FileObject;
  1952. switch (FileObject->Properties.Type) {
  1953. case IoObjectBlockDevice:
  1954. case IoObjectCharacterDevice:
  1955. Device = FileObject->Device;
  1956. ASSERT(Device->Header.Type == ObjectDevice);
  1957. Status = IopSendUserControlIrp(Device,
  1958. MinorCode,
  1959. FromKernelMode,
  1960. ContextBuffer,
  1961. ContextBufferSize);
  1962. break;
  1963. case IoObjectTerminalMaster:
  1964. case IoObjectTerminalSlave:
  1965. Status = IopTerminalUserControl(Handle,
  1966. MinorCode,
  1967. FromKernelMode,
  1968. ContextBuffer,
  1969. ContextBufferSize);
  1970. break;
  1971. case IoObjectSocket:
  1972. Status = IoSocketUserControl(Handle,
  1973. MinorCode,
  1974. FromKernelMode,
  1975. ContextBuffer,
  1976. ContextBufferSize);
  1977. break;
  1978. default:
  1979. Status = STATUS_NOT_SUPPORTED;
  1980. break;
  1981. }
  1982. return Status;
  1983. }
  1984. KERNEL_API
  1985. KSTATUS
  1986. IoGetDevice (
  1987. PIO_HANDLE Handle,
  1988. PDEVICE *Device
  1989. )
  1990. /*++
  1991. Routine Description:
  1992. This routine returns the actual device backing the given I/O object. Not
  1993. all I/O objects are actually backed by a single device. For file and
  1994. directory objects, this routine will return a pointer to the volume.
  1995. Arguments:
  1996. Handle - Supplies the open file handle.
  1997. Device - Supplies a pointer where the underlying I/O device will be
  1998. returned.
  1999. Return Value:
  2000. Status code.
  2001. --*/
  2002. {
  2003. PDEVICE FileDevice;
  2004. PFILE_OBJECT FileObject;
  2005. PPAGING_IO_HANDLE PagingIoHandle;
  2006. //
  2007. // For paging I/O handles, this routine is called during page in (so it
  2008. // can't fault). Get the device directly out of the paging I/O handle.
  2009. //
  2010. if (Handle->HandleType == IoHandleTypePaging) {
  2011. PagingIoHandle = (PPAGING_IO_HANDLE)Handle;
  2012. *Device = PagingIoHandle->Device;
  2013. if (PagingIoHandle->Device != NULL) {
  2014. return STATUS_SUCCESS;
  2015. }
  2016. return STATUS_INVALID_CONFIGURATION;
  2017. }
  2018. FileObject = Handle->FileObject;
  2019. FileDevice = FileObject->Device;
  2020. if (IS_DEVICE_OR_VOLUME(FileDevice)) {
  2021. *Device = FileDevice;
  2022. return STATUS_SUCCESS;
  2023. }
  2024. return STATUS_INVALID_CONFIGURATION;
  2025. }
  2026. KERNEL_API
  2027. BOOL
  2028. IoIsPageFileAccessSupported (
  2029. PIO_HANDLE Handle
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. This routine determines whether or not page file access is supported on the
  2034. given handle.
  2035. Arguments:
  2036. Handle - Supplies a pointer to the I/O handle.
  2037. Return Value:
  2038. Returns TRUE if the handle supports page file I/O, or FALSE otherwise.
  2039. --*/
  2040. {
  2041. if (Handle->HandleType == IoHandleTypePaging) {
  2042. return TRUE;
  2043. }
  2044. return FALSE;
  2045. }
  2046. KERNEL_API
  2047. KSTATUS
  2048. IoGetGlobalStatistics (
  2049. PIO_GLOBAL_STATISTICS Statistics
  2050. )
  2051. /*++
  2052. Routine Description:
  2053. This routine returns a snap of the global I/O statistics counters.
  2054. Arguments:
  2055. Statistics - Supplies a pointer to the global I/O statistics.
  2056. Return Value:
  2057. STATUS_SUCCESS on success.
  2058. STATUS_INVALID_PARAMETER if the version is less than
  2059. IO_GLOBAL_STATISTICS_VERSION.
  2060. --*/
  2061. {
  2062. if ((Statistics->Version < IO_GLOBAL_STATISTICS_VERSION) ||
  2063. (Statistics->Version > IO_GLOBAL_STATISTICS_MAX_VERSION)) {
  2064. return STATUS_INVALID_PARAMETER;
  2065. }
  2066. Statistics->BytesRead = RtlAtomicOr64(&(IoGlobalStatistics.BytesRead), 0);
  2067. Statistics->BytesWritten = RtlAtomicOr64(&(IoGlobalStatistics.BytesWritten),
  2068. 0);
  2069. Statistics->PagingBytesRead =
  2070. RtlAtomicOr64(&(IoGlobalStatistics.PagingBytesRead), 0);
  2071. Statistics->PagingBytesWritten =
  2072. RtlAtomicOr64(&(IoGlobalStatistics.PagingBytesWritten), 0);
  2073. return STATUS_SUCCESS;
  2074. }
  2075. KSTATUS
  2076. IoOpenPageFile (
  2077. PSTR Path,
  2078. ULONG PathSize,
  2079. ULONG Access,
  2080. ULONG Flags,
  2081. PIO_HANDLE *Handle,
  2082. PULONGLONG FileSize
  2083. )
  2084. /*++
  2085. Routine Description:
  2086. This routine opens a page file. This routine is to be used only
  2087. internally by MM.
  2088. Arguments:
  2089. Path - Supplies a pointer to the string containing the file path to open.
  2090. PathSize - Supplies the length of the path buffer in bytes, including
  2091. the null terminator.
  2092. Access - Supplies the desired access permissions to the object. See
  2093. IO_ACCESS_* definitions.
  2094. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  2095. See OPEN_FLAG_* definitions.
  2096. Handle - Supplies a pointer where a pointer to the open I/O handle will be
  2097. returned on success.
  2098. FileSize - Supplies a pointer where the file size in bytes will be returned
  2099. on success.
  2100. Return Value:
  2101. Status code.
  2102. --*/
  2103. {
  2104. PDEVICE Device;
  2105. PFILE_OBJECT FileObject;
  2106. PIO_HANDLE IoHandle;
  2107. ULONGLONG LocalFileSize;
  2108. PPAGING_IO_HANDLE NewHandle;
  2109. KSTATUS Status;
  2110. *FileSize = 0;
  2111. *Handle = NULL;
  2112. IoHandle = NULL;
  2113. NewHandle = NULL;
  2114. ASSERT(KeGetRunLevel() == RunLevelLow);
  2115. //
  2116. // Allocate the basic structure.
  2117. //
  2118. NewHandle = MmAllocateNonPagedPool(sizeof(PAGING_IO_HANDLE),
  2119. IO_ALLOCATION_TAG);
  2120. if (NewHandle == NULL) {
  2121. Status = STATUS_INSUFFICIENT_RESOURCES;
  2122. goto OpenPageFileEnd;
  2123. }
  2124. RtlZeroMemory(NewHandle, sizeof(PAGING_IO_HANDLE));
  2125. NewHandle->HandleType = IoHandleTypePaging;
  2126. //
  2127. // Open the file normally, but with the page file and non-cached flags set.
  2128. //
  2129. Flags |= OPEN_FLAG_PAGE_FILE | OPEN_FLAG_NON_CACHED;
  2130. Status = IopOpen(TRUE,
  2131. NULL,
  2132. Path,
  2133. PathSize,
  2134. Access,
  2135. Flags,
  2136. IoObjectInvalid,
  2137. NULL,
  2138. 0,
  2139. &IoHandle);
  2140. if (!KSUCCESS(Status)) {
  2141. goto OpenPageFileEnd;
  2142. }
  2143. //
  2144. // Even if a page file exists on this device, it might not be intended for
  2145. // use on this sytem. If the device is not an intended paging device, then
  2146. // return failure.
  2147. //
  2148. FileObject = IoHandle->FileObject;
  2149. Device = FileObject->Device;
  2150. if (!IS_DEVICE_OR_VOLUME(Device)) {
  2151. Status = STATUS_NOT_SUPPORTED;
  2152. goto OpenPageFileEnd;
  2153. }
  2154. if ((Device->Flags & DEVICE_FLAG_PAGING_DEVICE) == 0) {
  2155. Status = STATUS_NO_SUCH_FILE;
  2156. goto OpenPageFileEnd;
  2157. }
  2158. NewHandle->DeviceContext = IoHandle->DeviceContext;
  2159. NewHandle->Device = Device;
  2160. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &LocalFileSize);
  2161. NewHandle->Capacity = LocalFileSize;
  2162. NewHandle->IoHandle = IoHandle;
  2163. NewHandle->OffsetAlignment = FileObject->Properties.BlockSize;
  2164. NewHandle->SizeAlignment = FileObject->Properties.BlockSize;
  2165. *FileSize = NewHandle->Capacity;
  2166. Status = STATUS_SUCCESS;
  2167. OpenPageFileEnd:
  2168. if (!KSUCCESS(Status)) {
  2169. if (IoHandle != NULL) {
  2170. IoClose(IoHandle);
  2171. }
  2172. if (NewHandle != NULL) {
  2173. MmFreeNonPagedPool(NewHandle);
  2174. }
  2175. NewHandle = NULL;
  2176. }
  2177. *Handle = (PIO_HANDLE)NewHandle;
  2178. return Status;
  2179. }
  2180. KSTATUS
  2181. IopOpen (
  2182. BOOL FromKernelMode,
  2183. PIO_HANDLE Directory,
  2184. PSTR Path,
  2185. ULONG PathLength,
  2186. ULONG Access,
  2187. ULONG Flags,
  2188. IO_OBJECT_TYPE TypeOverride,
  2189. PVOID OverrideParameter,
  2190. FILE_PERMISSIONS CreatePermissions,
  2191. PIO_HANDLE *Handle
  2192. )
  2193. /*++
  2194. Routine Description:
  2195. This routine opens a file, device, pipe, or other I/O object.
  2196. Arguments:
  2197. FromKernelMode - Supplies a boolean indicating the request is coming from
  2198. kernel mode.
  2199. Directory - Supplies an optional pointer to a handle to a directory to use
  2200. if the given path is relative. Supply NULL to use the current working
  2201. directory.
  2202. Path - Supplies a pointer to the path to open.
  2203. PathLength - Supplies the length of the path buffer in bytes, including the
  2204. null terminator.
  2205. Access - Supplies the desired access permissions to the object. See
  2206. IO_ACCESS_* definitions.
  2207. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  2208. See OPEN_FLAG_* definitions.
  2209. TypeOverride - Supplies an object type that the regular file should be
  2210. converted to. Supply the invalid object type to specify no override.
  2211. OverrideParameter - Supplies an optional parameter to send along with the
  2212. override type.
  2213. CreatePermissions - Supplies the permissions to apply for created object
  2214. on create operations.
  2215. Handle - Supplies a pointer where a pointer to the open I/O handle will be
  2216. returned on success.
  2217. Return Value:
  2218. Status code.
  2219. --*/
  2220. {
  2221. PFILE_OBJECT DirectoryFileObject;
  2222. PPATH_POINT DirectoryPathPoint;
  2223. PFILE_OBJECT FileObject;
  2224. PATH_POINT PathPoint;
  2225. PKPROCESS Process;
  2226. KSTATUS Status;
  2227. DirectoryPathPoint = NULL;
  2228. PathPoint.PathEntry = NULL;
  2229. PathPoint.MountPoint = NULL;
  2230. //
  2231. // If the request is meant to unlink on creation, make sure that the create
  2232. // flag is also set and prepare to fail if the file already exists.
  2233. //
  2234. ASSERT(((Flags & OPEN_FLAG_UNLINK_ON_CREATE) == 0) ||
  2235. ((Flags & (OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS)) ==
  2236. (OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS)));
  2237. //
  2238. // If the caller specified a directory, validate that it is a directory,
  2239. // and perform permission checking if search permissions were not granted
  2240. // upon open.
  2241. //
  2242. if (Directory != NULL) {
  2243. DirectoryFileObject = Directory->FileObject;
  2244. DirectoryPathPoint = &(Directory->PathPoint);
  2245. if (DirectoryFileObject->Properties.Type != IoObjectRegularDirectory) {
  2246. Status = STATUS_NOT_A_DIRECTORY;
  2247. goto OpenEnd;
  2248. }
  2249. ASSERT(DirectoryFileObject ==
  2250. DirectoryPathPoint->PathEntry->FileObject);
  2251. }
  2252. //
  2253. // Apply the umask.
  2254. //
  2255. if ((Flags & OPEN_FLAG_CREATE) != 0) {
  2256. Process = PsGetCurrentProcess();
  2257. CreatePermissions &= ~(Process->Umask);
  2258. }
  2259. //
  2260. // If there is no path, create an anonymous object.
  2261. //
  2262. if (PathLength == 0) {
  2263. Status = IopCreateAnonymousObject(Access,
  2264. Flags,
  2265. TypeOverride,
  2266. OverrideParameter,
  2267. CreatePermissions,
  2268. &PathPoint);
  2269. //
  2270. // There is a path, so walk it to create or open your destiny.
  2271. //
  2272. } else {
  2273. //
  2274. // Change the override if the create flag is on.
  2275. //
  2276. if ((Flags & OPEN_FLAG_CREATE) != 0) {
  2277. if ((Flags & OPEN_FLAG_DIRECTORY) != 0) {
  2278. ASSERT(TypeOverride == IoObjectInvalid);
  2279. TypeOverride = IoObjectRegularDirectory;
  2280. } else if (TypeOverride == IoObjectInvalid) {
  2281. TypeOverride = IoObjectRegularFile;
  2282. }
  2283. }
  2284. Status = IopPathWalk(FromKernelMode,
  2285. DirectoryPathPoint,
  2286. &Path,
  2287. &PathLength,
  2288. Flags,
  2289. TypeOverride,
  2290. OverrideParameter,
  2291. CreatePermissions,
  2292. &PathPoint);
  2293. }
  2294. if (!KSUCCESS(Status)) {
  2295. goto OpenEnd;
  2296. }
  2297. //
  2298. // Check the directory flag against the type.
  2299. //
  2300. FileObject = PathPoint.PathEntry->FileObject;
  2301. //
  2302. // If the directory flag is set, the resulting file object is required to
  2303. // be a directory.
  2304. //
  2305. if ((Flags & OPEN_FLAG_DIRECTORY) != 0) {
  2306. if ((FileObject->Properties.Type != IoObjectRegularDirectory) &&
  2307. (FileObject->Properties.Type != IoObjectObjectDirectory)) {
  2308. Status = STATUS_NOT_A_DIRECTORY;
  2309. goto OpenEnd;
  2310. }
  2311. //
  2312. // Sockets can only be opened if they're being created or just opened for
  2313. // information.
  2314. //
  2315. } else if (FileObject->Properties.Type == IoObjectSocket) {
  2316. if ((TypeOverride != IoObjectSocket) && (Access != 0)) {
  2317. Status = STATUS_NO_SUCH_DEVICE_OR_ADDRESS;
  2318. goto OpenEnd;
  2319. }
  2320. //
  2321. // If the directory flag is not set, then check the override against the
  2322. // object.
  2323. //
  2324. } else {
  2325. //
  2326. // If the object is a directory, then fail if either an override was
  2327. // specified (meaning a create is trying to occur) or the open is for
  2328. // anything other than read. Turns out opening a directory for read is
  2329. // allowed, it's just that no I/O can be performed on it.
  2330. //
  2331. if ((FileObject->Properties.Type == IoObjectRegularDirectory) ||
  2332. (FileObject->Properties.Type == IoObjectObjectDirectory)) {
  2333. if (((Access & (IO_ACCESS_WRITE | IO_ACCESS_EXECUTE)) != 0) ||
  2334. (TypeOverride != IoObjectInvalid)) {
  2335. if (TypeOverride == IoObjectSymbolicLink) {
  2336. Status = STATUS_FILE_EXISTS;
  2337. } else {
  2338. Status = STATUS_FILE_IS_DIRECTORY;
  2339. }
  2340. goto OpenEnd;
  2341. }
  2342. }
  2343. }
  2344. //
  2345. // Check permissions on path entry.
  2346. //
  2347. if (FromKernelMode == FALSE) {
  2348. Status = IopCheckPermissions(FromKernelMode, &PathPoint, Access);
  2349. if (!KSUCCESS(Status)) {
  2350. goto OpenEnd;
  2351. }
  2352. }
  2353. //
  2354. // Open the path point, which upon success takes another reference on the
  2355. // path point.
  2356. //
  2357. Status = IopOpenPathPoint(&PathPoint, Access, Flags, Handle);
  2358. if (!KSUCCESS(Status)) {
  2359. goto OpenEnd;
  2360. }
  2361. Status = STATUS_SUCCESS;
  2362. OpenEnd:
  2363. //
  2364. // Do not use the path point release reference macro here, the mount point
  2365. // may be null if an anonymous object was created.
  2366. //
  2367. if (PathPoint.PathEntry != NULL) {
  2368. IoPathEntryReleaseReference(PathPoint.PathEntry);
  2369. if (PathPoint.MountPoint != NULL) {
  2370. IoMountPointReleaseReference(PathPoint.MountPoint);
  2371. }
  2372. }
  2373. return Status;
  2374. }
  2375. KSTATUS
  2376. IopOpenPathPoint (
  2377. PPATH_POINT PathPoint,
  2378. ULONG Access,
  2379. ULONG Flags,
  2380. PIO_HANDLE *Handle
  2381. )
  2382. /*++
  2383. Routine Description:
  2384. This routine opens a path entry object. This routine must be called
  2385. carefully by internal functions, as it skips all permission checks.
  2386. Arguments:
  2387. PathPoint - Supplies a pointer to the path point to open. Upon success this
  2388. routine will add a reference to the path point's path entry and mount
  2389. point.
  2390. Access - Supplies the desired access permissions to the object. See
  2391. IO_ACCESS_* definitions.
  2392. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  2393. See OPEN_FLAG_* definitions.
  2394. Handle - Supplies a pointer where a pointer to the open I/O handle will be
  2395. returned on success.
  2396. Return Value:
  2397. Status code.
  2398. --*/
  2399. {
  2400. IRP_CLOSE CloseIrp;
  2401. PDEVICE Device;
  2402. PFILE_OBJECT FileObject;
  2403. PIO_HANDLE NewHandle;
  2404. PVOID OldDeviceContext;
  2405. ULONG OldFileObjectFlags;
  2406. IRP_OPEN OpenIrp;
  2407. BOOL OpenIrpSent;
  2408. KSTATUS Status;
  2409. Device = NULL;
  2410. NewHandle = NULL;
  2411. OpenIrpSent = FALSE;
  2412. //
  2413. // Create an I/O handle.
  2414. //
  2415. Status = IopCreateIoHandle(&NewHandle);
  2416. if (!KSUCCESS(Status)) {
  2417. goto OpenPathEntryEnd;
  2418. }
  2419. IO_COPY_PATH_POINT(&(NewHandle->PathPoint), PathPoint);
  2420. NewHandle->OpenFlags = Flags;
  2421. NewHandle->Access = Access;
  2422. FileObject = PathPoint->PathEntry->FileObject;
  2423. NewHandle->FileObject = FileObject;
  2424. switch (FileObject->Properties.Type) {
  2425. case IoObjectRegularFile:
  2426. case IoObjectSymbolicLink:
  2427. case IoObjectBlockDevice:
  2428. RtlZeroMemory(&OpenIrp, sizeof(IRP_OPEN));
  2429. OpenIrp.FileProperties = &(FileObject->Properties);
  2430. OpenIrp.IoState = FileObject->IoState;
  2431. Device = FileObject->Device;
  2432. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  2433. //
  2434. // If the file object is cacheable and has not been opened, call the
  2435. // driver to get a context with full access.
  2436. //
  2437. if ((IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE) &&
  2438. ((FileObject->Flags & FILE_OBJECT_FLAG_OPEN) == 0)) {
  2439. OpenIrp.DesiredAccess = IO_ACCESS_READ | IO_ACCESS_WRITE;
  2440. OpenIrp.OpenFlags = Flags;
  2441. Status = IopSendOpenIrp(Device, &OpenIrp);
  2442. if (!KSUCCESS(Status)) {
  2443. goto OpenPathEntryEnd;
  2444. }
  2445. //
  2446. // If someone wants to replace a cacheable file, think about this.
  2447. //
  2448. ASSERT(OpenIrp.Replacement == NULL);
  2449. //
  2450. // Now try to insert the device context into the file object. First
  2451. // exchange the device context pointer. It is not safe to mark it
  2452. // open until the context is set.
  2453. //
  2454. OldDeviceContext = (PVOID)RtlAtomicCompareExchange(
  2455. (PVOID)&(FileObject->DeviceContext),
  2456. (UINTN)OpenIrp.DeviceContext,
  2457. (UINTN)NULL);
  2458. //
  2459. // If the old context was NULL, then this caller might have won the
  2460. // race to set it. That said, some devices return a NULL context.
  2461. // So additionally try to set the open status. If this race is lost
  2462. // then send the close IRP. The other open won.
  2463. //
  2464. if (OldDeviceContext == NULL) {
  2465. OldFileObjectFlags = RtlAtomicOr32(&(FileObject->Flags),
  2466. FILE_OBJECT_FLAG_OPEN);
  2467. if ((OldFileObjectFlags & FILE_OBJECT_FLAG_OPEN) != 0) {
  2468. CloseIrp.DeviceContext = OpenIrp.DeviceContext;
  2469. IopSendCloseIrp(Device, &CloseIrp);
  2470. }
  2471. //
  2472. // Otherwise, this caller lost the race. It should destroy its
  2473. // context before continuing. It is not safe, however, to assert
  2474. // that the file object is open. The winner of the context race may
  2475. // not have set the open flag yet.
  2476. //
  2477. } else {
  2478. CloseIrp.DeviceContext = OpenIrp.DeviceContext;
  2479. IopSendCloseIrp(Device, &CloseIrp);
  2480. }
  2481. }
  2482. //
  2483. // If the file object is going to be used in the paging path or is not
  2484. // cacheable, open up a device context that will be stored in the I/O
  2485. // handle.
  2486. //
  2487. if ((IO_IS_FILE_OBJECT_CACHEABLE(FileObject) == FALSE) ||
  2488. ((Flags & OPEN_FLAG_PAGE_FILE) != 0) ||
  2489. ((Flags & OPEN_FLAG_PAGING_DEVICE) != 0)) {
  2490. OpenIrp.DesiredAccess = Access;
  2491. OpenIrp.OpenFlags = Flags;
  2492. Status = IopSendOpenIrp(Device, &OpenIrp);
  2493. if (!KSUCCESS(Status)) {
  2494. goto OpenPathEntryEnd;
  2495. }
  2496. ASSERT(OpenIrp.Replacement == NULL);
  2497. OpenIrpSent = TRUE;
  2498. NewHandle->DeviceContext = OpenIrp.DeviceContext;
  2499. }
  2500. //
  2501. // If the caller requested a truncate operation and it is allowed on
  2502. // this object type, modify the file object's size.
  2503. //
  2504. if (((Flags & OPEN_FLAG_TRUNCATE) != 0) &&
  2505. ((Flags & OPEN_FLAG_PAGE_FILE) == 0)) {
  2506. Status = IopModifyFileObjectSize(FileObject,
  2507. NewHandle->DeviceContext,
  2508. 0);
  2509. if (!KSUCCESS(Status)) {
  2510. goto OpenPathEntryEnd;
  2511. }
  2512. }
  2513. Status = STATUS_SUCCESS;
  2514. break;
  2515. case IoObjectCharacterDevice:
  2516. case IoObjectRegularDirectory:
  2517. RtlZeroMemory(&OpenIrp, sizeof(IRP_OPEN));
  2518. OpenIrp.FileProperties = &(FileObject->Properties);
  2519. OpenIrp.IoState = FileObject->IoState;
  2520. OpenIrp.DesiredAccess = Access;
  2521. OpenIrp.OpenFlags = Flags;
  2522. Device = FileObject->Device;
  2523. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  2524. Status = IopSendOpenIrp(Device, &OpenIrp);
  2525. if (!KSUCCESS(Status)) {
  2526. goto OpenPathEntryEnd;
  2527. }
  2528. OpenIrpSent = TRUE;
  2529. NewHandle->DeviceContext = OpenIrp.DeviceContext;
  2530. //
  2531. // If the caller actually wanted to replace this object with something
  2532. // else, overwrite the handle. Directories cannot be replaced,
  2533. // since they are too heavily involved with their path entries, which
  2534. // do not get overwritten.
  2535. //
  2536. if (OpenIrp.Replacement != NULL) {
  2537. ASSERT(FileObject->Properties.Type != IoObjectRegularDirectory);
  2538. IopOverwriteIoHandle(NewHandle, OpenIrp.Replacement);
  2539. }
  2540. break;
  2541. case IoObjectPipe:
  2542. Status = IopOpenPipe(NewHandle);
  2543. break;
  2544. //
  2545. // Object directories don't need anything to be opened.
  2546. //
  2547. case IoObjectObjectDirectory:
  2548. Status = STATUS_SUCCESS;
  2549. break;
  2550. case IoObjectSocket:
  2551. Status = IopOpenSocket(NewHandle);
  2552. break;
  2553. case IoObjectTerminalMaster:
  2554. Status = IopTerminalOpenMaster(NewHandle);
  2555. break;
  2556. case IoObjectTerminalSlave:
  2557. Status = IopTerminalOpenSlave(NewHandle);
  2558. break;
  2559. case IoObjectSharedMemoryObject:
  2560. if ((Flags & OPEN_FLAG_TRUNCATE) != 0) {
  2561. Status = IopModifyFileObjectSize(FileObject, NULL, 0);
  2562. if (!KSUCCESS(Status)) {
  2563. goto OpenPathEntryEnd;
  2564. }
  2565. }
  2566. Status = STATUS_SUCCESS;
  2567. break;
  2568. default:
  2569. ASSERT(FALSE);
  2570. Status = STATUS_INVALID_CONFIGURATION;
  2571. break;
  2572. }
  2573. if (!KSUCCESS(Status)) {
  2574. goto OpenPathEntryEnd;
  2575. }
  2576. //
  2577. // Do not use the default path point add reference macro. An anonymous
  2578. // object does not have a mount point.
  2579. //
  2580. IoPathEntryAddReference(PathPoint->PathEntry);
  2581. if (PathPoint->MountPoint != NULL) {
  2582. IoMountPointAddReference(PathPoint->MountPoint);
  2583. }
  2584. Status = STATUS_SUCCESS;
  2585. OpenPathEntryEnd:
  2586. if (!KSUCCESS(Status)) {
  2587. if (OpenIrpSent != FALSE) {
  2588. CloseIrp.DeviceContext = NewHandle->DeviceContext;
  2589. IopSendCloseIrp(Device, &CloseIrp);
  2590. }
  2591. if (NewHandle != NULL) {
  2592. NewHandle->PathPoint.PathEntry = NULL;
  2593. IoIoHandleReleaseReference(NewHandle);
  2594. NewHandle = NULL;
  2595. }
  2596. }
  2597. ASSERT((NewHandle == NULL) || (NewHandle->PathPoint.PathEntry != NULL));
  2598. *Handle = NewHandle;
  2599. return Status;
  2600. }
  2601. KSTATUS
  2602. IopOpenDevice (
  2603. PDEVICE Device,
  2604. ULONG Access,
  2605. ULONG Flags,
  2606. PIO_HANDLE *Handle
  2607. )
  2608. /*++
  2609. Routine Description:
  2610. This routine opens a device or volume.
  2611. Arguments:
  2612. Device - Supplies a pointer to a device to open.
  2613. Access - Supplies the desired access permissions to the object. See
  2614. IO_ACCESS_* definitions.
  2615. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  2616. See OPEN_FLAG_* definitions.
  2617. Handle - Supplies a pointer where a pointer to the open I/O handle will be
  2618. returned on success.
  2619. Return Value:
  2620. Status code.
  2621. --*/
  2622. {
  2623. PIO_HANDLE NewHandle;
  2624. PCHAR ObjectPath;
  2625. KSTATUS Status;
  2626. ASSERT((Device->Header.Type == ObjectDevice) ||
  2627. (Device->Header.Type == ObjectVolume));
  2628. NewHandle = NULL;
  2629. ObjectPath = ObGetFullPath(Device, DEVICE_ALLOCATION_TAG);
  2630. if (ObjectPath == NULL) {
  2631. Status = STATUS_INSUFFICIENT_RESOURCES;
  2632. goto OpenDeviceEnd;
  2633. }
  2634. //
  2635. // Open the device from kernel mode.
  2636. //
  2637. Status = IopOpen(TRUE,
  2638. NULL,
  2639. ObjectPath,
  2640. RtlStringLength(ObjectPath) + 1,
  2641. Access,
  2642. Flags,
  2643. IoObjectInvalid,
  2644. NULL,
  2645. 0,
  2646. &NewHandle);
  2647. if (!KSUCCESS(Status)) {
  2648. goto OpenDeviceEnd;
  2649. }
  2650. OpenDeviceEnd:
  2651. if (ObjectPath != NULL) {
  2652. MmFreePagedPool(ObjectPath);
  2653. }
  2654. *Handle = NewHandle;
  2655. return Status;
  2656. }
  2657. KSTATUS
  2658. IopCreateSpecialIoObject (
  2659. ULONG Flags,
  2660. IO_OBJECT_TYPE Type,
  2661. PVOID OverrideParameter,
  2662. FILE_PERMISSIONS CreatePermissions,
  2663. PFILE_OBJECT *FileObject
  2664. )
  2665. /*++
  2666. Routine Description:
  2667. This routine creates a special file object.
  2668. Arguments:
  2669. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  2670. See OPEN_FLAG_* definitions.
  2671. Type - Supplies the type of special object to create.
  2672. OverrideParameter - Supplies an optional parameter to send along with the
  2673. override type.
  2674. CreatePermissions - Supplies the permissions to assign to the new file.
  2675. FileObject - Supplies a pointer where a pointer to the new file object
  2676. will be returned on success.
  2677. Return Value:
  2678. Status code.
  2679. --*/
  2680. {
  2681. KSTATUS Status;
  2682. switch (Type) {
  2683. case IoObjectPipe:
  2684. Status = IopCreatePipe(NULL, 0, CreatePermissions, FileObject);
  2685. break;
  2686. case IoObjectSocket:
  2687. Status = IopCreateSocket(OverrideParameter,
  2688. CreatePermissions,
  2689. FileObject);
  2690. break;
  2691. case IoObjectTerminalMaster:
  2692. case IoObjectTerminalSlave:
  2693. Status = IopCreateTerminal(Type,
  2694. OverrideParameter,
  2695. CreatePermissions,
  2696. FileObject);
  2697. break;
  2698. case IoObjectSharedMemoryObject:
  2699. Status = IopCreateSharedMemoryObject(NULL,
  2700. 0,
  2701. Flags,
  2702. CreatePermissions,
  2703. FileObject);
  2704. break;
  2705. default:
  2706. ASSERT(FALSE);
  2707. return STATUS_NOT_SUPPORTED;
  2708. }
  2709. return Status;
  2710. }
  2711. KSTATUS
  2712. IopClose (
  2713. PIO_HANDLE IoHandle
  2714. )
  2715. /*++
  2716. Routine Description:
  2717. This routine shuts down an I/O handle that is about to be destroyed.
  2718. Arguments:
  2719. IoHandle - Supplies a pointer to the I/O handle returned when the file was
  2720. opened.
  2721. Return Value:
  2722. Status code.
  2723. --*/
  2724. {
  2725. IRP_CLOSE CloseIrp;
  2726. PDEVICE Device;
  2727. PFILE_OBJECT FileObject;
  2728. KSTATUS Status;
  2729. //
  2730. // Use the file object in the path entry rather than the I/O handle so that
  2731. // opens and closes are balanced.
  2732. //
  2733. FileObject = NULL;
  2734. if (IoHandle->PathPoint.PathEntry != NULL) {
  2735. FileObject = IoHandle->PathPoint.PathEntry->FileObject;
  2736. switch (FileObject->Properties.Type) {
  2737. case IoObjectRegularFile:
  2738. case IoObjectRegularDirectory:
  2739. case IoObjectSymbolicLink:
  2740. case IoObjectBlockDevice:
  2741. case IoObjectCharacterDevice:
  2742. //
  2743. // If the handle received a device context on open, close it.
  2744. //
  2745. if ((IO_IS_FILE_OBJECT_CACHEABLE(FileObject) == FALSE) ||
  2746. ((IoHandle->OpenFlags & OPEN_FLAG_PAGE_FILE) != 0) ||
  2747. ((IoHandle->OpenFlags & OPEN_FLAG_PAGING_DEVICE) != 0)) {
  2748. CloseIrp.DeviceContext = IoHandle->DeviceContext;
  2749. Device = FileObject->Device;
  2750. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  2751. Status = IopSendCloseIrp(Device, &CloseIrp);
  2752. //
  2753. // Otherwise, just report success.
  2754. //
  2755. } else {
  2756. Status = STATUS_SUCCESS;
  2757. }
  2758. break;
  2759. case IoObjectPipe:
  2760. Status = IopClosePipe(IoHandle);
  2761. break;
  2762. case IoObjectSocket:
  2763. Status = IopCloseSocket(IoHandle);
  2764. break;
  2765. case IoObjectTerminalMaster:
  2766. Status = IopTerminalCloseMaster(IoHandle);
  2767. break;
  2768. case IoObjectTerminalSlave:
  2769. Status = IopTerminalCloseSlave(IoHandle);
  2770. break;
  2771. default:
  2772. Status = STATUS_SUCCESS;
  2773. break;
  2774. }
  2775. if (!KSUCCESS(Status)) {
  2776. goto CloseEnd;
  2777. }
  2778. }
  2779. //
  2780. // Clear the asynchronous receiver information from this handle.
  2781. //
  2782. if (IoHandle->Async != NULL) {
  2783. IoSetHandleAsynchronous(IoHandle, 0, FALSE);
  2784. MmFreePagedPool(IoHandle->Async);
  2785. IoHandle->Async = NULL;
  2786. }
  2787. //
  2788. // Let go of the path point, and slide gently into the night. Be careful,
  2789. // as anonymous objects do not have a mount point. Also handles that failed
  2790. // to open do not have a path entry.
  2791. //
  2792. if (IoHandle->PathPoint.PathEntry != NULL) {
  2793. //
  2794. // If the file object in the handle is not the same as the one in the
  2795. // path entry, release the reference on the one in the handle.
  2796. //
  2797. if (FileObject != IoHandle->FileObject) {
  2798. IopFileObjectReleaseReference(IoHandle->FileObject);
  2799. }
  2800. IoPathEntryReleaseReference(IoHandle->PathPoint.PathEntry);
  2801. if (IoHandle->PathPoint.MountPoint != NULL) {
  2802. IoMountPointReleaseReference(IoHandle->PathPoint.MountPoint);
  2803. }
  2804. }
  2805. Status = STATUS_SUCCESS;
  2806. CloseEnd:
  2807. return Status;
  2808. }
  2809. KSTATUS
  2810. IopDelete (
  2811. BOOL FromKernelMode,
  2812. PIO_HANDLE Directory,
  2813. PSTR Path,
  2814. ULONG PathSize,
  2815. ULONG Flags
  2816. )
  2817. /*++
  2818. Routine Description:
  2819. This routine attempts to delete the object at the given path. If the path
  2820. points to a directory, the directory must be empty. If the path points to
  2821. a file object or shared memory object, its hard link count is decremented.
  2822. If the hard link count reaches zero and no processes have the object open,
  2823. the contents of the object are destroyed. If processes have open handles to
  2824. the object, the destruction of the object contents are deferred until the
  2825. last handle to the old file is closed. If the path points to a symbolic
  2826. link, the link itself is removed and not the destination. The removal of
  2827. the entry from the directory is immediate.
  2828. Arguments:
  2829. FromKernelMode - Supplies a boolean indicating the request is coming from
  2830. kernel mode.
  2831. Directory - Supplies an optional pointer to an open handle to a directory
  2832. for relative paths. Supply NULL to use the current working directory.
  2833. Path - Supplies a pointer to the path to delete.
  2834. PathSize - Supplies the length of the path buffer in bytes, including the
  2835. null terminator.
  2836. Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
  2837. Return Value:
  2838. Status code.
  2839. --*/
  2840. {
  2841. PPATH_ENTRY DirectoryEntry;
  2842. PFILE_OBJECT DirectoryFileObject;
  2843. PPATH_POINT DirectoryPathPoint;
  2844. PATH_POINT PathPoint;
  2845. KSTATUS Status;
  2846. DirectoryPathPoint = NULL;
  2847. PathPoint.PathEntry = NULL;
  2848. //
  2849. // If the caller specified a directory, validate that it is a directory.
  2850. // Search permission checking for the directory is done in the path walk
  2851. // code.
  2852. //
  2853. if (Directory != NULL) {
  2854. DirectoryPathPoint = &(Directory->PathPoint);
  2855. DirectoryEntry = DirectoryPathPoint->PathEntry;
  2856. DirectoryFileObject = DirectoryEntry->FileObject;
  2857. if (DirectoryFileObject->Properties.Type != IoObjectRegularDirectory) {
  2858. Status = STATUS_NOT_A_DIRECTORY;
  2859. goto DeleteEnd;
  2860. }
  2861. ASSERT(Directory->FileObject == DirectoryFileObject);
  2862. }
  2863. Status = IopPathWalk(FromKernelMode,
  2864. DirectoryPathPoint,
  2865. &Path,
  2866. &PathSize,
  2867. OPEN_FLAG_SYMBOLIC_LINK | OPEN_FLAG_NO_MOUNT_POINT,
  2868. IoObjectInvalid,
  2869. NULL,
  2870. FILE_PERMISSION_NONE,
  2871. &PathPoint);
  2872. if (!KSUCCESS(Status)) {
  2873. goto DeleteEnd;
  2874. }
  2875. Status = IopDeletePathPoint(FromKernelMode, &PathPoint, Flags);
  2876. if (!KSUCCESS(Status)) {
  2877. goto DeleteEnd;
  2878. }
  2879. DeleteEnd:
  2880. if (PathPoint.PathEntry != NULL) {
  2881. IO_PATH_POINT_RELEASE_REFERENCE(&PathPoint);
  2882. }
  2883. return Status;
  2884. }
  2885. KSTATUS
  2886. IopDeleteByHandle (
  2887. BOOL FromKernelMode,
  2888. PIO_HANDLE Handle,
  2889. ULONG Flags
  2890. )
  2891. /*++
  2892. Routine Description:
  2893. This routine attempts to delete the the object open by the given I/O
  2894. handle. This does not close or invalidate the handle, but it does attempt
  2895. to unlink the object so future path walks will not find it at that location.
  2896. Arguments:
  2897. FromKernelMode - Supplies a boolean indicating the request is coming from
  2898. kernel mode.
  2899. Handle - Supplies the open handle to the device.
  2900. Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
  2901. Return Value:
  2902. Status code.
  2903. --*/
  2904. {
  2905. KSTATUS Status;
  2906. //
  2907. // Fail for anonymous path entries.
  2908. //
  2909. if (Handle->PathPoint.PathEntry->NameSize == 0) {
  2910. return STATUS_PATH_NOT_FOUND;
  2911. }
  2912. Status = IopDeletePathPoint(FromKernelMode, &(Handle->PathPoint), Flags);
  2913. return Status;
  2914. }
  2915. KSTATUS
  2916. IopDeletePathPoint (
  2917. BOOL FromKernelMode,
  2918. PPATH_POINT PathPoint,
  2919. ULONG Flags
  2920. )
  2921. /*++
  2922. Routine Description:
  2923. This routine attempts to delete the object at the given path. If the path
  2924. points to a directory, the directory must be empty. If the path point is
  2925. a file object or shared memory object, its hard link count is decremented.
  2926. If the hard link count reaches zero and no processes have the object open,
  2927. the contents of the object are destroyed. If processes have open handles to
  2928. the object, the destruction of the object contents are deferred until the
  2929. last handle to the old file is closed.
  2930. Arguments:
  2931. FromKernelMode - Supplies a boolean indicating the request is coming from
  2932. kernel mode.
  2933. PathPoint - Supplies a pointer to the path point to delete. The caller
  2934. should already have a reference on this path point, which will need to
  2935. be released by the caller when finished.
  2936. Flags - Supplies a bitfield of flags. See DELETE_FLAG_* definitions.
  2937. Return Value:
  2938. Status code.
  2939. --*/
  2940. {
  2941. PDEVICE Device;
  2942. PFILE_OBJECT DirectoryFileObject;
  2943. PFILE_OBJECT FileObject;
  2944. BOOL LocksHeld;
  2945. PATH_POINT ParentPathPoint;
  2946. BOOL SendUnlinkRequest;
  2947. KSTATUS Status;
  2948. BOOL Unlinked;
  2949. LocksHeld = FALSE;
  2950. ParentPathPoint.PathEntry = NULL;
  2951. //
  2952. // Delete is not allowed if the path entry is mounted. Doesn't matter
  2953. // where.
  2954. //
  2955. if (PathPoint->PathEntry->MountCount != 0) {
  2956. Status = STATUS_RESOURCE_IN_USE;
  2957. goto DeletePathPointEnd;
  2958. }
  2959. //
  2960. // Get the file object for the file to delete, and the path point for the
  2961. // containing directory.
  2962. //
  2963. FileObject = PathPoint->PathEntry->FileObject;
  2964. IopGetParentPathPoint(NULL,
  2965. PathPoint,
  2966. &ParentPathPoint);
  2967. ASSERT(PathPoint->MountPoint == ParentPathPoint.MountPoint);
  2968. //
  2969. // Perform permission checking on the directory in preparation for the
  2970. // directory write operation.
  2971. //
  2972. if (FromKernelMode == FALSE) {
  2973. Status = IopCheckDeletePermission(FromKernelMode,
  2974. &ParentPathPoint,
  2975. PathPoint);
  2976. if (!KSUCCESS(Status)) {
  2977. goto DeletePathPointEnd;
  2978. }
  2979. }
  2980. //
  2981. // The root object cannot be deleted. This is detected by the parent
  2982. // equaling the child.
  2983. //
  2984. if (IO_ARE_PATH_POINTS_EQUAL(PathPoint, &ParentPathPoint) != FALSE) {
  2985. Status = STATUS_NOT_SUPPORTED;
  2986. goto DeletePathPointEnd;
  2987. }
  2988. //
  2989. // Square up with the directory flag.
  2990. //
  2991. if ((Flags & DELETE_FLAG_DIRECTORY) != 0) {
  2992. if (FileObject->Properties.Type != IoObjectRegularDirectory) {
  2993. Status = STATUS_NOT_A_DIRECTORY;
  2994. goto DeletePathPointEnd;
  2995. }
  2996. } else {
  2997. if (FileObject->Properties.Type == IoObjectRegularDirectory) {
  2998. Status = STATUS_FILE_IS_DIRECTORY;
  2999. goto DeletePathPointEnd;
  3000. }
  3001. }
  3002. //
  3003. // The object file system only allows unlinking of shared memory objects,
  3004. // pipes, and terminals by kernel mode callers.
  3005. //
  3006. Device = PathPoint->PathEntry->FileObject->Device;
  3007. SendUnlinkRequest = FALSE;
  3008. if (Device == ObGetRootObject()) {
  3009. if ((FromKernelMode == FALSE) ||
  3010. ((FileObject->Properties.Type != IoObjectSharedMemoryObject) &&
  3011. (FileObject->Properties.Type != IoObjectTerminalMaster) &&
  3012. (FileObject->Properties.Type != IoObjectTerminalSlave) &&
  3013. (FileObject->Properties.Type != IoObjectPipe))) {
  3014. Status = STATUS_ACCESS_DENIED;
  3015. goto DeletePathPointEnd;
  3016. }
  3017. //
  3018. // Otherwise deletes can only be from devices or volumes.
  3019. //
  3020. } else {
  3021. if ((Device->Header.Type != ObjectDevice) &&
  3022. (Device->Header.Type != ObjectVolume)) {
  3023. Status = STATUS_ACCESS_DENIED;
  3024. goto DeletePathPointEnd;
  3025. }
  3026. SendUnlinkRequest = TRUE;
  3027. }
  3028. DirectoryFileObject = ParentPathPoint.PathEntry->FileObject;
  3029. //
  3030. // The unlink operation needs to modify the parent directory and the file
  3031. // properties of the child. Hold both locks exclusively. Directories are
  3032. // always acquired first.
  3033. //
  3034. ASSERT(DirectoryFileObject != FileObject);
  3035. KeAcquireSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
  3036. KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
  3037. LocksHeld = TRUE;
  3038. //
  3039. // With the appropriate locks acquired, check to make sure the file can
  3040. // still be unlinked. If it cannot, act like it was not found.
  3041. //
  3042. if (PathPoint->PathEntry->SiblingListEntry.Next == NULL) {
  3043. Status = STATUS_PATH_NOT_FOUND;
  3044. goto DeletePathPointEnd;
  3045. }
  3046. //
  3047. // Check again to make sure that the path entry did not get mounted on.
  3048. // Mount creation synchronizes with the path entry's file object lock.
  3049. //
  3050. if (PathPoint->PathEntry->MountCount != 0) {
  3051. Status = STATUS_RESOURCE_IN_USE;
  3052. goto DeletePathPointEnd;
  3053. }
  3054. ASSERT(FileObject->Properties.HardLinkCount != 0);
  3055. //
  3056. // If unlink request needs to be sent to a driver, then send it now.
  3057. //
  3058. if (SendUnlinkRequest != FALSE) {
  3059. Status = IopSendUnlinkRequest(Device,
  3060. FileObject,
  3061. DirectoryFileObject,
  3062. PathPoint->PathEntry->Name,
  3063. PathPoint->PathEntry->NameSize,
  3064. &Unlinked);
  3065. //
  3066. // Otherwise just handle the unlink by calling the type specific unlink
  3067. // routine, decrementing the object's hard link count and updating the
  3068. // directory's access time.
  3069. //
  3070. } else {
  3071. if (FileObject->Properties.Type == IoObjectSharedMemoryObject) {
  3072. Status = IopUnlinkSharedMemoryObject(FileObject, &Unlinked);
  3073. } else if (FileObject->Properties.Type == IoObjectPipe) {
  3074. Status = IopUnlinkPipe(FileObject, &Unlinked);
  3075. } else {
  3076. ASSERT((FileObject->Properties.Type == IoObjectTerminalMaster) ||
  3077. (FileObject->Properties.Type == IoObjectTerminalSlave));
  3078. Status = IopUnlinkTerminal(FileObject, &Unlinked);
  3079. }
  3080. if (Unlinked != FALSE) {
  3081. IopFileObjectDecrementHardLinkCount(FileObject);
  3082. IopUpdateFileObjectTime(DirectoryFileObject,
  3083. FileObjectModifiedTime);
  3084. }
  3085. }
  3086. //
  3087. // If the object was successfully unlinked, finish the job even if the call
  3088. // failed. Unlink the path entry from the system's path hierarchy. This
  3089. // needs to be done while the parent's file object I/O lock is held
  3090. // exclusively.
  3091. //
  3092. if (Unlinked != FALSE) {
  3093. IopPathUnlink(PathPoint->PathEntry);
  3094. }
  3095. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  3096. KeReleaseSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
  3097. LocksHeld = FALSE;
  3098. //
  3099. // Clean the cached path entries if the path point was successfully
  3100. // unlinked from its parent. The only things that should be there now are
  3101. // negative path entries with a reference count of zero.
  3102. //
  3103. if (Unlinked != FALSE) {
  3104. IopPathCleanCache(PathPoint->PathEntry);
  3105. }
  3106. if (!KSUCCESS(Status)) {
  3107. goto DeletePathPointEnd;
  3108. }
  3109. DeletePathPointEnd:
  3110. if (LocksHeld != FALSE) {
  3111. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  3112. KeReleaseSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
  3113. }
  3114. if (ParentPathPoint.PathEntry != NULL) {
  3115. IO_PATH_POINT_RELEASE_REFERENCE(&ParentPathPoint);
  3116. }
  3117. return Status;
  3118. }
  3119. KSTATUS
  3120. IopSendFileOperationIrp (
  3121. IRP_MINOR_CODE MinorCode,
  3122. PFILE_OBJECT FileObject,
  3123. PVOID DeviceContext,
  3124. ULONG Flags
  3125. )
  3126. /*++
  3127. Routine Description:
  3128. This routine sends a file operation IRP.
  3129. Arguments:
  3130. MinorCode - Supplies the minor code of the IRP to send.
  3131. FileObject - Supplies a pointer to the file object of the file being
  3132. operated on.
  3133. DeviceContext - Supplies a pointer to the device context to send down.
  3134. Flags - Supplies a bitmask of I/O flags. See IO_FLAG_* for definitions.
  3135. Return Value:
  3136. Status code.
  3137. --*/
  3138. {
  3139. PDEVICE Device;
  3140. SYSTEM_CONTROL_FILE_OPERATION Request;
  3141. KSTATUS Status;
  3142. if ((FileObject->Properties.Type != IoObjectRegularFile) &&
  3143. (FileObject->Properties.Type != IoObjectRegularDirectory) &&
  3144. (FileObject->Properties.Type != IoObjectSymbolicLink) &&
  3145. (FileObject->Properties.Type != IoObjectBlockDevice) &&
  3146. (FileObject->Properties.Type != IoObjectCharacterDevice)) {
  3147. return STATUS_SUCCESS;
  3148. }
  3149. Request.FileProperties = &(FileObject->Properties);
  3150. Request.DeviceContext = DeviceContext;
  3151. Request.Flags = Flags;
  3152. Device = FileObject->Device;
  3153. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  3154. Status = IopSendSystemControlIrp(Device, MinorCode, &Request);
  3155. return Status;
  3156. }
  3157. KSTATUS
  3158. IopSendLookupRequest (
  3159. PDEVICE Device,
  3160. PFILE_OBJECT Directory,
  3161. PSTR FileName,
  3162. ULONG FileNameSize,
  3163. PFILE_PROPERTIES Properties
  3164. )
  3165. /*++
  3166. Routine Description:
  3167. This routine sends a lookup request IRP. This routine assumes that the
  3168. directory's lock is held exclusively.
  3169. Arguments:
  3170. Device - Supplies a pointer to the device to send the request to.
  3171. Directory - Supplies a pointer to the file object of the directory to
  3172. search in.
  3173. FileName - Supplies a pointer to the name of the file, which may not be
  3174. null terminated.
  3175. FileNameSize - Supplies the size of the file name buffer including space
  3176. for a null terminator (which may be a null terminator or may be a
  3177. garbage character).
  3178. Properties - Supplies a pointer where the file properties will be returned
  3179. if the file was found.
  3180. Return Value:
  3181. Status code.
  3182. --*/
  3183. {
  3184. SYSTEM_CONTROL_LOOKUP Request;
  3185. KSTATUS Status;
  3186. ASSERT(KeIsSharedExclusiveLockHeldExclusive(Directory->Lock) != FALSE);
  3187. ASSERT(Directory->Properties.HardLinkCount != 0);
  3188. RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_LOOKUP));
  3189. Request.Root = FALSE;
  3190. Request.DirectoryProperties = &(Directory->Properties);
  3191. Request.FileName = FileName;
  3192. Request.FileNameSize = FileNameSize;
  3193. Status = IopSendSystemControlIrp(Device,
  3194. IrpMinorSystemControlLookup,
  3195. &Request);
  3196. RtlCopyMemory(Properties, &(Request.Properties), sizeof(FILE_PROPERTIES));
  3197. return Status;
  3198. }
  3199. KSTATUS
  3200. IopSendRootLookupRequest (
  3201. PDEVICE Device,
  3202. PFILE_PROPERTIES Properties,
  3203. PULONG Flags
  3204. )
  3205. /*++
  3206. Routine Description:
  3207. This routine sends a lookup request IRP for the device's root.
  3208. Arguments:
  3209. Device - Supplies a pointer to the device to send the request to.
  3210. Properties - Supplies the file properties if the file was found.
  3211. Flags - Supplies a pointer that receives the flags returned by the root
  3212. lookup call. See LOOKUP_FLAG_* for definitions.
  3213. Return Value:
  3214. Status code.
  3215. --*/
  3216. {
  3217. SYSTEM_CONTROL_LOOKUP Request;
  3218. KSTATUS Status;
  3219. RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_LOOKUP));
  3220. Request.Root = TRUE;
  3221. Status = IopSendSystemControlIrp(Device,
  3222. IrpMinorSystemControlLookup,
  3223. &Request);
  3224. RtlCopyMemory(Properties, &(Request.Properties), sizeof(FILE_PROPERTIES));
  3225. *Flags = Request.Flags;
  3226. return Status;
  3227. }
  3228. KSTATUS
  3229. IopSendCreateRequest (
  3230. PDEVICE Device,
  3231. PFILE_OBJECT Directory,
  3232. PSTR Name,
  3233. ULONG NameSize,
  3234. PFILE_PROPERTIES Properties
  3235. )
  3236. /*++
  3237. Routine Description:
  3238. This routine sends a creation request to the device. This routine assumes
  3239. that the directory's lock is held exclusively.
  3240. Arguments:
  3241. Device - Supplies a pointer to the device to send the request to.
  3242. Directory - Supplies a pointer to the file object of the directory to
  3243. create the file in.
  3244. Name - Supplies a pointer to the name of the file or directory to create,
  3245. which may not be null terminated.
  3246. NameSize - Supplies the size of the name buffer including space for a null
  3247. terminator (which may be a null terminator or may be a garbage
  3248. character).
  3249. Properties - Supplies a pointer to the file properties of the created file
  3250. on success. The permissions, object type, user ID, group ID, and access
  3251. times are all valid from the system.
  3252. Return Value:
  3253. Status code.
  3254. --*/
  3255. {
  3256. SYSTEM_CONTROL_CREATE Request;
  3257. KSTATUS Status;
  3258. ASSERT(KeIsSharedExclusiveLockHeldExclusive(Directory->Lock) != FALSE);
  3259. ASSERT(Directory->Properties.HardLinkCount != 0);
  3260. RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_CREATE));
  3261. Request.DirectoryProperties = &(Directory->Properties);
  3262. Request.Name = Name;
  3263. Request.NameSize = NameSize;
  3264. RtlCopyMemory(&(Request.FileProperties),
  3265. Properties,
  3266. sizeof(FILE_PROPERTIES));
  3267. Status = IopSendSystemControlIrp(Device,
  3268. IrpMinorSystemControlCreate,
  3269. &Request);
  3270. RtlCopyMemory(Properties,
  3271. &(Request.FileProperties),
  3272. sizeof(FILE_PROPERTIES));
  3273. //
  3274. // Update the access time and modified time if file was created.
  3275. //
  3276. if (KSUCCESS(Status)) {
  3277. IopUpdateFileObjectTime(Directory, FileObjectModifiedTime);
  3278. IopUpdateFileObjectFileSize(Directory, Request.DirectorySize);
  3279. }
  3280. return Status;
  3281. }
  3282. KSTATUS
  3283. IopSendUnlinkRequest (
  3284. PDEVICE Device,
  3285. PFILE_OBJECT FileObject,
  3286. PFILE_OBJECT DirectoryObject,
  3287. PSTR Name,
  3288. ULONG NameSize,
  3289. PBOOL Unlinked
  3290. )
  3291. /*++
  3292. Routine Description:
  3293. This routine sends an unlink request to the device. This routine assumes
  3294. that the directory's lock is held exclusively.
  3295. Arguments:
  3296. Device - Supplies a pointer to the device to send the request to.
  3297. FileObject - Supplies a pointer to the file object of the file that is to
  3298. be unlinked.
  3299. DirectoryObject - Supplies a pointer to the file object of the directory
  3300. from which the file will be unlinked.
  3301. Name - Supplies a pointer to the name of the file or directory to create,
  3302. which may not be null terminated.
  3303. NameSize - Supplies the size of the name buffer including space for a null
  3304. terminator (which may be a null terminator or may be a garbage
  3305. character).
  3306. Unlinked - Supplies a boolean that receives whether or not the file was
  3307. unlinked. The file may be unlinked even if the call fails.
  3308. Return Value:
  3309. Status code.
  3310. --*/
  3311. {
  3312. KSTATUS Status;
  3313. SYSTEM_CONTROL_UNLINK UnlinkRequest;
  3314. ASSERT(KeIsSharedExclusiveLockHeldExclusive(DirectoryObject->Lock));
  3315. ASSERT(DirectoryObject->Properties.HardLinkCount != 0);
  3316. UnlinkRequest.DirectoryProperties = &(DirectoryObject->Properties);
  3317. UnlinkRequest.FileProperties = &(FileObject->Properties);
  3318. UnlinkRequest.Name = Name;
  3319. UnlinkRequest.NameSize = NameSize;
  3320. UnlinkRequest.Unlinked = FALSE;
  3321. Status = IopSendSystemControlIrp(Device,
  3322. IrpMinorSystemControlUnlink,
  3323. &UnlinkRequest);
  3324. //
  3325. // If the file was successfully unlinked, finish the job even if the IRP
  3326. // failed.
  3327. //
  3328. if (UnlinkRequest.Unlinked != FALSE) {
  3329. //
  3330. // Decrement the hard link count of the file being deleted.
  3331. //
  3332. IopFileObjectDecrementHardLinkCount(FileObject);
  3333. //
  3334. // The directory was modified, update its times.
  3335. //
  3336. IopUpdateFileObjectTime(DirectoryObject, FileObjectModifiedTime);
  3337. }
  3338. *Unlinked = UnlinkRequest.Unlinked;
  3339. return Status;
  3340. }
  3341. KERNEL_API
  3342. KSTATUS
  3343. IoGetFileBlockInformation (
  3344. PIO_HANDLE Handle,
  3345. PFILE_BLOCK_INFORMATION *FileBlockInformation
  3346. )
  3347. /*++
  3348. Routine Description:
  3349. This routine gets a list of logical block offsets for the given file or
  3350. partition, comprising the runs of contiguous disk space taken up by the
  3351. file or partition.
  3352. Arguments:
  3353. Handle - Supplies an I/O handle for the file or partition.
  3354. FileBlockInformation - Supplies a pointer that receives a pointer to the
  3355. block information for the file or partition. If this is non-null and a
  3356. partition is queried, then the partition will update the offsets in the
  3357. block information to be logical block offsets for the parent disk.
  3358. Return Value:
  3359. Status code.
  3360. --*/
  3361. {
  3362. SYSTEM_CONTROL_GET_BLOCK_INFORMATION BlockInformation;
  3363. PDEVICE Device;
  3364. PFILE_OBJECT FileObject;
  3365. PIRP Irp;
  3366. PPAGING_IO_HANDLE PagingHandle;
  3367. KSTATUS Status;
  3368. Irp = NULL;
  3369. Status = IoGetDevice(Handle, &Device);
  3370. if (!KSUCCESS(Status)) {
  3371. goto GetBlockInformationEnd;
  3372. }
  3373. if (Handle->HandleType == IoHandleTypePaging) {
  3374. PagingHandle = (PPAGING_IO_HANDLE)Handle;
  3375. Handle = PagingHandle->IoHandle;
  3376. }
  3377. FileObject = Handle->FileObject;
  3378. Irp = IoCreateIrp(Device, IrpMajorSystemControl, 0);
  3379. if (Irp == NULL) {
  3380. Status = STATUS_INSUFFICIENT_RESOURCES;
  3381. goto GetBlockInformationEnd;
  3382. }
  3383. BlockInformation.FileProperties = &(FileObject->Properties);
  3384. BlockInformation.FileBlockInformation = *FileBlockInformation;
  3385. Irp->MinorCode = IrpMinorSystemControlGetBlockInformation;
  3386. Irp->U.SystemControl.SystemContext = &BlockInformation;
  3387. Status = IoSendSynchronousIrp(Irp);
  3388. if (!KSUCCESS(Status)) {
  3389. goto GetBlockInformationEnd;
  3390. }
  3391. Status = IoGetIrpStatus(Irp);
  3392. if (!KSUCCESS(Status)) {
  3393. goto GetBlockInformationEnd;
  3394. }
  3395. *FileBlockInformation = BlockInformation.FileBlockInformation;
  3396. GetBlockInformationEnd:
  3397. if (Irp != NULL) {
  3398. IoDestroyIrp(Irp);
  3399. }
  3400. return Status;
  3401. }
  3402. KERNEL_API
  3403. VOID
  3404. IoDestroyFileBlockInformation (
  3405. PFILE_BLOCK_INFORMATION FileBlockInformation
  3406. )
  3407. /*++
  3408. Routine Description:
  3409. This routine destroys file block information for a file or partition.
  3410. Arguments:
  3411. FileBlockInformation - Supplies a pointer to file block information to be
  3412. destroyed.
  3413. Return Value:
  3414. Status code.
  3415. --*/
  3416. {
  3417. PFILE_BLOCK_ENTRY BlockEntry;
  3418. while (LIST_EMPTY(&(FileBlockInformation->BlockList)) == FALSE) {
  3419. BlockEntry = LIST_VALUE(FileBlockInformation->BlockList.Next,
  3420. FILE_BLOCK_ENTRY,
  3421. ListEntry);
  3422. LIST_REMOVE(&(BlockEntry->ListEntry));
  3423. MmFreeNonPagedPool(BlockEntry);
  3424. }
  3425. MmFreeNonPagedPool(FileBlockInformation);
  3426. return;
  3427. }
  3428. KSTATUS
  3429. IoWriteFileBlocks (
  3430. PFILE_BLOCK_IO_CONTEXT FileContext,
  3431. PIO_BUFFER IoBuffer,
  3432. ULONGLONG Offset,
  3433. UINTN SizeInBytes,
  3434. PUINTN BytesCompleted
  3435. )
  3436. /*++
  3437. Routine Description:
  3438. This routine writes data directly to a file's disk blocks, bypassing the
  3439. filesystem. It is meant for critical code paths, such as writing out the
  3440. crash dump file during a system failure.
  3441. Arguments:
  3442. FileContext - Supplies a pointer to the file block context, including the
  3443. file's block information, the device's block level I/O routines and
  3444. block information.
  3445. IoBuffer - Supplies a pointer to an I/O buffer with the data to write.
  3446. Offset - Supplies the offset, in bytes, into the file where the data is to
  3447. be written.
  3448. SizeInBytes - Supplies the size of the data to write, in bytes.
  3449. BytesCompleted - Supplies a pointer that receives the total number of bytes
  3450. written to the disk.
  3451. Return Value:
  3452. Status code.
  3453. --*/
  3454. {
  3455. UINTN AlignedSize;
  3456. ULONGLONG BlockCount;
  3457. PLIST_ENTRY BlockList;
  3458. ULONGLONG BlockOffset;
  3459. PFILE_BLOCK_ENTRY BlockRun;
  3460. ULONGLONG BlockRunOffset;
  3461. UINTN BlocksCompleted;
  3462. ULONG BlockShift;
  3463. UINTN BlocksRemaining;
  3464. ULONGLONG BlocksThisRound;
  3465. PDISK_BLOCK_IO_WRITE BlockWrite;
  3466. PLIST_ENTRY CurrentEntry;
  3467. KSTATUS Status;
  3468. ASSERT(POWER_OF_2(FileContext->BlockSize) != FALSE);
  3469. BlockWrite = (PDISK_BLOCK_IO_WRITE)FileContext->BlockIoWrite;
  3470. //
  3471. // Align the size up to full blocks. The I/O buffer should be able to
  3472. // handle it.
  3473. //
  3474. AlignedSize = ALIGN_RANGE_UP(SizeInBytes, FileContext->BlockSize);
  3475. ASSERT(MmGetIoBufferSize(IoBuffer) >= AlignedSize);
  3476. //
  3477. // The I/O buffer should be mapped.
  3478. //
  3479. ASSERT(KSUCCESS(MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE)));
  3480. //
  3481. // TODO: Support partial block writes to crash dump files.
  3482. //
  3483. ASSERT(IS_ALIGNED(Offset, FileContext->BlockSize) != FALSE);
  3484. BlockList = &(FileContext->FileBlockInformation->BlockList);
  3485. BlockShift = RtlCountTrailingZeros32(FileContext->BlockSize);
  3486. BlockOffset = Offset >> BlockShift;
  3487. //
  3488. // Find the first block run that this write is targeting.
  3489. //
  3490. BlockCount = 0;
  3491. BlockRun = NULL;
  3492. BlockRunOffset = 0;
  3493. CurrentEntry = BlockList->Next;
  3494. while (CurrentEntry != BlockList) {
  3495. BlockRun = LIST_VALUE(CurrentEntry, FILE_BLOCK_ENTRY, ListEntry);
  3496. if (BlockOffset < (BlockCount + BlockRun->Count)) {
  3497. ASSERT(BlockOffset >= BlockCount);
  3498. BlockRunOffset = BlockOffset - BlockCount;
  3499. break;
  3500. }
  3501. BlockCount += BlockRun->Count;
  3502. CurrentEntry = CurrentEntry->Next;
  3503. BlockRun = NULL;
  3504. }
  3505. //
  3506. // Trusted callers really shouldn't be going beyond the end of the file or
  3507. // the buffer.
  3508. //
  3509. ASSERT(BlockRun != NULL);
  3510. //
  3511. // Loop writing each fragment of the I/O buffer to as many contiguous
  3512. // blocks as possible.
  3513. //
  3514. BlocksRemaining = AlignedSize >> BlockShift;
  3515. while (BlocksRemaining != 0) {
  3516. //
  3517. // Determine how many contiguous blocks can be written this round.
  3518. //
  3519. BlocksThisRound = BlockRun->Count - BlockRunOffset;
  3520. if (BlocksRemaining < BlocksThisRound) {
  3521. BlocksThisRound = BlocksRemaining;
  3522. }
  3523. ASSERT(BlocksThisRound != 0);
  3524. //
  3525. // Send this write down to the disk.
  3526. //
  3527. Status = BlockWrite(FileContext->DiskToken,
  3528. IoBuffer,
  3529. BlockRun->Address + BlockRunOffset,
  3530. (UINTN)BlocksThisRound,
  3531. &BlocksCompleted);
  3532. if (!KSUCCESS(Status)) {
  3533. goto WriteFileBlocksEnd;
  3534. }
  3535. //
  3536. // Update the I/O buffer offset so the next run starts where this left
  3537. // off.
  3538. //
  3539. MmIoBufferIncrementOffset(IoBuffer, BlocksCompleted << BlockShift);
  3540. BlocksRemaining -= BlocksCompleted;
  3541. if (BlocksCompleted != BlocksThisRound) {
  3542. Status = STATUS_DATA_LENGTH_MISMATCH;
  3543. goto WriteFileBlocksEnd;
  3544. }
  3545. //
  3546. // Move to the next block run if this run is exhausted.
  3547. //
  3548. BlockRunOffset += BlocksThisRound;
  3549. if (BlockRunOffset == BlockRun->Count) {
  3550. CurrentEntry = CurrentEntry->Next;
  3551. if (CurrentEntry == BlockList) {
  3552. break;
  3553. }
  3554. BlockRun = LIST_VALUE(CurrentEntry, FILE_BLOCK_ENTRY, ListEntry);
  3555. BlockRunOffset = 0;
  3556. }
  3557. }
  3558. if (BlocksRemaining != 0) {
  3559. Status = STATUS_END_OF_FILE;
  3560. goto WriteFileBlocksEnd;
  3561. }
  3562. Status = STATUS_SUCCESS;
  3563. WriteFileBlocksEnd:
  3564. BlocksCompleted = (AlignedSize >> BlockShift) - BlocksRemaining;
  3565. *BytesCompleted = BlocksCompleted << BlockShift;
  3566. if (*BytesCompleted > SizeInBytes) {
  3567. *BytesCompleted = SizeInBytes;
  3568. }
  3569. if (*BytesCompleted != 0) {
  3570. MmIoBufferDecrementOffset(IoBuffer, *BytesCompleted);
  3571. }
  3572. return Status;
  3573. }
  3574. KSTATUS
  3575. IopSynchronizeBlockDevice (
  3576. PDEVICE Device
  3577. )
  3578. /*++
  3579. Routine Description:
  3580. This routine sends a sync request to a block device to ensure all data is
  3581. written out to permanent storage.
  3582. Arguments:
  3583. Device - Supplies a pointer to the device to send the synchronize request
  3584. to.
  3585. Return Value:
  3586. Status code.
  3587. --*/
  3588. {
  3589. KSTATUS Status;
  3590. Status = IopSendSystemControlIrp(Device,
  3591. IrpMinorSystemControlSynchronize,
  3592. NULL);
  3593. return Status;
  3594. }
  3595. KERNEL_API
  3596. KSTATUS
  3597. IoLoadFile (
  3598. PSTR Path,
  3599. ULONG PathLength,
  3600. PLOAD_FILE_COMPLETION_ROUTINE CompletionRoutine,
  3601. PVOID CompletionContext
  3602. )
  3603. /*++
  3604. Routine Description:
  3605. This routine asynchronously loads the file at the given path. The path can
  3606. either be absolute or relative. For the kernel process, relative paths are
  3607. in relative to the system volume's drivers directory. The supplied
  3608. completion routine is invoked when the load finishes.
  3609. Arguments:
  3610. Path - Supplies a pointer to the path to the file. It can either be an
  3611. absolute or relative path. Relative paths for the kernel process are
  3612. relative to the system partition's drivers directory.
  3613. PathLength - Supplies the length of the path buffer in bytes, including the
  3614. null terminator.
  3615. CompletionRoutine - Supplies a pointer to the callback routine to notify
  3616. when the load is complete.
  3617. CompletionContext - Supplies a pointer to an opaque context that will be
  3618. passed to the completion routine along with the loaded file.
  3619. Return Value:
  3620. Status code.
  3621. --*/
  3622. {
  3623. UINTN BytesCompleted;
  3624. ULONGLONG FileSize;
  3625. PLOADED_FILE NewFile;
  3626. KSTATUS Status;
  3627. NewFile = NULL;
  3628. //
  3629. // Fail if the path is NULL or has no length.
  3630. //
  3631. if ((Path == NULL) || (PathLength < 2)) {
  3632. Status = STATUS_INVALID_PARAMETER;
  3633. goto LoadFileEnd;
  3634. }
  3635. //
  3636. // Allocate a new file structure to store the loaded file information.
  3637. //
  3638. NewFile = MmAllocatePagedPool(sizeof(LOADED_FILE), IO_ALLOCATION_TAG);
  3639. if (NewFile == NULL) {
  3640. Status = STATUS_INSUFFICIENT_RESOURCES;
  3641. goto LoadFileEnd;
  3642. }
  3643. RtlZeroMemory(NewFile, sizeof(LOADED_FILE));
  3644. NewFile->Version = LOADED_FILE_VERSION;
  3645. //
  3646. // Open the file using the given path. If it is a relative path, then it
  3647. // will search in the process's current directory. For the kernel, that
  3648. // is the drivers directory on the system partition.
  3649. //
  3650. Status = IoOpen(TRUE,
  3651. NULL,
  3652. Path,
  3653. PathLength,
  3654. IO_ACCESS_READ | IO_ACCESS_EXECUTE,
  3655. 0,
  3656. FILE_PERMISSION_NONE,
  3657. &(NewFile->IoHandle));
  3658. if (!KSUCCESS(Status)) {
  3659. goto LoadFileEnd;
  3660. }
  3661. //
  3662. // Get the file size and allocate an I/O buffer to contain it.
  3663. //
  3664. Status = IoGetFileSize(NewFile->IoHandle, &FileSize);
  3665. if (!KSUCCESS(Status)) {
  3666. goto LoadFileEnd;
  3667. }
  3668. if (FileSize > MAX_UINTN) {
  3669. Status = STATUS_NOT_SUPPORTED;
  3670. goto LoadFileEnd;
  3671. }
  3672. NewFile->Length = (UINTN)FileSize;
  3673. //
  3674. // Create an I/O buffer that can support the read.
  3675. //
  3676. NewFile->IoBuffer = MmAllocateUninitializedIoBuffer(NewFile->Length, 0);
  3677. if (NewFile->IoBuffer == NULL) {
  3678. Status = STATUS_INSUFFICIENT_RESOURCES;
  3679. goto LoadFileEnd;
  3680. }
  3681. //
  3682. // TODO: Convert file load reads to asynchronous I/O.
  3683. //
  3684. Status = IoReadAtOffset(NewFile->IoHandle,
  3685. NewFile->IoBuffer,
  3686. 0,
  3687. NewFile->Length,
  3688. 0,
  3689. WAIT_TIME_INDEFINITE,
  3690. &BytesCompleted,
  3691. NULL);
  3692. if (!KSUCCESS(Status)) {
  3693. goto LoadFileEnd;
  3694. }
  3695. if (BytesCompleted != NewFile->Length) {
  3696. Status = STATUS_DATA_LENGTH_MISMATCH;
  3697. goto LoadFileEnd;
  3698. }
  3699. //
  3700. // With success on the horizon, call the callback to signal completion.
  3701. //
  3702. CompletionRoutine(CompletionContext, NewFile);
  3703. LoadFileEnd:
  3704. if (!KSUCCESS(Status)) {
  3705. if (NewFile != NULL) {
  3706. IoUnloadFile(NewFile);
  3707. NewFile = NULL;
  3708. }
  3709. }
  3710. return Status;
  3711. }
  3712. KERNEL_API
  3713. VOID
  3714. IoUnloadFile (
  3715. PLOADED_FILE File
  3716. )
  3717. /*++
  3718. Routine Description:
  3719. This routine unloads the given file.
  3720. Arguments:
  3721. File - Supplies a pointer to the file to unload.
  3722. Return Value:
  3723. None.
  3724. --*/
  3725. {
  3726. if (File->IoBuffer != NULL) {
  3727. MmFreeIoBuffer(File->IoBuffer);
  3728. }
  3729. if (File->IoHandle != NULL) {
  3730. IoClose(File->IoHandle);
  3731. }
  3732. MmFreePagedPool(File);
  3733. return;
  3734. }
  3735. //
  3736. // --------------------------------------------------------- Internal Functions
  3737. //
  3738. KSTATUS
  3739. IopOpenPagingDevice (
  3740. PDEVICE Device,
  3741. ULONG Access,
  3742. ULONG Flags,
  3743. PPAGING_IO_HANDLE *Handle,
  3744. PULONG IoOffsetAlignment,
  3745. PULONG IoSizeAlignment,
  3746. PULONGLONG IoCapacity
  3747. )
  3748. /*++
  3749. Routine Description:
  3750. This routine opens a block device for paging.
  3751. Arguments:
  3752. Device - Supplies a pointer to the device to open.
  3753. Access - Supplies the desired access permissions to the object. See
  3754. IO_ACCESS_* definitions.
  3755. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  3756. See OPEN_FLAG_* definitions.
  3757. Handle - Supplies a pointer where a pointer to the open I/O handle will be
  3758. returned on success.
  3759. IoOffsetAlignment - Supplies a pointer where the alignment requirement in
  3760. bytes will be returned for all I/O offsets.
  3761. IoSizeAlignment - Supplies a pointer where the alignment requirement for
  3762. the size of all transfers (the block size) will be returned for all
  3763. I/O requests.
  3764. IoCapacity - Supplies the device's total size, in bytes.
  3765. Return Value:
  3766. Status code.
  3767. --*/
  3768. {
  3769. PFILE_OBJECT FileObject;
  3770. PIO_HANDLE IoHandle;
  3771. PPAGING_IO_HANDLE PagingHandle;
  3772. KSTATUS Status;
  3773. IoHandle = NULL;
  3774. PagingHandle = NULL;
  3775. ASSERT(KeGetRunLevel() == RunLevelLow);
  3776. //
  3777. // Allocate the basic structure.
  3778. //
  3779. PagingHandle = MmAllocateNonPagedPool(sizeof(PAGING_IO_HANDLE),
  3780. IO_ALLOCATION_TAG);
  3781. if (PagingHandle == NULL) {
  3782. Status = STATUS_INSUFFICIENT_RESOURCES;
  3783. goto OpenPagingDeviceEnd;
  3784. }
  3785. RtlZeroMemory(PagingHandle, sizeof(PAGING_IO_HANDLE));
  3786. PagingHandle->HandleType = IoHandleTypePaging;
  3787. //
  3788. // Open the device normally.
  3789. //
  3790. Status = IopOpenDevice(Device, Access, Flags, &IoHandle);
  3791. if (!KSUCCESS(Status)) {
  3792. goto OpenPagingDeviceEnd;
  3793. }
  3794. //
  3795. // Grab some needed parameters from the paged file object structure.
  3796. //
  3797. FileObject = IoHandle->FileObject;
  3798. PagingHandle->IoHandle = IoHandle;
  3799. PagingHandle->Device = FileObject->Device;
  3800. PagingHandle->DeviceContext = IoHandle->DeviceContext;
  3801. READ_INT64_SYNC(&(FileObject->Properties.FileSize),
  3802. &(PagingHandle->Capacity));
  3803. PagingHandle->OffsetAlignment = FileObject->Properties.BlockSize;
  3804. PagingHandle->SizeAlignment = PagingHandle->OffsetAlignment;
  3805. *IoOffsetAlignment = PagingHandle->OffsetAlignment;
  3806. *IoSizeAlignment = PagingHandle->SizeAlignment;
  3807. *IoCapacity = PagingHandle->Capacity;
  3808. Status = STATUS_SUCCESS;
  3809. OpenPagingDeviceEnd:
  3810. if (!KSUCCESS(Status)) {
  3811. if (IoHandle != NULL) {
  3812. IoClose(IoHandle);
  3813. }
  3814. if (PagingHandle != NULL) {
  3815. MmFreeNonPagedPool(PagingHandle);
  3816. }
  3817. PagingHandle = NULL;
  3818. }
  3819. *Handle = PagingHandle;
  3820. return Status;
  3821. }
  3822. KSTATUS
  3823. IopClosePagingObject (
  3824. PPAGING_IO_HANDLE Handle
  3825. )
  3826. /*++
  3827. Routine Description:
  3828. This routine closes a page file or device.
  3829. Arguments:
  3830. Handle - Supplies the handle returned upon opening the page file or device.
  3831. Return Value:
  3832. Status code.
  3833. --*/
  3834. {
  3835. KSTATUS Status;
  3836. //
  3837. // This routine is called from IoClose, but assert here that it will not
  3838. // recurse more than once.
  3839. //
  3840. ASSERT(Handle->HandleType == IoHandleTypePaging);
  3841. ASSERT(Handle->IoHandle->HandleType == IoHandleTypeDefault);
  3842. Status = IoClose(Handle->IoHandle);
  3843. if (!KSUCCESS(Status)) {
  3844. goto ClosePagingObjectEnd;
  3845. }
  3846. MmFreeNonPagedPool(Handle);
  3847. Status = STATUS_SUCCESS;
  3848. ClosePagingObjectEnd:
  3849. return Status;
  3850. }
  3851. KSTATUS
  3852. IopCreateAnonymousObject (
  3853. ULONG Access,
  3854. ULONG Flags,
  3855. IO_OBJECT_TYPE TypeOverride,
  3856. PVOID OverrideParameter,
  3857. FILE_PERMISSIONS CreatePermissions,
  3858. PPATH_POINT PathPoint
  3859. )
  3860. /*++
  3861. Routine Description:
  3862. This routine creates an anonymous I/O object, one that is not visible
  3863. in the global path system.
  3864. Arguments:
  3865. Access - Supplies the desired access permissions to the object. See
  3866. IO_ACCESS_* definitions.
  3867. Flags - Supplies a bitfield of flags governing the behavior of the handle.
  3868. See OPEN_FLAG_* definitions.
  3869. TypeOverride - Supplies an object type that the regular file should be
  3870. converted to. Supply the invalid object type to specify no override.
  3871. OverrideParameter - Supplies an optional parameter to send along with the
  3872. override type.
  3873. CreatePermissions - Supplies the initial permissions to create the entry
  3874. with.
  3875. PathPoint - Supplies a pointer that receives the path entry and mount point
  3876. of the newly minted path point.
  3877. Return Value:
  3878. Status code.
  3879. --*/
  3880. {
  3881. PFILE_OBJECT FileObject;
  3882. PPATH_ENTRY PathEntry;
  3883. KSTATUS Status;
  3884. FileObject = NULL;
  3885. PathEntry = NULL;
  3886. Status = IopCreateSpecialIoObject(Flags,
  3887. TypeOverride,
  3888. OverrideParameter,
  3889. CreatePermissions,
  3890. &FileObject);
  3891. if (!KSUCCESS(Status)) {
  3892. goto CreateAnonymousObjectEnd;
  3893. }
  3894. //
  3895. // Create an anonymous path entry for this object.
  3896. //
  3897. PathEntry = IopCreateAnonymousPathEntry(FileObject);
  3898. if (PathEntry == NULL) {
  3899. Status = STATUS_INSUFFICIENT_RESOURCES;
  3900. goto CreateAnonymousObjectEnd;
  3901. }
  3902. FileObject = NULL;
  3903. CreateAnonymousObjectEnd:
  3904. if (!KSUCCESS(Status)) {
  3905. if (PathEntry != NULL) {
  3906. IoPathEntryReleaseReference(PathEntry);
  3907. PathEntry = NULL;
  3908. }
  3909. }
  3910. if (FileObject != NULL) {
  3911. IopFileObjectReleaseReference(FileObject);
  3912. }
  3913. PathPoint->PathEntry = PathEntry;
  3914. PathPoint->MountPoint = NULL;
  3915. return Status;
  3916. }
  3917. KSTATUS
  3918. IopPerformIoOperation (
  3919. PIO_HANDLE Handle,
  3920. PIO_CONTEXT Context
  3921. )
  3922. /*++
  3923. Routine Description:
  3924. This routine reads from or writes to a file or device.
  3925. Arguments:
  3926. Handle - Supplies the open I/O handle.
  3927. Context - Supplies a pointer to the I/O context.
  3928. Return Value:
  3929. Status code. A failing status code does not necessarily mean no I/O made it
  3930. in or out. Check the bytes completed value to find out how much occurred.
  3931. --*/
  3932. {
  3933. PFILE_OBJECT FileObject;
  3934. KSTATUS Status;
  3935. ASSERT((Context->Flags & IO_FLAG_NO_ALLOCATE) == 0);
  3936. ASSERT(KeGetRunLevel() == RunLevelLow);
  3937. ASSERT(Context->BytesCompleted == 0);
  3938. ASSERT(Context->IoBuffer != NULL);
  3939. FileObject = Handle->FileObject;
  3940. if (FileObject == NULL) {
  3941. Status = STATUS_NO_SUCH_DEVICE;
  3942. goto PerformIoOperationEnd;
  3943. }
  3944. //
  3945. // Non-blocking handles always have a timeout of zero.
  3946. //
  3947. if ((Handle->OpenFlags & OPEN_FLAG_NON_BLOCKING) != 0) {
  3948. Context->TimeoutInMilliseconds = 0;
  3949. }
  3950. if ((Handle->OpenFlags & OPEN_FLAG_SYNCHRONIZED) != 0) {
  3951. Context->Flags |= IO_FLAG_DATA_SYNCHRONIZED;
  3952. }
  3953. //
  3954. // Fail if the caller hadn't opened the file with the correct access.
  3955. //
  3956. if (Context->Write != FALSE) {
  3957. if ((Handle->Access & IO_ACCESS_WRITE) == 0) {
  3958. Status = STATUS_INVALID_HANDLE;
  3959. goto PerformIoOperationEnd;
  3960. }
  3961. } else {
  3962. if ((Handle->Access & (IO_ACCESS_READ | IO_ACCESS_EXECUTE)) == 0) {
  3963. Status = STATUS_INVALID_HANDLE;
  3964. goto PerformIoOperationEnd;
  3965. }
  3966. }
  3967. //
  3968. // Perform the operation based on the file object type.
  3969. //
  3970. switch (FileObject->Properties.Type) {
  3971. case IoObjectBlockDevice:
  3972. case IoObjectRegularFile:
  3973. case IoObjectSharedMemoryObject:
  3974. case IoObjectSymbolicLink:
  3975. Status = IopPerformCacheableIoOperation(Handle, Context);
  3976. break;
  3977. case IoObjectCharacterDevice:
  3978. Status = IopPerformCharacterDeviceIoOperation(Handle, Context);
  3979. break;
  3980. case IoObjectRegularDirectory:
  3981. Status = IopPerformDirectoryIoOperation(Handle, Context);
  3982. break;
  3983. case IoObjectPipe:
  3984. Status = IopPerformPipeIoOperation(Handle, Context);
  3985. break;
  3986. case IoObjectSocket:
  3987. Status = IopPerformSocketIoOperation(Handle, Context);
  3988. break;
  3989. case IoObjectTerminalMaster:
  3990. Status = IopPerformTerminalMasterIoOperation(Handle, Context);
  3991. break;
  3992. case IoObjectTerminalSlave:
  3993. Status = IopPerformTerminalSlaveIoOperation(Handle, Context);
  3994. break;
  3995. case IoObjectObjectDirectory:
  3996. Status = IopPerformObjectIoOperation(Handle, Context);
  3997. break;
  3998. default:
  3999. ASSERT(FALSE);
  4000. Status = STATUS_NOT_SUPPORTED;
  4001. goto PerformIoOperationEnd;
  4002. }
  4003. PerformIoOperationEnd:
  4004. ASSERT(Context->BytesCompleted <= Context->SizeInBytes);
  4005. return Status;
  4006. }
  4007. KSTATUS
  4008. IopPerformPagingIoOperation (
  4009. PPAGING_IO_HANDLE Handle,
  4010. PIO_CONTEXT Context,
  4011. PIRP Irp
  4012. )
  4013. /*++
  4014. Routine Description:
  4015. This routine reads from or writes to a file or device.
  4016. Arguments:
  4017. Handle - Supplies the open I/O handle.
  4018. Context - Supplies a pointer to the paging I/O context.
  4019. Irp - Supplies a pointer to the IRP to use for this I/O.
  4020. Return Value:
  4021. Status code. A failing status code does not necessarily mean no I/O made it
  4022. in or out. Check the bytes completed value to find out how much occurred.
  4023. --*/
  4024. {
  4025. KSTATUS Status;
  4026. //
  4027. // Reset the paging IRP. The IRP should never be null.
  4028. //
  4029. ASSERT(Irp != NULL);
  4030. ASSERT(Context->BytesCompleted == 0);
  4031. ASSERT(Handle->HandleType == IoHandleTypePaging);
  4032. ASSERT(Context->IoBuffer != NULL);
  4033. ASSERT(IS_ALIGNED(Context->SizeInBytes, MmPageSize()) != FALSE);
  4034. IoInitializeIrp(Irp);
  4035. ASSERT(Irp->MajorCode == IrpMajorIo);
  4036. if (Context->Write != FALSE) {
  4037. Irp->MinorCode = IrpMinorIoWrite;
  4038. } else {
  4039. Irp->MinorCode = IrpMinorIoRead;
  4040. }
  4041. ASSERT((Context->Offset + Context->SizeInBytes) <= Handle->Capacity);
  4042. //
  4043. // Use the supplied I/O buffer directly. This code path should only be
  4044. // reached by trusted callers. The buffer should be properly aligned, etc.
  4045. //
  4046. Irp->U.ReadWrite.IoBuffer = Context->IoBuffer;
  4047. Irp->U.ReadWrite.DeviceContext = Handle->DeviceContext;
  4048. Irp->U.ReadWrite.IoFlags = Context->Flags;
  4049. Irp->U.ReadWrite.TimeoutInMilliseconds = WAIT_TIME_INDEFINITE;
  4050. Irp->U.ReadWrite.IoOffset = Context->Offset;
  4051. Irp->U.ReadWrite.IoSizeInBytes = Context->SizeInBytes;
  4052. Irp->U.ReadWrite.IoBytesCompleted = 0;
  4053. Status = IoSendSynchronousIrp(Irp);
  4054. if (!KSUCCESS(Status)) {
  4055. goto PerformPageFileIoOperationEnd;
  4056. }
  4057. //
  4058. // Update the global statistics.
  4059. //
  4060. if (Handle->Device->Header.Type == ObjectDevice) {
  4061. if (Context->Write != FALSE) {
  4062. RtlAtomicAdd64(&(IoGlobalStatistics.PagingBytesWritten),
  4063. Irp->U.ReadWrite.IoBytesCompleted);
  4064. } else {
  4065. RtlAtomicAdd64(&(IoGlobalStatistics.PagingBytesRead),
  4066. Irp->U.ReadWrite.IoBytesCompleted);
  4067. }
  4068. }
  4069. if (Irp->U.ReadWrite.IoBytesCompleted != Irp->U.ReadWrite.IoSizeInBytes) {
  4070. ASSERT(FALSE);
  4071. Status = STATUS_DATA_LENGTH_MISMATCH;
  4072. goto PerformPageFileIoOperationEnd;
  4073. }
  4074. Status = IoGetIrpStatus(Irp);
  4075. PerformPageFileIoOperationEnd:
  4076. Context->BytesCompleted = Irp->U.ReadWrite.IoBytesCompleted;
  4077. return Status;
  4078. }
  4079. KSTATUS
  4080. IopPerformCharacterDeviceIoOperation (
  4081. PIO_HANDLE Handle,
  4082. PIO_CONTEXT Context
  4083. )
  4084. /*++
  4085. Routine Description:
  4086. This routine performeds read and write I/O to a character device.
  4087. Arguments:
  4088. Handle - Supplies a pointer to the I/O handle.
  4089. Context - Supplies a pointer to the I/O context.
  4090. Return Value:
  4091. Status code.
  4092. --*/
  4093. {
  4094. PDEVICE Device;
  4095. PFILE_OBJECT FileObject;
  4096. IRP_MINOR_CODE MinorCode;
  4097. IRP_READ_WRITE Parameters;
  4098. KSTATUS Status;
  4099. ASSERT(Context->IoBuffer != NULL);
  4100. FileObject = Handle->FileObject;
  4101. ASSERT(FileObject->Properties.Type == IoObjectCharacterDevice);
  4102. //
  4103. // Initialize the parameters for the I/O IRP. The offset does not matter
  4104. // for character devices. Set it to 0, always.
  4105. //
  4106. Parameters.IoBuffer = Context->IoBuffer;
  4107. Parameters.DeviceContext = Handle->DeviceContext;
  4108. Parameters.IoFlags = Context->Flags;
  4109. Parameters.TimeoutInMilliseconds = Context->TimeoutInMilliseconds;
  4110. Parameters.IoSizeInBytes = Context->SizeInBytes;
  4111. Parameters.IoBytesCompleted = 0;
  4112. Parameters.IoOffset = 0;
  4113. Parameters.NewIoOffset = 0;
  4114. Parameters.FileProperties = &(FileObject->Properties);
  4115. Device = FileObject->Device;
  4116. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  4117. if (Context->Write != FALSE) {
  4118. MinorCode = IrpMinorIoWrite;
  4119. } else {
  4120. MinorCode = IrpMinorIoRead;
  4121. }
  4122. //
  4123. // Fire off the I/O.
  4124. //
  4125. Status = IopSendIoIrp(Device, MinorCode, &Parameters);
  4126. Context->BytesCompleted = Parameters.IoBytesCompleted;
  4127. return Status;
  4128. }
  4129. KSTATUS
  4130. IopPerformDirectoryIoOperation (
  4131. PIO_HANDLE Handle,
  4132. PIO_CONTEXT Context
  4133. )
  4134. /*++
  4135. Routine Description:
  4136. This routine performs I/O operations on regular directory handles. Only
  4137. read operations should be requested from a directory handle. It is
  4138. important to note that the supplied offset is a directory entry offset and
  4139. not a byte offset.
  4140. Arguments:
  4141. Handle - Supplies a pointer to the I/O handle.
  4142. Context - Supplies a pointer to the I/O context.
  4143. Return Value:
  4144. Status code. A failing status code does not necessarily mean no I/O made it
  4145. in or out. Check the bytes completed value to find out how much occurred.
  4146. --*/
  4147. {
  4148. PDEVICE Device;
  4149. PFILE_OBJECT FileObject;
  4150. BOOL LockHeldExclusive;
  4151. IRP_READ_WRITE Parameters;
  4152. KSTATUS Status;
  4153. ASSERT(Context->IoBuffer != NULL);
  4154. ASSERT((Context->Write == FALSE) && (Context->Flags == 0));
  4155. Context->BytesCompleted = 0;
  4156. Parameters.IoBytesCompleted = Context->BytesCompleted;
  4157. FileObject = Handle->FileObject;
  4158. ASSERT(FileObject != NULL);
  4159. KeAcquireSharedExclusiveLockShared(FileObject->Lock);
  4160. LockHeldExclusive = FALSE;
  4161. if (Context->Offset != IO_OFFSET_NONE) {
  4162. Parameters.IoOffset = Context->Offset;
  4163. } else {
  4164. Parameters.IoOffset =
  4165. RtlAtomicOr64((PULONGLONG)&(Handle->CurrentOffset), 0);
  4166. }
  4167. Parameters.NewIoOffset = Parameters.IoOffset;
  4168. if ((Handle->OpenFlags & OPEN_FLAG_DIRECTORY) == 0) {
  4169. Status = STATUS_FILE_IS_DIRECTORY;
  4170. goto PerformDirectoryIoOperationEnd;
  4171. }
  4172. //
  4173. // If this was a directory, add the relative entries.
  4174. //
  4175. Status = IopAddRelativeDirectoryEntries(Handle,
  4176. &(Parameters.IoOffset),
  4177. Context->IoBuffer,
  4178. Context->SizeInBytes,
  4179. &(Parameters.IoBytesCompleted));
  4180. Parameters.NewIoOffset = Parameters.IoOffset;
  4181. if (!KSUCCESS(Status)) {
  4182. goto PerformDirectoryIoOperationEnd;
  4183. }
  4184. //
  4185. // On success, both relative directory entries were added. Now off to the
  4186. // driver to add more.
  4187. //
  4188. ASSERT(Parameters.IoOffset >= DIRECTORY_CONTENTS_OFFSET);
  4189. //
  4190. // This I/O buffer does not need to be locked in memory at the moment.
  4191. // If some future file system requires use of the physical addresses,
  4192. // then it needs to be locked in memory.
  4193. //
  4194. Parameters.IoBuffer = Context->IoBuffer;
  4195. Parameters.DeviceContext = Handle->DeviceContext;
  4196. Parameters.IoFlags = Context->Flags;
  4197. Parameters.TimeoutInMilliseconds = Context->TimeoutInMilliseconds;
  4198. Parameters.IoSizeInBytes = Context->SizeInBytes;
  4199. Parameters.FileProperties = &(FileObject->Properties);
  4200. //
  4201. // Acquire the file lock in shared mode and fire off the I/O!
  4202. //
  4203. Device = FileObject->Device;
  4204. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  4205. Status = IopSendIoIrp(Device, IrpMinorIoRead, &Parameters);
  4206. if (KSUCCESS(Status) || (Status == STATUS_END_OF_FILE)) {
  4207. if ((Handle->OpenFlags & OPEN_FLAG_NO_ACCESS_TIME) == 0) {
  4208. ASSERT(LockHeldExclusive == FALSE);
  4209. KeSharedExclusiveLockConvertToExclusive(FileObject->Lock);
  4210. LockHeldExclusive = TRUE;
  4211. IopUpdateFileObjectTime(FileObject, FileObjectAccessTime);
  4212. }
  4213. }
  4214. PerformDirectoryIoOperationEnd:
  4215. //
  4216. // Adjust the current offset.
  4217. //
  4218. if (Context->Offset == IO_OFFSET_NONE) {
  4219. RtlAtomicExchange64((PULONGLONG)&(Handle->CurrentOffset),
  4220. Parameters.NewIoOffset);
  4221. }
  4222. if (LockHeldExclusive != FALSE) {
  4223. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  4224. } else {
  4225. KeReleaseSharedExclusiveLockShared(FileObject->Lock);
  4226. }
  4227. //
  4228. // Modify the file IDs of any directory entries that are mount points.
  4229. // This needs to happen for any directory entries read from disk.
  4230. //
  4231. if (Parameters.IoBytesCompleted != 0) {
  4232. IopFixMountPointDirectoryEntries(Handle,
  4233. Context->IoBuffer,
  4234. Parameters.IoBytesCompleted);
  4235. }
  4236. Context->BytesCompleted = Parameters.IoBytesCompleted;
  4237. return Status;
  4238. }
  4239. KSTATUS
  4240. IopAddRelativeDirectoryEntries (
  4241. PIO_HANDLE Handle,
  4242. PIO_OFFSET Offset,
  4243. PIO_BUFFER IoBuffer,
  4244. UINTN BufferSize,
  4245. PUINTN BytesConsumed
  4246. )
  4247. /*++
  4248. Routine Description:
  4249. This routine adds the relative . and .. directory entries to a directory
  4250. read operation.
  4251. Arguments:
  4252. Handle - Supplies the open I/O handle.
  4253. Offset - Supplies a pointer to the offset to read from. On return contains
  4254. the new offset.
  4255. IoBuffer - Supplies a pointer to the I/O buffer that will contain the added
  4256. relative directory entries on output.
  4257. BufferSize - Supplies the size of the I/O buffer, in bytes.
  4258. BytesConsumed - Supplies the a pointer that on input contains the number
  4259. of bytes in the buffer that have already been used. On output, it will
  4260. contain the updated number of bytes used.
  4261. Return Value:
  4262. Status code. A failing status code does not necessarily mean no I/O made it
  4263. in or out. Check the bytes completed value to find out how much occurred.
  4264. --*/
  4265. {
  4266. UINTN BytesAvailable;
  4267. PDIRECTORY_ENTRY Entry;
  4268. ULONG EntrySize;
  4269. PFILE_OBJECT FileObject;
  4270. IO_OFFSET FileOffset;
  4271. UCHAR LocalBuffer[sizeof(DIRECTORY_ENTRY) + sizeof("..") + 8];
  4272. PATH_POINT Parent;
  4273. PKPROCESS Process;
  4274. PPATH_POINT Root;
  4275. KSTATUS Status;
  4276. ASSERT(BufferSize >= *BytesConsumed);
  4277. BytesAvailable = BufferSize - *BytesConsumed;
  4278. FileOffset = *Offset;
  4279. Entry = (PDIRECTORY_ENTRY)LocalBuffer;
  4280. Status = STATUS_MORE_PROCESSING_REQUIRED;
  4281. //
  4282. // Tack on a . and a .. entry. Use reserved file offsets to remember
  4283. // which directory entries were reported.
  4284. //
  4285. if (FileOffset == DIRECTORY_OFFSET_DOT) {
  4286. EntrySize = ALIGN_RANGE_UP(sizeof(DIRECTORY_ENTRY) + sizeof("."), 8);
  4287. if (BytesAvailable > EntrySize) {
  4288. Entry->Size = EntrySize;
  4289. Entry->Type = IoObjectRegularDirectory;
  4290. Entry->NextOffset = DIRECTORY_OFFSET_DOT_DOT;
  4291. FileObject = Handle->FileObject;
  4292. ASSERT(FileObject == Handle->PathPoint.PathEntry->FileObject);
  4293. Entry->FileId = FileObject->Properties.FileId;
  4294. RtlCopyMemory(Entry + 1, ".", sizeof("."));
  4295. Status = MmCopyIoBufferData(IoBuffer,
  4296. Entry,
  4297. *BytesConsumed,
  4298. EntrySize,
  4299. TRUE);
  4300. if (!KSUCCESS(Status)) {
  4301. goto AddRelativeDirectoryEntriesEnd;
  4302. }
  4303. *BytesConsumed += EntrySize;
  4304. BytesAvailable -= EntrySize;
  4305. FileOffset = Entry->NextOffset;
  4306. }
  4307. }
  4308. if (FileOffset == DIRECTORY_OFFSET_DOT_DOT) {
  4309. EntrySize = ALIGN_RANGE_UP(sizeof(DIRECTORY_ENTRY) + sizeof(".."), 8);
  4310. if (BytesAvailable > EntrySize) {
  4311. Entry->Size = EntrySize;
  4312. Entry->Type = IoObjectRegularDirectory;
  4313. Entry->NextOffset = DIRECTORY_CONTENTS_OFFSET;
  4314. //
  4315. // Get the parent path point. Provide the process root to prevent
  4316. // leaking a file ID outside of the root. This does not need to
  4317. // hold the process' path locks because changing roots is required
  4318. // to be a single-threaded operation.
  4319. //
  4320. Root = NULL;
  4321. Process = PsGetCurrentProcess();
  4322. if (Process->Paths.Root.PathEntry != NULL) {
  4323. Root = (PPATH_POINT)&(Process->Paths.Root);
  4324. }
  4325. IopGetParentPathPoint(Root, &(Handle->PathPoint), &Parent);
  4326. FileObject = Parent.PathEntry->FileObject;
  4327. IO_PATH_POINT_RELEASE_REFERENCE(&Parent);
  4328. Entry->FileId = FileObject->Properties.FileId;
  4329. RtlCopyMemory(Entry + 1, "..", sizeof(".."));
  4330. Status = MmCopyIoBufferData(IoBuffer,
  4331. Entry,
  4332. *BytesConsumed,
  4333. EntrySize,
  4334. TRUE);
  4335. if (!KSUCCESS(Status)) {
  4336. goto AddRelativeDirectoryEntriesEnd;
  4337. }
  4338. *BytesConsumed += EntrySize;
  4339. BytesAvailable -= EntrySize;
  4340. FileOffset = Entry->NextOffset;
  4341. }
  4342. }
  4343. if (FileOffset >= DIRECTORY_CONTENTS_OFFSET) {
  4344. Status = STATUS_SUCCESS;
  4345. }
  4346. AddRelativeDirectoryEntriesEnd:
  4347. *Offset = FileOffset;
  4348. return Status;
  4349. }
  4350. VOID
  4351. IopFixMountPointDirectoryEntries (
  4352. PIO_HANDLE Handle,
  4353. PIO_BUFFER IoBuffer,
  4354. UINTN BufferSize
  4355. )
  4356. /*++
  4357. Routine Description:
  4358. This routine searches for mount points within the provided directory and
  4359. patches up the directory entries in the buffer to reflect those mount
  4360. points.
  4361. Arguments:
  4362. Handle - Supplies the open I/O handle.
  4363. IoBuffer - Supplies a pointer to the buffer filled with directory entries.
  4364. BufferSize - Supplies the size of the directory entries buffer.
  4365. Return Value:
  4366. None.
  4367. --*/
  4368. {
  4369. UINTN BytesRemaining;
  4370. PLIST_ENTRY CurrentEntry;
  4371. DIRECTORY_ENTRY DirectoryEntry;
  4372. BOOL FixRequired;
  4373. PMOUNT_POINT MountPoint;
  4374. UINTN Offset;
  4375. FILE_ID OriginalFileId;
  4376. PFILE_OBJECT OriginalFileObject;
  4377. PPATH_POINT PathPoint;
  4378. KSTATUS Status;
  4379. FILE_ID TargetFileId;
  4380. PFILE_OBJECT TargetFileObject;
  4381. PathPoint = &(Handle->PathPoint);
  4382. //
  4383. // If the current mount point has no children, then there is nothing to
  4384. // patch.
  4385. //
  4386. if (LIST_EMPTY(&(PathPoint->MountPoint->ChildListHead)) != FALSE) {
  4387. return;
  4388. }
  4389. //
  4390. // The current mount point has child mounts, but their root path entries
  4391. // are not necessarily children of the given current path entry. Check to
  4392. // make sure at least one fix up is required.
  4393. //
  4394. FixRequired = FALSE;
  4395. KeAcquireSharedExclusiveLockShared(IoMountLock);
  4396. CurrentEntry = PathPoint->MountPoint->ChildListHead.Next;
  4397. while (CurrentEntry != &(PathPoint->MountPoint->ChildListHead)) {
  4398. MountPoint = LIST_VALUE(CurrentEntry, MOUNT_POINT, SiblingListEntry);
  4399. if (MountPoint->MountEntry->Parent == PathPoint->PathEntry) {
  4400. FixRequired = TRUE;
  4401. break;
  4402. }
  4403. CurrentEntry = CurrentEntry->Next;
  4404. }
  4405. //
  4406. // If no mount points were direct children of the current path, then exit.
  4407. //
  4408. if (FixRequired == FALSE) {
  4409. goto FixMountPointDirectoryEntriesEnd;
  4410. }
  4411. //
  4412. // Otherwise, bite the bullet and iterate over the whole directory. Keep in
  4413. // mind that the mount point's child list may contain multiple entries that
  4414. // mount on top of the same file, so it should not be the primary loop.
  4415. //
  4416. Offset = 0;
  4417. BytesRemaining = BufferSize;
  4418. while (BytesRemaining >= sizeof(DIRECTORY_ENTRY)) {
  4419. Status = MmCopyIoBufferData(IoBuffer,
  4420. &DirectoryEntry,
  4421. Offset,
  4422. sizeof(DIRECTORY_ENTRY),
  4423. FALSE);
  4424. if (!KSUCCESS(Status)) {
  4425. goto FixMountPointDirectoryEntriesEnd;
  4426. }
  4427. OriginalFileId = DirectoryEntry.FileId;
  4428. TargetFileObject = NULL;
  4429. CurrentEntry = PathPoint->MountPoint->ChildListHead.Next;
  4430. while (CurrentEntry != &(PathPoint->MountPoint->ChildListHead)) {
  4431. MountPoint = LIST_VALUE(CurrentEntry,
  4432. MOUNT_POINT,
  4433. SiblingListEntry);
  4434. OriginalFileObject = MountPoint->MountEntry->FileObject;
  4435. if (OriginalFileObject->Properties.FileId == OriginalFileId) {
  4436. TargetFileObject = MountPoint->TargetEntry->FileObject;
  4437. TargetFileId = TargetFileObject->Properties.FileId;
  4438. break;
  4439. }
  4440. CurrentEntry = CurrentEntry->Next;
  4441. }
  4442. if (TargetFileObject != NULL) {
  4443. DirectoryEntry.FileId = TargetFileId;
  4444. MmCopyIoBufferData(IoBuffer,
  4445. &DirectoryEntry,
  4446. Offset,
  4447. sizeof(DIRECTORY_ENTRY),
  4448. TRUE);
  4449. }
  4450. Offset += DirectoryEntry.Size;
  4451. //
  4452. // Assert that the subtraction will not underflow.
  4453. //
  4454. ASSERT((BufferSize - Offset) <= BytesRemaining);
  4455. BytesRemaining = BufferSize - Offset;
  4456. }
  4457. FixMountPointDirectoryEntriesEnd:
  4458. KeReleaseSharedExclusiveLockShared(IoMountLock);
  4459. return;
  4460. }