path.c 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. path.c
  5. Abstract:
  6. This module implements support functionality for traversing paths.
  7. Author:
  8. Evan Green 18-Jun-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel.h>
  16. #include "iop.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // Define the default permissions for any object manager object.
  22. //
  23. #define OBJECT_DIRECTORY_PERMISSIONS \
  24. (FILE_PERMISSION_USER_READ | FILE_PERMISSION_USER_EXECUTE | \
  25. FILE_PERMISSION_GROUP_READ | FILE_PERMISSION_GROUP_EXECUTE | \
  26. FILE_PERMISSION_OTHER_READ | FILE_PERMISSION_OTHER_EXECUTE)
  27. //
  28. // Define the maximum size of the path entry cache, in percent of physical
  29. // memory.
  30. //
  31. #define PATH_ENTRY_CACHE_MAX_MEMORY_PERCENT 30
  32. //
  33. // Define the prefix prepended to an unreachable path.
  34. //
  35. #define PATH_UNREACHABLE_PATH_PREFIX "(unreachable)/"
  36. //
  37. // ------------------------------------------------------ Data Type Definitions
  38. //
  39. //
  40. // ----------------------------------------------- Internal Function Prototypes
  41. //
  42. KSTATUS
  43. IopPathWalkWorker (
  44. BOOL FromKernelMode,
  45. PPATH_POINT Start,
  46. PSTR *Path,
  47. PULONG PathSize,
  48. ULONG OpenFlags,
  49. IO_OBJECT_TYPE TypeOverride,
  50. PVOID OverrideParameter,
  51. FILE_PERMISSIONS CreatePermissions,
  52. ULONG RecursionLevel,
  53. PPATH_POINT Result
  54. );
  55. KSTATUS
  56. IopPathLookupThroughFileSystem (
  57. BOOL FromKernelMode,
  58. PPATH_POINT Directory,
  59. PSTR Name,
  60. ULONG NameSize,
  61. ULONG Hash,
  62. ULONG OpenFlags,
  63. IO_OBJECT_TYPE TypeOverride,
  64. PVOID OverrideParameter,
  65. FILE_PERMISSIONS CreatePermissions,
  66. PPATH_POINT Result
  67. );
  68. KSTATUS
  69. IopFollowSymbolicLink (
  70. BOOL FromKernelMode,
  71. ULONG OpenFlags,
  72. ULONG RecursionLevel,
  73. PPATH_POINT Directory,
  74. PPATH_POINT SymbolicLink,
  75. PPATH_POINT Result
  76. );
  77. ULONG
  78. IopHashPathString (
  79. PSTR String,
  80. ULONG StringSize
  81. );
  82. BOOL
  83. IopArePathsEqual (
  84. PSTR ExistingPath,
  85. PSTR QueryPath,
  86. ULONG QuerySize
  87. );
  88. BOOL
  89. IopFindPathPoint (
  90. PPATH_POINT Parent,
  91. ULONG OpenFlags,
  92. PSTR Name,
  93. ULONG NameSize,
  94. ULONG Hash,
  95. PPATH_POINT Result
  96. );
  97. VOID
  98. IopPathEntryReleaseReference (
  99. PPATH_ENTRY Entry,
  100. BOOL EnforceCacheSize,
  101. BOOL Destroy
  102. );
  103. PPATH_ENTRY
  104. IopDestroyPathEntry (
  105. PPATH_ENTRY Entry
  106. );
  107. UINTN
  108. IopGetPathEntryCacheTargetSize (
  109. VOID
  110. );
  111. //
  112. // -------------------------------------------------------------------- Globals
  113. //
  114. //
  115. // Store a pointer to the root path entry.
  116. //
  117. PATH_POINT IoPathPointRoot;
  118. //
  119. // Store the creation and modification dates used for object manager objects.
  120. //
  121. SYSTEM_TIME IoObjectManagerCreationTime;
  122. //
  123. // Store the LRU list of cached but unreferenced path entries.
  124. //
  125. PQUEUED_LOCK IoPathEntryListLock;
  126. LIST_ENTRY IoPathEntryList;
  127. UINTN IoPathEntryListSize;
  128. UINTN IoPathEntryListMaxSize;
  129. //
  130. // ------------------------------------------------------------------ Functions
  131. //
  132. KSTATUS
  133. IoPathAppend (
  134. PSTR Prefix,
  135. ULONG PrefixSize,
  136. PSTR Component,
  137. ULONG ComponentSize,
  138. ULONG AllocationTag,
  139. PSTR *AppendedPath,
  140. PULONG AppendedPathSize
  141. )
  142. /*++
  143. Routine Description:
  144. This routine appends a path component to a path.
  145. Arguments:
  146. Prefix - Supplies the initial path string. This can be null.
  147. PrefixSize - Supplies the size of the prefix string in bytes including the
  148. null terminator.
  149. Component - Supplies a pointer to the component string to add.
  150. ComponentSize - Supplies the size of the component string in bytes
  151. including a null terminator.
  152. AllocationTag - Supplies the tag to use for the combined allocation.
  153. AppendedPath - Supplies a pointer where the new path will be returned. The
  154. caller is responsible for freeing this memory..
  155. AppendedPathSize - Supplies a pointer where the size of the appended bath
  156. buffer in bytes including the null terminator will be returned.
  157. Return Value:
  158. TRUE on success.
  159. FALSE on failure.
  160. --*/
  161. {
  162. BOOL NeedSlash;
  163. PSTR NewPath;
  164. ULONG NewPathSize;
  165. KSTATUS Status;
  166. NeedSlash = FALSE;
  167. NewPath = NULL;
  168. NewPathSize = 0;
  169. //
  170. // Pull the trailing null off of the prefix string. If the prefix ends in
  171. // a slash then there's no need to append a slash.
  172. //
  173. if (Prefix != NULL) {
  174. ASSERT(PrefixSize != 0);
  175. if (Prefix[PrefixSize - 1] == '\0') {
  176. PrefixSize -= 1;
  177. if (PrefixSize == 0) {
  178. Prefix = NULL;
  179. }
  180. }
  181. NeedSlash = TRUE;
  182. if ((Prefix != NULL) && (Prefix[PrefixSize - 1] == '/')) {
  183. NeedSlash = FALSE;
  184. }
  185. }
  186. //
  187. // Get rid of any leading slashes in the component.
  188. //
  189. ASSERT(ComponentSize > 1);
  190. while ((ComponentSize != 0) && (*Component == '/')) {
  191. Component += 1;
  192. ComponentSize -= 1;
  193. }
  194. if ((ComponentSize == 0) || (*Component == '\0')) {
  195. Status = STATUS_INVALID_PARAMETER;
  196. goto PathAppendEnd;
  197. }
  198. if (Component[ComponentSize - 1] != '\0') {
  199. ComponentSize += 1;
  200. }
  201. //
  202. // Allocate and create the new string.
  203. //
  204. NewPathSize = PrefixSize + ComponentSize;
  205. if (NeedSlash != 0) {
  206. NewPathSize += 1;
  207. }
  208. NewPath = MmAllocatePagedPool(NewPathSize, AllocationTag);
  209. if (NewPath == NULL) {
  210. Status = STATUS_INSUFFICIENT_RESOURCES;
  211. goto PathAppendEnd;
  212. }
  213. if (Prefix != NULL) {
  214. RtlCopyMemory(NewPath, Prefix, PrefixSize);
  215. }
  216. if (NeedSlash != FALSE) {
  217. NewPath[PrefixSize] = '/';
  218. RtlCopyMemory(NewPath + PrefixSize + 1, Component, ComponentSize);
  219. } else {
  220. RtlCopyMemory(NewPath + PrefixSize, Component, ComponentSize);
  221. }
  222. NewPath[NewPathSize - 1] = '\0';
  223. Status = STATUS_SUCCESS;
  224. PathAppendEnd:
  225. if (!KSUCCESS(Status)) {
  226. if (NewPath != NULL) {
  227. MmFreePagedPool(NewPath);
  228. NewPath = NULL;
  229. }
  230. NewPathSize = 0;
  231. }
  232. *AppendedPath = NewPath;
  233. *AppendedPathSize = NewPathSize;
  234. return Status;
  235. }
  236. PPATH_POINT
  237. IoGetPathPoint (
  238. PIO_HANDLE IoHandle
  239. )
  240. /*++
  241. Routine Description:
  242. This routine returns the path point for the given handle.
  243. Arguments:
  244. IoHandle - Supplies a pointer to the I/O handle to get the path point of.
  245. Return Value:
  246. Returns a pointer to the path point corresponding to the given handle.
  247. --*/
  248. {
  249. PPAGING_IO_HANDLE PagingHandle;
  250. if (IoHandle->HandleType == IoHandleTypePaging) {
  251. PagingHandle = (PPAGING_IO_HANDLE)IoHandle;
  252. return &(PagingHandle->IoHandle->PathPoint);
  253. }
  254. return &(IoHandle->PathPoint);
  255. }
  256. VOID
  257. IoPathEntryAddReference (
  258. PPATH_ENTRY Entry
  259. )
  260. /*++
  261. Routine Description:
  262. This routine increments the reference count of the given path entry.
  263. Arguments:
  264. Entry - Supplies a pointer to the path entry.
  265. Return Value:
  266. None.
  267. --*/
  268. {
  269. ULONG OldReferenceCount;
  270. OldReferenceCount = RtlAtomicAdd32(&(Entry->ReferenceCount), 1);
  271. ASSERT(OldReferenceCount < 0x10000000);
  272. //
  273. // If this brought the path entry back from the cache, then remove it from
  274. // the cache list.
  275. //
  276. if (OldReferenceCount == 0) {
  277. ASSERT(KeGetRunLevel() == RunLevelLow);
  278. KeAcquireQueuedLock(IoPathEntryListLock);
  279. ASSERT(Entry->CacheListEntry.Next != NULL);
  280. LIST_REMOVE(&(Entry->CacheListEntry));
  281. Entry->CacheListEntry.Next = NULL;
  282. IoPathEntryListSize -= 1;
  283. KeReleaseQueuedLock(IoPathEntryListLock);
  284. }
  285. return;
  286. }
  287. VOID
  288. IoPathEntryReleaseReference (
  289. PPATH_ENTRY Entry
  290. )
  291. /*++
  292. Routine Description:
  293. This routine decrements the reference count of the given path entry. If the
  294. reference count drops to zero, the path entry will be destroyed.
  295. Arguments:
  296. Entry - Supplies a pointer to the path entry.
  297. Return Value:
  298. None.
  299. --*/
  300. {
  301. IopPathEntryReleaseReference(Entry, TRUE, FALSE);
  302. return;
  303. }
  304. KSTATUS
  305. IopInitializePathSupport (
  306. VOID
  307. )
  308. /*++
  309. Routine Description:
  310. This routine is called at system initialization time to initialize support
  311. for path traversal. It connects the root of the object manager to the root
  312. of the path/mount system.
  313. Arguments:
  314. None.
  315. Return Value:
  316. Status code.
  317. --*/
  318. {
  319. BOOL Created;
  320. PFILE_OBJECT FileObject;
  321. ULONGLONG MaxMemory;
  322. PPATH_ENTRY PathEntry;
  323. FILE_PROPERTIES Properties;
  324. PVOID RootObject;
  325. KSTATUS Status;
  326. ASSERT(IoPathPointRoot.PathEntry == NULL);
  327. FileObject = NULL;
  328. RootObject = NULL;
  329. KeGetSystemTime(&IoObjectManagerCreationTime);
  330. IoPathEntryListLock = KeCreateQueuedLock();
  331. if (IoPathEntryListLock == NULL) {
  332. Status = STATUS_INSUFFICIENT_RESOURCES;
  333. goto InitializePathSupportEnd;
  334. }
  335. INITIALIZE_LIST_HEAD(&IoPathEntryList);
  336. IoPathEntryListSize = 0;
  337. MaxMemory = MmGetTotalPhysicalPages() * MmPageSize();
  338. if (MaxMemory > (MAX_UINTN - (UINTN)KERNEL_VA_START + 1)) {
  339. MaxMemory = MAX_UINTN - (UINTN)KERNEL_VA_START + 1;
  340. }
  341. IoPathEntryListMaxSize = ((MaxMemory *
  342. PATH_ENTRY_CACHE_MAX_MEMORY_PERCENT) / 100) /
  343. sizeof(PATH_ENTRY);
  344. RootObject = ObGetRootObject();
  345. IopFillOutFilePropertiesForObject(&Properties, RootObject);
  346. Status = IopCreateOrLookupFileObject(&Properties,
  347. RootObject,
  348. FILE_OBJECT_FLAG_EXTERNAL_IO_STATE,
  349. &FileObject,
  350. &Created);
  351. if (!KSUCCESS(Status)) {
  352. goto InitializePathSupportEnd;
  353. }
  354. ASSERT(Created != FALSE);
  355. KeSignalEvent(FileObject->ReadyEvent, SignalOptionSignalAll);
  356. PathEntry = IopCreatePathEntry(NULL, 0, 0, NULL, FileObject);
  357. if (PathEntry == NULL) {
  358. Status = STATUS_INSUFFICIENT_RESOURCES;
  359. goto InitializePathSupportEnd;
  360. }
  361. IoPathPointRoot.PathEntry = PathEntry;
  362. InitializePathSupportEnd:
  363. if (!KSUCCESS(Status)) {
  364. if (IoPathEntryListLock != NULL) {
  365. KeDestroyQueuedLock(IoPathEntryListLock);
  366. IoPathEntryListLock = NULL;
  367. }
  368. if (RootObject != NULL) {
  369. ObReleaseReference(RootObject);
  370. }
  371. if (FileObject != NULL) {
  372. IopFileObjectReleaseReference(FileObject);
  373. }
  374. }
  375. return STATUS_SUCCESS;
  376. }
  377. KSTATUS
  378. IopPathWalk (
  379. BOOL FromKernelMode,
  380. PPATH_POINT Directory,
  381. PSTR *Path,
  382. PULONG PathSize,
  383. ULONG OpenFlags,
  384. IO_OBJECT_TYPE TypeOverride,
  385. PVOID OverrideParameter,
  386. FILE_PERMISSIONS CreatePermissions,
  387. PPATH_POINT Result
  388. )
  389. /*++
  390. Routine Description:
  391. This routine attempts to walk the given path.
  392. Arguments:
  393. FromKernelMode - Supplies a boolean indicating whether or not this request
  394. is coming directly from kernel mode (and should use the kernel's root).
  395. Directory - Supplies an optional pointer to a path point containing the
  396. directory to start from if the path is relative. Supply NULL to use the
  397. current working directory.
  398. Path - Supplies a pointer that on input contains a pointer to the string
  399. of the path to walk. This pointer will be advanced beyond the portion
  400. of the path that was successfully walked.
  401. PathSize - Supplies a pointer that on input contains the size of the
  402. input path string in bytes. This value will be updated to reflect the
  403. new size of the updated path string.
  404. OpenFlags - Supplies a bitfield of flags governing the behavior of the
  405. handle. See OPEN_FLAG_* definitions.
  406. TypeOverride - Supplies the type of object to create. If this is invalid,
  407. then this routine will try to open an existing object. If this type is
  408. valid, then this routine will attempt to create an object of the given
  409. type.
  410. OverrideParameter - Supplies an optional parameter to send along with the
  411. override type.
  412. CreatePermissions - Supplies the permissions to assign to a created file.
  413. Result - Supplies a pointer to a path point that receives the resulting
  414. path entry and mount point on success. The path entry and mount point
  415. will come with an extra reference on them, so the caller must be sure
  416. to release the references when finished.
  417. Return Value:
  418. Status code.
  419. --*/
  420. {
  421. KSTATUS Status;
  422. ASSERT((PVOID)(*Path) >= KERNEL_VA_START);
  423. Status = IopPathWalkWorker(FromKernelMode,
  424. Directory,
  425. Path,
  426. PathSize,
  427. OpenFlags,
  428. TypeOverride,
  429. OverrideParameter,
  430. CreatePermissions,
  431. 0,
  432. Result);
  433. return Status;
  434. }
  435. VOID
  436. IopFillOutFilePropertiesForObject (
  437. PFILE_PROPERTIES Properties,
  438. POBJECT_HEADER Object
  439. )
  440. /*++
  441. Routine Description:
  442. This routine fills out the file properties structure for an object manager
  443. object directory.
  444. Arguments:
  445. Properties - Supplies a pointer to the file properties.
  446. Object - Supplies a pointer to the object.
  447. Return Value:
  448. TRUE if the paths are equals.
  449. FALSE if the paths differ in some way.
  450. --*/
  451. {
  452. RtlZeroMemory(Properties, sizeof(FILE_PROPERTIES));
  453. Properties->DeviceId = OBJECT_MANAGER_DEVICE_ID;
  454. Properties->FileId = (FILE_ID)(UINTN)Object;
  455. ObAddReference(Object);
  456. Properties->Type = IoObjectObjectDirectory;
  457. Properties->HardLinkCount = 1;
  458. Properties->Permissions = OBJECT_DIRECTORY_PERMISSIONS;
  459. RtlCopyMemory(&(Properties->StatusChangeTime),
  460. &IoObjectManagerCreationTime,
  461. sizeof(SYSTEM_TIME));
  462. RtlCopyMemory(&(Properties->ModifiedTime),
  463. &IoObjectManagerCreationTime,
  464. sizeof(SYSTEM_TIME));
  465. RtlCopyMemory(&(Properties->AccessTime),
  466. &IoObjectManagerCreationTime,
  467. sizeof(SYSTEM_TIME));
  468. return;
  469. }
  470. PPATH_ENTRY
  471. IopCreateAnonymousPathEntry (
  472. PFILE_OBJECT FileObject
  473. )
  474. /*++
  475. Routine Description:
  476. This routine creates a new path entry structure that is not connected to
  477. the global path tree.
  478. Arguments:
  479. FileObject - Supplies a pointer to the file object backing this entry. This
  480. routine takes ownership of an assumed reference on the file object.
  481. Return Value:
  482. Returns a pointer to the path entry on success.
  483. NULL on allocation failure.
  484. --*/
  485. {
  486. return IopCreatePathEntry(NULL, 0, 0, NULL, FileObject);
  487. }
  488. KSTATUS
  489. IopPathSplit (
  490. PSTR Path,
  491. ULONG PathSize,
  492. PSTR *DirectoryComponent,
  493. PULONG DirectoryComponentSize,
  494. PSTR *LastComponent,
  495. PULONG LastComponentSize
  496. )
  497. /*++
  498. Routine Description:
  499. This routine creates a new string containing the last component of the
  500. given path.
  501. Arguments:
  502. Path - Supplies a pointer to the null terminated path string.
  503. PathSize - Supplies the size of the path string in bytes including the
  504. null terminator.
  505. DirectoryComponent - Supplies a pointer where a newly allocated string
  506. containing only the directory component will be returned on success.
  507. The caller is responsible for freeing this memory from paged pool.
  508. DirectoryComponentSize - Supplies a pointer where the size of the directory
  509. component buffer in bytes including the null terminator will be
  510. returned.
  511. LastComponent - Supplies a pointer where a newly allocated string
  512. containing only the last component will be returned on success. The
  513. caller is responsible for freeing this memory from paged pool.
  514. LastComponentSize - Supplies a pointer where the size of the last component
  515. buffer in bytes including the null terminator will be returned.
  516. Return Value:
  517. Status code.
  518. --*/
  519. {
  520. ULONG EndIndex;
  521. ULONG Length;
  522. PSTR NewDirectoryComponent;
  523. ULONG NewDirectoryComponentSize;
  524. PSTR NewLastComponent;
  525. ULONG NewLastComponentSize;
  526. ULONG NextStartIndex;
  527. ULONG StartIndex;
  528. KSTATUS Status;
  529. NewDirectoryComponent = NULL;
  530. NewDirectoryComponentSize = 0;
  531. NewLastComponent = NULL;
  532. NewLastComponentSize = 0;
  533. if ((Path == NULL) || (PathSize == 0)) {
  534. Status = STATUS_INVALID_PARAMETER;
  535. goto PathSplitEnd;
  536. }
  537. //
  538. // Loop looking at path components.
  539. //
  540. EndIndex = 0;
  541. StartIndex = 0;
  542. NextStartIndex = 0;
  543. while (TRUE) {
  544. //
  545. // Get past any path separators stuck on the beginning.
  546. //
  547. while ((Path[NextStartIndex] == PATH_SEPARATOR) &&
  548. (StartIndex < PathSize)) {
  549. NextStartIndex += 1;
  550. }
  551. //
  552. // This next part is just a bunch of trailing slashes, so stop, as the
  553. // path ended without a next component.
  554. //
  555. if ((NextStartIndex == PathSize) || (Path[NextStartIndex] == '\0')) {
  556. break;
  557. }
  558. //
  559. // Officially advance to this as a valid component, and find its end.
  560. //
  561. StartIndex = NextStartIndex;
  562. EndIndex = StartIndex;
  563. while ((EndIndex < PathSize) && (Path[EndIndex] != PATH_SEPARATOR) &&
  564. (Path[EndIndex] != '\0')) {
  565. EndIndex += 1;
  566. }
  567. //
  568. // If the path ended abruptly, add one to account for a null terminator
  569. // that should have been there, and stop.
  570. //
  571. if (EndIndex == PathSize) {
  572. EndIndex += 1;
  573. break;
  574. }
  575. if (Path[EndIndex] == '\0') {
  576. break;
  577. }
  578. NextStartIndex = EndIndex;
  579. }
  580. ASSERT(EndIndex >= StartIndex);
  581. //
  582. // Allocate and initialize the new buffer containing only the last
  583. // component.
  584. //
  585. Length = EndIndex - StartIndex;
  586. NewLastComponentSize = Length + 1;
  587. NewLastComponent = MmAllocatePagedPool(NewLastComponentSize,
  588. PATH_ALLOCATION_TAG);
  589. if (NewLastComponent == NULL) {
  590. Status = STATUS_INSUFFICIENT_RESOURCES;
  591. goto PathSplitEnd;
  592. }
  593. if (Length != 0) {
  594. RtlCopyMemory(NewLastComponent, Path + StartIndex, Length);
  595. }
  596. NewLastComponent[Length] = '\0';
  597. //
  598. // Allocate and initialize the new buffer containing only the directory
  599. // component.
  600. //
  601. NewDirectoryComponentSize = StartIndex + 1;
  602. NewDirectoryComponent = MmAllocatePagedPool(NewDirectoryComponentSize,
  603. PATH_ALLOCATION_TAG);
  604. if (NewDirectoryComponent == NULL) {
  605. Status = STATUS_INSUFFICIENT_RESOURCES;
  606. goto PathSplitEnd;
  607. }
  608. if (StartIndex != 0) {
  609. RtlCopyMemory(NewDirectoryComponent, Path, StartIndex);
  610. }
  611. NewDirectoryComponent[StartIndex] = '\0';
  612. Status = STATUS_SUCCESS;
  613. PathSplitEnd:
  614. if (!KSUCCESS(Status)) {
  615. if (NewLastComponent != NULL) {
  616. MmFreePagedPool(NewLastComponent);
  617. NewLastComponent = NULL;
  618. }
  619. NewLastComponentSize = 0;
  620. if (NewDirectoryComponent != NULL) {
  621. MmFreePagedPool(NewDirectoryComponent);
  622. NewDirectoryComponent = NULL;
  623. }
  624. NewDirectoryComponentSize = 0;
  625. }
  626. *DirectoryComponent = NewDirectoryComponent;
  627. *DirectoryComponentSize = NewDirectoryComponentSize;
  628. *LastComponent = NewLastComponent;
  629. *LastComponentSize = NewLastComponentSize;
  630. return Status;
  631. }
  632. PPATH_ENTRY
  633. IopCreatePathEntry (
  634. PSTR Name,
  635. ULONG NameSize,
  636. ULONG Hash,
  637. PPATH_ENTRY Parent,
  638. PFILE_OBJECT FileObject
  639. )
  640. /*++
  641. Routine Description:
  642. This routine creates a new path entry structure.
  643. Arguments:
  644. Name - Supplies an optional pointer to the name to give this path entry. A
  645. copy of this name will be made.
  646. NameSize - Supplies the size of the name buffer in bytes including the
  647. null terminator.
  648. Hash - Supplies the hash of the name string.
  649. Parent - Supplies a pointer to the parent of this entry.
  650. FileObject - Supplies an optional pointer to the file object backing this
  651. entry. This routine takes ownership of an assumed reference on the file
  652. object.
  653. Return Value:
  654. Returns a pointer to the path entry on success.
  655. NULL on allocation failure.
  656. --*/
  657. {
  658. ULONG AllocationSize;
  659. PPATH_ENTRY Entry;
  660. AllocationSize = sizeof(PATH_ENTRY);
  661. if (Name != NULL) {
  662. AllocationSize += NameSize;
  663. }
  664. Entry = MmAllocatePagedPool(AllocationSize, PATH_ALLOCATION_TAG);
  665. if (Entry == NULL) {
  666. return NULL;
  667. }
  668. RtlZeroMemory(Entry, sizeof(PATH_ENTRY));
  669. INITIALIZE_LIST_HEAD(&(Entry->ChildList));
  670. if (Name != NULL) {
  671. Entry->Name = (PSTR)(Entry + 1);
  672. RtlStringCopy(Entry->Name, Name, NameSize);
  673. Entry->NameSize = NameSize;
  674. }
  675. Entry->Hash = Hash;
  676. Entry->ReferenceCount = 1;
  677. if (Parent != NULL) {
  678. Entry->Parent = Parent;
  679. IoPathEntryAddReference(Parent);
  680. }
  681. if (FileObject != NULL) {
  682. Entry->FileObject = FileObject;
  683. //
  684. // The caller should have added an additional reference to the file
  685. // object before calling this routine.
  686. //
  687. ASSERT(FileObject->ReferenceCount >= 2);
  688. //
  689. // Increment the count of path entries that own the file object.
  690. //
  691. IopFileObjectAddPathEntryReference(Entry->FileObject);
  692. }
  693. return Entry;
  694. }
  695. BOOL
  696. IopIsDescendantPath (
  697. PPATH_ENTRY Ancestor,
  698. PPATH_ENTRY DescendantEntry
  699. )
  700. /*++
  701. Routine Description:
  702. This routine determines whether or not the given descendant path entry is a
  703. descendent of the given path entry. This does not take mount points into
  704. account.
  705. Arguments:
  706. Ancestor - Supplies a pointer to the possible ancestor path entry.
  707. DescendantEntry - Supplies a pointer to the possible descendant path entry.
  708. Return Value:
  709. Returns TRUE if it is a descendant, or FALSE otherwise.
  710. --*/
  711. {
  712. if (Ancestor == NULL) {
  713. return TRUE;
  714. }
  715. ASSERT(DescendantEntry != NULL);
  716. //
  717. // A path entry is a descendant of itself.
  718. //
  719. while (DescendantEntry != NULL) {
  720. if (DescendantEntry == Ancestor) {
  721. return TRUE;
  722. }
  723. DescendantEntry = DescendantEntry->Parent;
  724. }
  725. return FALSE;
  726. }
  727. VOID
  728. IopPathUnlink (
  729. PPATH_ENTRY Entry
  730. )
  731. /*++
  732. Routine Description:
  733. This routine unlinks the given path entry from the path hierarchy. In most
  734. cases the caller should hold both the path entry's file object lock (if it
  735. exists) and the parent path entry's file object lock exclusively.
  736. Arguments:
  737. Entry - Supplies a pointer to the path entry that is to be unlinked from
  738. the path hierarchy.
  739. Return Value:
  740. None.
  741. --*/
  742. {
  743. ASSERT(Entry->Parent != NULL);
  744. //
  745. // The path entry must be pulled out of the list (as opposed to converting
  746. // it to a negative entry) because I/O handles and mount points have
  747. // references/pointers to it.
  748. //
  749. if (Entry->SiblingListEntry.Next != NULL) {
  750. LIST_REMOVE(&(Entry->SiblingListEntry));
  751. Entry->SiblingListEntry.Next = NULL;
  752. }
  753. return;
  754. }
  755. KSTATUS
  756. IopGetPathFromRoot (
  757. PPATH_POINT Entry,
  758. PPATH_POINT Root,
  759. PSTR *Path,
  760. PULONG PathSize
  761. )
  762. /*++
  763. Routine Description:
  764. This routine creates a string representing the path from the given root to
  765. the given entry. If the entry is not a descendent of the given root, then
  766. the full path is printed.
  767. Arguments:
  768. Entry - Supplies a pointer to the path point where to stop the string.
  769. Root - Supplies a optional pointer to the path point to treat as root.
  770. Path - Supplies a pointer that receives the full path string.
  771. PathSize - Supplies a pointer that receives the size of the full path
  772. string, in bytes.
  773. Return Value:
  774. Status code.
  775. --*/
  776. {
  777. KSTATUS Status;
  778. KeAcquireSharedExclusiveLockShared(IoMountLock);
  779. Status = IopGetPathFromRootUnlocked(Entry, Root, Path, PathSize);
  780. KeReleaseSharedExclusiveLockShared(IoMountLock);
  781. return Status;
  782. }
  783. KSTATUS
  784. IopGetPathFromRootUnlocked (
  785. PPATH_POINT Entry,
  786. PPATH_POINT Root,
  787. PSTR *Path,
  788. PULONG PathSize
  789. )
  790. /*++
  791. Routine Description:
  792. This routine creates a string representing the path from the given root to
  793. the given entry. If the entry is not a descendent of the given root, then
  794. the full path is printed. This routine assumes that the mount lock is held
  795. in shared mode.
  796. Arguments:
  797. Entry - Supplies a pointer to the path point where to stop the string.
  798. Root - Supplies a optional pointer to the path point to treat as root.
  799. Path - Supplies a pointer that receives the full path string.
  800. PathSize - Supplies a pointer that receives the size of the full path
  801. string, in bytes.
  802. Return Value:
  803. Status code.
  804. --*/
  805. {
  806. PSTR Name;
  807. ULONG NameSize;
  808. ULONG Offset;
  809. PSTR PathBuffer;
  810. ULONG PathBufferSize;
  811. PATH_POINT PathPoint;
  812. ULONG PrefixSize;
  813. KSTATUS Status;
  814. PPATH_POINT TrueRoot;
  815. BOOL Unreachable;
  816. ASSERT(KeIsSharedExclusiveLockHeldShared(IoMountLock) != FALSE);
  817. ASSERT((Root == NULL) || (Root->PathEntry != NULL));
  818. TrueRoot = &IoPathPointRoot;
  819. if (Root == NULL) {
  820. Root = TrueRoot;
  821. }
  822. //
  823. // Do a quick check for NULL, root, and equal path points. If
  824. // this is the case then the path is just "/".
  825. //
  826. if ((Entry == Root) ||
  827. (Entry == NULL) ||
  828. (Entry->PathEntry == NULL) ||
  829. (Entry->MountPoint == NULL) ||
  830. (IO_ARE_PATH_POINTS_EQUAL(Entry, Root) != FALSE) ||
  831. (IO_ARE_PATH_POINTS_EQUAL(Entry, TrueRoot) != FALSE)) {
  832. PathBufferSize = sizeof(CHAR) * 2;
  833. PathBuffer = MmAllocatePagedPool(PathBufferSize, PATH_ALLOCATION_TAG);
  834. if (PathBuffer == NULL) {
  835. Status = STATUS_INSUFFICIENT_RESOURCES;
  836. goto GetPathFromRootEnd;
  837. }
  838. PathBuffer[0] = PATH_SEPARATOR;
  839. PathBuffer[1] = STRING_TERMINATOR;
  840. *Path = PathBuffer;
  841. *PathSize = PathBufferSize;
  842. Status = STATUS_SUCCESS;
  843. goto GetPathFromRootEnd;
  844. }
  845. //
  846. // Fail for an anonymous path entry unless it is a mount point.
  847. //
  848. if ((Entry->PathEntry->NameSize == 0) &&
  849. (IO_IS_MOUNT_POINT(Entry) == FALSE)) {
  850. Status = STATUS_PATH_NOT_FOUND;
  851. goto GetPathFromRootEnd;
  852. }
  853. //
  854. // Determine the size of the path.
  855. //
  856. Unreachable = FALSE;
  857. PathBufferSize = 0;
  858. IO_COPY_PATH_POINT(&PathPoint, Entry);
  859. while ((IO_ARE_PATH_POINTS_EQUAL(&PathPoint, Root) == FALSE) &&
  860. (IO_ARE_PATH_POINTS_EQUAL(&PathPoint, TrueRoot) == FALSE)) {
  861. if (IO_IS_MOUNT_POINT(&PathPoint) != FALSE) {
  862. if (PathPoint.MountPoint->Parent == NULL) {
  863. Unreachable = TRUE;
  864. break;
  865. }
  866. PathBufferSize += PathPoint.MountPoint->MountEntry->NameSize;
  867. PathPoint.PathEntry = PathPoint.MountPoint->MountEntry->Parent;
  868. PathPoint.MountPoint = PathPoint.MountPoint->Parent;
  869. } else {
  870. PathBufferSize += PathPoint.PathEntry->NameSize;
  871. PathPoint.PathEntry = PathPoint.PathEntry->Parent;
  872. }
  873. }
  874. //
  875. // If the path was found to be unreachable, add the appropriate prefix. If
  876. // the path point is equal to the original entry, then add space for the
  877. // null terminator.
  878. //
  879. if (Unreachable != FALSE) {
  880. PathBufferSize += RtlStringLength(PATH_UNREACHABLE_PATH_PREFIX);
  881. if (IO_ARE_PATH_POINTS_EQUAL(&PathPoint, Entry) != FALSE) {
  882. PathBufferSize += sizeof(CHAR);
  883. }
  884. //
  885. // Otherwise add space for the root slash.
  886. //
  887. } else {
  888. PathBufferSize += sizeof(CHAR);
  889. }
  890. //
  891. // Allocate a buffer for the path.
  892. //
  893. PathBuffer = MmAllocatePagedPool(PathBufferSize, PATH_ALLOCATION_TAG);
  894. if (PathBuffer == NULL) {
  895. Status = STATUS_INSUFFICIENT_RESOURCES;
  896. goto GetPathFromRootEnd;
  897. }
  898. //
  899. // Now roll through again and create the path, backwards. Because the mount
  900. // lock is held shared, this should get the exact same path result as above.
  901. //
  902. Offset = PathBufferSize;
  903. IO_COPY_PATH_POINT(&PathPoint, Entry);
  904. while ((IO_ARE_PATH_POINTS_EQUAL(&PathPoint, Root) == FALSE) &&
  905. (IO_ARE_PATH_POINTS_EQUAL(&PathPoint, TrueRoot) == FALSE)) {
  906. if (IO_IS_MOUNT_POINT(&PathPoint) != FALSE) {
  907. if (PathPoint.MountPoint->Parent == NULL) {
  908. ASSERT(Unreachable != FALSE);
  909. break;
  910. }
  911. NameSize = PathPoint.MountPoint->MountEntry->NameSize;
  912. Name = PathPoint.MountPoint->MountEntry->Name;
  913. PathPoint.PathEntry = PathPoint.MountPoint->MountEntry->Parent;
  914. PathPoint.MountPoint = PathPoint.MountPoint->Parent;
  915. } else {
  916. NameSize = PathPoint.PathEntry->NameSize;
  917. Name = PathPoint.PathEntry->Name;
  918. PathPoint.PathEntry = PathPoint.PathEntry->Parent;
  919. }
  920. //
  921. // Add the null terminator for the final entry.
  922. //
  923. if (Offset == PathBufferSize) {
  924. PathBuffer[Offset - 1] = STRING_TERMINATOR;
  925. //
  926. // Add path separators for the non-terminal entries.
  927. //
  928. } else {
  929. PathBuffer[Offset - 1] = PATH_SEPARATOR;
  930. }
  931. Offset -= NameSize;
  932. RtlCopyMemory(PathBuffer + Offset, Name, NameSize - 1);
  933. }
  934. //
  935. // If the path is unreachable, then prepend the string with the unreachable
  936. // string.
  937. //
  938. if (Unreachable != FALSE) {
  939. if (Offset == PathBufferSize) {
  940. Offset -= 1;
  941. PathBuffer[Offset] = STRING_TERMINATOR;
  942. }
  943. PrefixSize = RtlStringLength(PATH_UNREACHABLE_PATH_PREFIX);
  944. Offset -= PrefixSize;
  945. ASSERT(Offset == 0);
  946. RtlCopyMemory(PathBuffer + Offset,
  947. PATH_UNREACHABLE_PATH_PREFIX,
  948. PrefixSize);
  949. //
  950. // Otherwise add the last separator for the root.
  951. //
  952. } else {
  953. ASSERT(Offset == 1);
  954. Offset -= 1;
  955. PathBuffer[Offset] = PATH_SEPARATOR;
  956. }
  957. //
  958. // The string better be null terminated.
  959. //
  960. ASSERT(PathBuffer[PathBufferSize - 1] == STRING_TERMINATOR);
  961. *Path = PathBuffer;
  962. *PathSize = PathBufferSize;
  963. Status = STATUS_SUCCESS;
  964. GetPathFromRootEnd:
  965. return Status;
  966. }
  967. KSTATUS
  968. IopPathLookup (
  969. BOOL FromKernelMode,
  970. PPATH_POINT Root,
  971. PPATH_POINT Directory,
  972. BOOL DirectoryLockHeld,
  973. PSTR Name,
  974. ULONG NameSize,
  975. ULONG OpenFlags,
  976. IO_OBJECT_TYPE TypeOverride,
  977. PVOID OverrideParameter,
  978. FILE_PERMISSIONS CreatePermissions,
  979. PPATH_POINT Result
  980. )
  981. /*++
  982. Routine Description:
  983. This routine attempts to look up a child with the given name in a directory.
  984. Arguments:
  985. FromKernelMode - Supplies a boolean indicating whether this request is
  986. originating from kernel mode (TRUE) or user mode (FALSE). Kernel mode
  987. requests are not subjected to permission checks.
  988. Root - Supplies a pointer to the caller's root path point.
  989. Directory - Supplies a pointer to the path point to search.
  990. DirectoryLockHeld - Supplies a boolean indicating whether or not the caller
  991. had already acquired the directory's lock (exclusively).
  992. Name - Supplies a pointer to the name string.
  993. NameSize - Supplies a pointer to the size of the string in bytes
  994. including an assumed null terminator.
  995. OpenFlags - Supplies a bitfield of flags governing the behavior of the
  996. handle. See OPEN_FLAG_* definitions.
  997. TypeOverride - Supplies the type of object to create. If this is invalid,
  998. then this routine will try to open an existing object. If this type is
  999. valid, then this routine will attempt to create an object of the given
  1000. type.
  1001. OverrideParameter - Supplies an optional parameter to send along with the
  1002. override type.
  1003. CreatePermissions - Supplies the permissions to assign to a created file.
  1004. Result - Supplies a pointer to a path point that receives the resulting
  1005. path entry and mount point on success. The path entry and mount point
  1006. will come with an extra reference on them, so the caller must be sure
  1007. to release the references when finished. This routine may return a
  1008. path entry even on failing status codes, such as a negative path entry.
  1009. Return Value:
  1010. Status code.
  1011. --*/
  1012. {
  1013. PFILE_OBJECT DirectoryFileObject;
  1014. BOOL FoundPathPoint;
  1015. ULONG Hash;
  1016. KSTATUS Status;
  1017. Result->PathEntry = NULL;
  1018. ASSERT(NameSize != 0);
  1019. //
  1020. // This had better be a directory of some kind.
  1021. //
  1022. DirectoryFileObject = Directory->PathEntry->FileObject;
  1023. if ((DirectoryFileObject->Properties.Type != IoObjectRegularDirectory) &&
  1024. (DirectoryFileObject->Properties.Type != IoObjectObjectDirectory)) {
  1025. return STATUS_NOT_A_DIRECTORY;
  1026. }
  1027. //
  1028. // Either it was specified that the directory lock was not held, or it
  1029. // better be held.
  1030. //
  1031. ASSERT((DirectoryLockHeld == FALSE) ||
  1032. (KeIsSharedExclusiveLockHeldExclusive(DirectoryFileObject->Lock)));
  1033. //
  1034. // First look for the . and .. values.
  1035. //
  1036. if (IopArePathsEqual(".", Name, NameSize) != FALSE) {
  1037. if (TypeOverride != IoObjectInvalid) {
  1038. return STATUS_FILE_EXISTS;
  1039. }
  1040. //
  1041. // This add reference is safe without a lock because the caller should
  1042. // already have an extra reference on the directory.
  1043. //
  1044. IO_COPY_PATH_POINT(Result, Directory);
  1045. IO_PATH_POINT_ADD_REFERENCE(Result);
  1046. return STATUS_SUCCESS;
  1047. } else if (IopArePathsEqual("..", Name, NameSize) != FALSE) {
  1048. if (TypeOverride != IoObjectInvalid) {
  1049. return STATUS_FILE_EXISTS;
  1050. }
  1051. IopGetParentPathPoint(Root, Directory, Result);
  1052. return STATUS_SUCCESS;
  1053. }
  1054. //
  1055. // First cruise through the cached list looking for this entry. Successful
  1056. // return adds a reference to the found entry.
  1057. //
  1058. if (DirectoryLockHeld == FALSE) {
  1059. KeAcquireSharedExclusiveLockShared(DirectoryFileObject->Lock);
  1060. }
  1061. Hash = IopHashPathString(Name, NameSize);
  1062. FoundPathPoint = IopFindPathPoint(Directory,
  1063. OpenFlags,
  1064. Name,
  1065. NameSize,
  1066. Hash,
  1067. Result);
  1068. if (DirectoryLockHeld == FALSE) {
  1069. KeReleaseSharedExclusiveLockShared(DirectoryFileObject->Lock);
  1070. }
  1071. if (FoundPathPoint != FALSE) {
  1072. //
  1073. // If a negative cache entry was found, return "not found" unless the
  1074. // caller is trying to create.
  1075. //
  1076. if (Result->PathEntry->Negative != FALSE) {
  1077. if (TypeOverride == IoObjectInvalid) {
  1078. return STATUS_PATH_NOT_FOUND;
  1079. }
  1080. ASSERT(DirectoryLockHeld == FALSE);
  1081. IO_PATH_POINT_RELEASE_REFERENCE(Result);
  1082. Result->PathEntry = NULL;
  1083. //
  1084. // A real path entry was found, return it.
  1085. //
  1086. } else {
  1087. if ((TypeOverride != IoObjectInvalid) &&
  1088. ((OpenFlags & OPEN_FLAG_FAIL_IF_EXISTS) != 0)) {
  1089. return STATUS_FILE_EXISTS;
  1090. }
  1091. return STATUS_SUCCESS;
  1092. }
  1093. }
  1094. //
  1095. // Fine, do it the hard way.
  1096. //
  1097. if (DirectoryLockHeld == FALSE) {
  1098. KeAcquireSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
  1099. }
  1100. Status = IopPathLookupThroughFileSystem(FromKernelMode,
  1101. Directory,
  1102. Name,
  1103. NameSize,
  1104. Hash,
  1105. OpenFlags,
  1106. TypeOverride,
  1107. OverrideParameter,
  1108. CreatePermissions,
  1109. Result);
  1110. if (DirectoryLockHeld == FALSE) {
  1111. KeReleaseSharedExclusiveLockExclusive(DirectoryFileObject->Lock);
  1112. }
  1113. return Status;
  1114. }
  1115. VOID
  1116. IopPathCleanCache (
  1117. PPATH_ENTRY RootPath
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. This routine attempts to destroy any cached path entries below the given
  1122. root path. In the process of doing so, it unlinks the given root path
  1123. (if necessary) and dismantles the tree of path entries below it.
  1124. Arguments:
  1125. RootPath - Supplies a pointer to the root path entry.
  1126. DoNotCache - Supplies a boolean indicating whether or not to mark open
  1127. path entries as non-cacheable or not.
  1128. Return Value:
  1129. None.
  1130. --*/
  1131. {
  1132. PPATH_ENTRY ChildPath;
  1133. PLIST_ENTRY CurrentEntry;
  1134. PPATH_ENTRY CurrentPath;
  1135. PFILE_OBJECT FileObject;
  1136. LIST_ENTRY ProcessList;
  1137. INITIALIZE_LIST_HEAD(&ProcessList);
  1138. //
  1139. // Unlink the current root so that it can be inserted on the local list.
  1140. //
  1141. if (RootPath->SiblingListEntry.Next != NULL) {
  1142. ASSERT(RootPath->Parent != NULL);
  1143. FileObject = RootPath->Parent->FileObject;
  1144. KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
  1145. IopPathUnlink(RootPath);
  1146. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  1147. }
  1148. //
  1149. // Do nothing if the root path has no children. There is no reason to add
  1150. // and remove a reference on it.
  1151. //
  1152. if (LIST_EMPTY(&(RootPath->ChildList)) != FALSE) {
  1153. return;
  1154. }
  1155. //
  1156. // Reference the root path and add it to the list of path entries that are
  1157. // to be processed.
  1158. //
  1159. ASSERT(RootPath->SiblingListEntry.Next == NULL);
  1160. IoPathEntryAddReference(RootPath);
  1161. INSERT_BEFORE(&(RootPath->SiblingListEntry), &ProcessList);
  1162. //
  1163. // Iterate over the list of path entries to process. This will "flatten"
  1164. // the tree by adding more entries to the list as it goes. For any cached
  1165. // path entries, it will add and release a reference after unlinking the
  1166. // path entry, which will trigger destruction.
  1167. //
  1168. CurrentEntry = ProcessList.Next;
  1169. while (CurrentEntry != &ProcessList) {
  1170. CurrentPath = LIST_VALUE(CurrentEntry, PATH_ENTRY, SiblingListEntry);
  1171. FileObject = NULL;
  1172. if (CurrentPath->Negative == FALSE) {
  1173. FileObject = CurrentPath->FileObject;
  1174. KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
  1175. }
  1176. //
  1177. // Process the children. An open child will get moved to the list being
  1178. // processed. A cached child will either get added to the destroy list
  1179. // or be left in the cache.
  1180. //
  1181. while (LIST_EMPTY(&(CurrentPath->ChildList)) == FALSE) {
  1182. ChildPath = LIST_VALUE(CurrentPath->ChildList.Next,
  1183. PATH_ENTRY,
  1184. SiblingListEntry);
  1185. IoPathEntryAddReference(ChildPath);
  1186. IopPathUnlink(ChildPath);
  1187. INSERT_BEFORE(&(ChildPath->SiblingListEntry), &ProcessList);
  1188. }
  1189. if (FileObject != NULL) {
  1190. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  1191. }
  1192. //
  1193. // Release the reference taken for the active list and move to the next
  1194. // entry (this must be done after the children are processed).
  1195. // Releasing this reference may destroy the current path entry.
  1196. //
  1197. CurrentEntry = CurrentEntry->Next;
  1198. CurrentPath->SiblingListEntry.Next = NULL;
  1199. IoPathEntryReleaseReference(CurrentPath);
  1200. }
  1201. return;
  1202. }
  1203. VOID
  1204. IopPathEntryIncrementMountCount (
  1205. PPATH_ENTRY PathEntry
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This routine increments the mount count for the given path entry.
  1210. Arguments:
  1211. PathEntry - Supplies a pointer to a path entry.
  1212. Return Value:
  1213. None.
  1214. --*/
  1215. {
  1216. ULONG OldMountCount;
  1217. OldMountCount = RtlAtomicAdd32(&(PathEntry->MountCount), 1);
  1218. ASSERT(OldMountCount < 0x10000000);
  1219. return;
  1220. }
  1221. VOID
  1222. IopPathEntryDecrementMountCount (
  1223. PPATH_ENTRY PathEntry
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. This routine decrements the mount count for the given path entry.
  1228. Arguments:
  1229. PathEntry - Supplies a pointer to a path entry.
  1230. Return Value:
  1231. None.
  1232. --*/
  1233. {
  1234. ULONG OldMountCount;
  1235. OldMountCount = RtlAtomicAdd32(&(PathEntry->MountCount), (ULONG)-1);
  1236. ASSERT((OldMountCount != 0) && (OldMountCount < 0x10000000));
  1237. return;
  1238. }
  1239. VOID
  1240. IopGetParentPathPoint (
  1241. PPATH_POINT Root,
  1242. PPATH_POINT PathPoint,
  1243. PPATH_POINT ParentPathPoint
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. This routine gets the parent path point of the given path point, correctly
  1248. traversing mount points. This routine takes references on the parent path
  1249. point's path entry and mount point.
  1250. Arguments:
  1251. Root - Supplies an optional pointer to the caller's path point root. If
  1252. supplied, then the parent will never be lower in the path tree than
  1253. the root.
  1254. PathPoint - Supplies a pointer to the path point whose parent is being
  1255. queried.
  1256. ParentPathPoint - Supplies a pointer to a path point that receives the
  1257. parent path point's information.
  1258. Return Value:
  1259. None.
  1260. --*/
  1261. {
  1262. PMOUNT_POINT MountPoint;
  1263. PPATH_ENTRY PathEntry;
  1264. MountPoint = NULL;
  1265. PathEntry = NULL;
  1266. //
  1267. // Prevent the caller from going above their root, if supplied.
  1268. //
  1269. if ((Root == NULL) ||
  1270. (IO_ARE_PATH_POINTS_EQUAL(PathPoint, Root) == FALSE)) {
  1271. //
  1272. // If the path point is a mount point, then move out of the mount point
  1273. // to the mount entry's parent. Be careful here as the parent might
  1274. // disappear with a lazy unmount. If it does, just return the current
  1275. // path point.
  1276. //
  1277. if (IO_IS_MOUNT_POINT(PathPoint) != FALSE) {
  1278. MountPoint = IopGetMountPointParent(PathPoint->MountPoint);
  1279. if (MountPoint == NULL) {
  1280. PathEntry = NULL;
  1281. } else {
  1282. PathEntry = PathPoint->MountPoint->MountEntry->Parent;
  1283. }
  1284. //
  1285. // Otherwise just move to the directory's parent, which belongs to the
  1286. // same mount point. Be careful, as the root mount point does not have
  1287. // a parent.
  1288. //
  1289. } else if (PathPoint->PathEntry->Parent != NULL) {
  1290. PathEntry = PathPoint->PathEntry->Parent;
  1291. MountPoint = PathPoint->MountPoint;
  1292. IoMountPointAddReference(MountPoint);
  1293. }
  1294. }
  1295. //
  1296. // If nothing suitable was found, remain in the same directory.
  1297. //
  1298. if (PathEntry == NULL) {
  1299. ASSERT(MountPoint == NULL);
  1300. PathEntry = PathPoint->PathEntry;
  1301. MountPoint = PathPoint->MountPoint;
  1302. IoMountPointAddReference(MountPoint);
  1303. }
  1304. //
  1305. // This add reference is safe because the caller has a reference on the
  1306. // given path point, preventing the parent path from being released in
  1307. // medias res.
  1308. //
  1309. IoPathEntryAddReference(PathEntry);
  1310. ParentPathPoint->PathEntry = PathEntry;
  1311. ParentPathPoint->MountPoint = MountPoint;
  1312. return;
  1313. }
  1314. //
  1315. // --------------------------------------------------------- Internal Functions
  1316. //
  1317. KSTATUS
  1318. IopPathWalkWorker (
  1319. BOOL FromKernelMode,
  1320. PPATH_POINT Start,
  1321. PSTR *Path,
  1322. PULONG PathSize,
  1323. ULONG OpenFlags,
  1324. IO_OBJECT_TYPE TypeOverride,
  1325. PVOID OverrideParameter,
  1326. FILE_PERMISSIONS CreatePermissions,
  1327. ULONG RecursionLevel,
  1328. PPATH_POINT Result
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. This routine attempts to walk the given path.
  1333. Arguments:
  1334. FromKernelMode - Supplies a boolean indicating whether or not this request
  1335. is coming directly from kernel mode (and should use the kernel's root).
  1336. Start - Supplies a pointer to the path point to start the walk from.
  1337. Path - Supplies a pointer that on input contains a pointer to the string
  1338. of the path to walk. This pointer will be advanced beyond the portion
  1339. of the path that was successfully walked.
  1340. PathSize - Supplies a pointer that on input contains the size of the
  1341. input path string in bytes. This value will be updated to reflect the
  1342. new size of the updated path string.
  1343. OpenFlags - Supplies a bitfield of flags governing the behavior of the
  1344. handle. See OPEN_FLAG_* definitions.
  1345. TypeOverride - Supplies the type of object to create. If this is invalid,
  1346. then this routine will try to open an existing object. If this type is
  1347. valid, then this routine will attempt to create an object of the given
  1348. type.
  1349. OverrideParameter - Supplies an optional parameter to send along with the
  1350. override type.
  1351. CreatePermissions - Supplies the permissions to assign to a created file.
  1352. RecursionLevel - Supplies the recursion level used internally to avoid
  1353. symbolic link loops.
  1354. Result - Supplies a pointer to a path point that receives the resulting
  1355. path entry and mount point on success. The path entry and mount point
  1356. will come with an extra reference on them, so the caller must be sure
  1357. to release the references when finished.
  1358. Return Value:
  1359. Status code.
  1360. --*/
  1361. {
  1362. ULONG ComponentSize;
  1363. BOOL Create;
  1364. PSTR CurrentPath;
  1365. ULONG CurrentPathSize;
  1366. PATH_POINT Entry;
  1367. PFILE_OBJECT FileObject;
  1368. BOOL FollowLink;
  1369. PATH_POINT LinkEntry;
  1370. PATH_POINT NextEntry;
  1371. PSTR NextSeparator;
  1372. PKPROCESS Process;
  1373. ULONG RemainingSize;
  1374. PPATH_POINT Root;
  1375. PATH_POINT RootCopy;
  1376. KSTATUS Status;
  1377. ULONG ThisIterationOpenFlags;
  1378. IO_OBJECT_TYPE ThisOverride;
  1379. ASSERT(KeGetRunLevel() == RunLevelLow);
  1380. CurrentPath = *Path;
  1381. CurrentPathSize = *PathSize;
  1382. Entry.PathEntry = NULL;
  1383. //
  1384. // Empty paths do not resolve to anything.
  1385. //
  1386. if ((CurrentPathSize <= 1) || (*CurrentPath == '\0')) {
  1387. return STATUS_PATH_NOT_FOUND;
  1388. }
  1389. CurrentPathSize -= 1;
  1390. //
  1391. // If a valid I/O object type was supplied, then this is a create.
  1392. //
  1393. Create = FALSE;
  1394. if (TypeOverride != IoObjectInvalid) {
  1395. Create = TRUE;
  1396. }
  1397. //
  1398. // For all components except the end, follow symbolic links.
  1399. //
  1400. FollowLink = TRUE;
  1401. if (FromKernelMode != FALSE) {
  1402. Process = PsGetKernelProcess();
  1403. } else {
  1404. Process = PsGetCurrentProcess();
  1405. }
  1406. //
  1407. // Get the path entry to start with.
  1408. //
  1409. KeAcquireQueuedLock(Process->Paths.Lock);
  1410. Root = (PPATH_POINT)&(Process->Paths.Root);
  1411. if (Root->PathEntry != NULL) {
  1412. IO_COPY_PATH_POINT(&RootCopy, Root);
  1413. Root = &RootCopy;
  1414. } else {
  1415. Root = &IoPathPointRoot;
  1416. }
  1417. if (*CurrentPath != PATH_SEPARATOR) {
  1418. if (Start != NULL) {
  1419. IO_COPY_PATH_POINT(&Entry, Start);
  1420. } else {
  1421. IO_COPY_PATH_POINT(&Entry, &(Process->Paths.CurrentDirectory));
  1422. }
  1423. }
  1424. if (Entry.PathEntry == NULL) {
  1425. IO_COPY_PATH_POINT(&Entry, Root);
  1426. }
  1427. //
  1428. // This add reference is safe because the root will never be removed and
  1429. // the current directory always has an additional reference preventing it
  1430. // from being removed in the middle of this operation.
  1431. //
  1432. IO_PATH_POINT_ADD_REFERENCE(Root);
  1433. IO_PATH_POINT_ADD_REFERENCE(&Entry);
  1434. KeReleaseQueuedLock(Process->Paths.Lock);
  1435. //
  1436. // Loop walking path components.
  1437. //
  1438. while (CurrentPathSize != 0) {
  1439. //
  1440. // Get past any separators.
  1441. //
  1442. while ((CurrentPathSize != 0) && (*CurrentPath == PATH_SEPARATOR)) {
  1443. CurrentPath += 1;
  1444. CurrentPathSize -= 1;
  1445. }
  1446. if ((*CurrentPath == '\0') || (CurrentPathSize == 0)) {
  1447. break;
  1448. }
  1449. //
  1450. // Find the next separator. A trailing slash on the end of a final
  1451. // path component is treated as if it's not the final component.
  1452. //
  1453. RemainingSize = CurrentPathSize;
  1454. NextSeparator = CurrentPath;
  1455. while ((*NextSeparator != PATH_SEPARATOR) && (*NextSeparator != '\0') &&
  1456. (RemainingSize != 0)) {
  1457. RemainingSize -= 1;
  1458. NextSeparator += 1;
  1459. }
  1460. if ((*NextSeparator == '\0') || (RemainingSize == 0)) {
  1461. NextSeparator = NULL;
  1462. }
  1463. ComponentSize = CurrentPathSize - RemainingSize;
  1464. //
  1465. // If it's a create operation and this is the last component, then
  1466. // feed in the type override. Otherwise, this is just an open
  1467. // operation of a directory along the way.
  1468. //
  1469. ThisOverride = IoObjectInvalid;
  1470. ThisIterationOpenFlags = OPEN_FLAG_DIRECTORY;
  1471. if (NextSeparator == NULL) {
  1472. ThisIterationOpenFlags = OpenFlags;
  1473. if (Create != FALSE) {
  1474. ThisOverride = TypeOverride;
  1475. }
  1476. //
  1477. // If this is the end component and the caller wants the symbolic
  1478. // link specifically, don't follow the link.
  1479. //
  1480. if ((OpenFlags & OPEN_FLAG_SYMBOLIC_LINK) != 0) {
  1481. FollowLink = FALSE;
  1482. }
  1483. }
  1484. //
  1485. // Ensure the caller has permission to search in this directory. It is
  1486. // the caller's responsibility to do the appropriate permission checks
  1487. // on the final path entry.
  1488. //
  1489. if (FromKernelMode == FALSE) {
  1490. Status = IopCheckPermissions(FromKernelMode,
  1491. &Entry,
  1492. IO_ACCESS_EXECUTE);
  1493. if (!KSUCCESS(Status)) {
  1494. goto PathWalkWorkerEnd;
  1495. }
  1496. }
  1497. //
  1498. // This routine takes a reference on a sucessfully returned entry.
  1499. //
  1500. Status = IopPathLookup(FromKernelMode,
  1501. Root,
  1502. &Entry,
  1503. FALSE,
  1504. CurrentPath,
  1505. ComponentSize + 1,
  1506. ThisIterationOpenFlags,
  1507. ThisOverride,
  1508. OverrideParameter,
  1509. CreatePermissions,
  1510. &NextEntry);
  1511. if (!KSUCCESS(Status)) {
  1512. if (NextEntry.PathEntry != NULL) {
  1513. IO_PATH_POINT_RELEASE_REFERENCE(&NextEntry);
  1514. }
  1515. goto PathWalkWorkerEnd;
  1516. }
  1517. //
  1518. // If this is a symbolic link and links should be followed this
  1519. // iteration, then follow the link. This is recursive.
  1520. //
  1521. FileObject = NextEntry.PathEntry->FileObject;
  1522. if (FollowLink != FALSE) {
  1523. if (FileObject->Properties.Type == IoObjectSymbolicLink) {
  1524. //
  1525. // If this is the last component and the caller doesn't want
  1526. // symbolic links, fail. Symbolic links in inner components
  1527. // of the path are still followed. Also stop if too many
  1528. // symbolic links were traversed.
  1529. //
  1530. if ((RecursionLevel > MAX_SYMBOLIC_LINK_RECURSION) ||
  1531. ((NextSeparator == NULL) &&
  1532. ((OpenFlags & OPEN_FLAG_NO_SYMBOLIC_LINK) != 0))) {
  1533. IO_PATH_POINT_RELEASE_REFERENCE(&NextEntry);
  1534. Status = STATUS_SYMBOLIC_LINK_LOOP;
  1535. goto PathWalkWorkerEnd;
  1536. }
  1537. Status = IopFollowSymbolicLink(FromKernelMode,
  1538. ThisIterationOpenFlags,
  1539. RecursionLevel,
  1540. &Entry,
  1541. &NextEntry,
  1542. &LinkEntry);
  1543. IO_PATH_POINT_RELEASE_REFERENCE(&NextEntry);
  1544. IO_COPY_PATH_POINT(&NextEntry, &LinkEntry);
  1545. if (!KSUCCESS(Status)) {
  1546. ASSERT(NextEntry.PathEntry == NULL);
  1547. goto PathWalkWorkerEnd;
  1548. }
  1549. //
  1550. // Count a symbolic link traversal as "recursion" even though
  1551. // in this case it's not recursive in a function call sense.
  1552. // This protects against runaway paths with symbolic links that
  1553. // loop back up the path tree (ie to ".", "..", etc).
  1554. //
  1555. RecursionLevel += 1;
  1556. FileObject = NextEntry.PathEntry->FileObject;
  1557. }
  1558. }
  1559. //
  1560. // Move on to the next entry and release the reference on this entry.
  1561. //
  1562. IO_PATH_POINT_RELEASE_REFERENCE(&Entry);
  1563. IO_COPY_PATH_POINT(&Entry, &NextEntry);
  1564. //
  1565. // Watch out for the end.
  1566. //
  1567. CurrentPath += ComponentSize;
  1568. CurrentPathSize -= ComponentSize;
  1569. if (NextSeparator == NULL) {
  1570. break;
  1571. }
  1572. //
  1573. // This new thing needs to be a directory as there are more components
  1574. // to traverse (or a least a trailing slash, which should be treated
  1575. // the same way).
  1576. //
  1577. if ((FileObject->Properties.Type != IoObjectRegularDirectory) &&
  1578. (FileObject->Properties.Type != IoObjectObjectDirectory)) {
  1579. Status = STATUS_NOT_A_DIRECTORY;
  1580. goto PathWalkWorkerEnd;
  1581. }
  1582. }
  1583. Status = STATUS_SUCCESS;
  1584. PathWalkWorkerEnd:
  1585. IO_PATH_POINT_RELEASE_REFERENCE(Root);
  1586. if (!KSUCCESS(Status)) {
  1587. if (Entry.PathEntry != NULL) {
  1588. IO_PATH_POINT_RELEASE_REFERENCE(&Entry);
  1589. Entry.PathEntry = NULL;
  1590. }
  1591. }
  1592. if (Entry.PathEntry != NULL) {
  1593. IO_COPY_PATH_POINT(Result, &Entry);
  1594. }
  1595. *Path = CurrentPath;
  1596. *PathSize = CurrentPathSize + 1;
  1597. return Status;
  1598. }
  1599. KSTATUS
  1600. IopPathLookupThroughFileSystem (
  1601. BOOL FromKernelMode,
  1602. PPATH_POINT Directory,
  1603. PSTR Name,
  1604. ULONG NameSize,
  1605. ULONG Hash,
  1606. ULONG OpenFlags,
  1607. IO_OBJECT_TYPE TypeOverride,
  1608. PVOID OverrideParameter,
  1609. FILE_PERMISSIONS CreatePermissions,
  1610. PPATH_POINT Result
  1611. )
  1612. /*++
  1613. Routine Description:
  1614. This routine attempts to look up a child with the given name in a
  1615. directory by asking the file system. This routine assumes that the parent
  1616. directory's I/O lock is already held.
  1617. Arguments:
  1618. FromKernelMode - Supplies a boolean indicating whether or not the request
  1619. originated from kernel mode (TRUE) or user mode (FALSE).
  1620. Directory - Supplies a pointer to the path point to search.
  1621. Name - Supplies a pointer to the name string.
  1622. NameSize - Supplies a pointer to the size of the string in bytes
  1623. including an assumed null terminator.
  1624. Hash - Supplies the hash of the name string.
  1625. OpenFlags - Supplies a bitfield of flags governing the behavior of the
  1626. handle. See OPEN_FLAG_* definitions.
  1627. TypeOverride - Supplies the type of object to create. If this is invalid,
  1628. then this routine will try to open an existing object. If this type is
  1629. valid, then this routine will attempt to create an object of the given
  1630. type.
  1631. OverrideParameter - Supplies an optional parameter to send along with the
  1632. override type.
  1633. CreatePermissions - Supplies the permissions to assign to a created file.
  1634. Result - Supplies a pointer to a path point that receives the resulting
  1635. path entry and mount point on success. The path entry and mount point
  1636. will come with an extra reference on them, so the caller must be sure
  1637. to release the references when finished. A path point may be returned
  1638. even on failing status codes (such as a negative path entry).
  1639. Return Value:
  1640. Status code.
  1641. --*/
  1642. {
  1643. POBJECT_HEADER Child;
  1644. BOOL Created;
  1645. PDEVICE DirectoryDevice;
  1646. PPATH_ENTRY DirectoryEntry;
  1647. PFILE_OBJECT DirectoryFileObject;
  1648. BOOL DoNotCache;
  1649. PFILE_OBJECT FileObject;
  1650. ULONG FileObjectFlags;
  1651. BOOL FoundPathPoint;
  1652. BOOL Negative;
  1653. POBJECT_HEADER Object;
  1654. PPATH_ENTRY PathEntry;
  1655. PDEVICE PathRoot;
  1656. FILE_PROPERTIES Properties;
  1657. ULONG RootLookupFlags;
  1658. KSTATUS Status;
  1659. PKTHREAD Thread;
  1660. BOOL Unlinked;
  1661. Child = NULL;
  1662. Created = FALSE;
  1663. DirectoryEntry = Directory->PathEntry;
  1664. DoNotCache = FALSE;
  1665. FileObject = NULL;
  1666. Negative = FALSE;
  1667. PathEntry = NULL;
  1668. PathRoot = DirectoryEntry->FileObject->Device;
  1669. //
  1670. // This had better be a directory of some kind.
  1671. //
  1672. DirectoryFileObject = DirectoryEntry->FileObject;
  1673. ASSERT((DirectoryFileObject->Properties.Type == IoObjectObjectDirectory) ||
  1674. (DirectoryFileObject->Properties.Type == IoObjectRegularDirectory));
  1675. //
  1676. // The directory's I/O lock should be held exclusively.
  1677. //
  1678. ASSERT(KeIsSharedExclusiveLockHeldExclusive(DirectoryFileObject->Lock));
  1679. //
  1680. // If the hard link count on this directory has dropped since the caller
  1681. // got a reference, then just exit.
  1682. //
  1683. if (DirectoryFileObject->Properties.HardLinkCount == 0) {
  1684. Status = STATUS_PATH_NOT_FOUND;
  1685. goto PathLookupThroughFileSystemEnd;
  1686. }
  1687. //
  1688. // With the directory lock held exclusively, double check to make sure
  1689. // something else didn't already create this path entry.
  1690. //
  1691. FoundPathPoint = IopFindPathPoint(Directory,
  1692. OpenFlags,
  1693. Name,
  1694. NameSize,
  1695. Hash,
  1696. Result);
  1697. if (FoundPathPoint != FALSE) {
  1698. //
  1699. // If negative path entry was found, fail unless it's a create
  1700. // operation.
  1701. //
  1702. if (Result->PathEntry->Negative != FALSE) {
  1703. if (TypeOverride == IoObjectInvalid) {
  1704. Status = STATUS_PATH_NOT_FOUND;
  1705. goto PathLookupThroughFileSystemEnd;
  1706. }
  1707. //
  1708. // A real path entry was found. Return the path point.
  1709. //
  1710. } else {
  1711. if ((TypeOverride != IoObjectInvalid) &&
  1712. ((OpenFlags & OPEN_FLAG_FAIL_IF_EXISTS) != 0)) {
  1713. Status = STATUS_FILE_EXISTS;
  1714. } else {
  1715. Status = STATUS_SUCCESS;
  1716. }
  1717. goto PathLookupThroughFileSystemEnd;
  1718. }
  1719. }
  1720. //
  1721. // Call out to the driver if the root is managed by it.
  1722. //
  1723. if (IS_DEVICE_OR_VOLUME(PathRoot)) {
  1724. if (TypeOverride != IoObjectInvalid) {
  1725. //
  1726. // Check to make sure the caller has permission to create objects
  1727. // in this directory.
  1728. //
  1729. if (FromKernelMode == FALSE) {
  1730. Status = IopCheckPermissions(FromKernelMode,
  1731. Directory,
  1732. IO_ACCESS_WRITE);
  1733. if (!KSUCCESS(Status)) {
  1734. goto PathLookupThroughFileSystemEnd;
  1735. }
  1736. }
  1737. //
  1738. // Send the create IRP. Set the file owner to the effective user ID
  1739. // of the caller. If the sticky bit is set in the directory, set
  1740. // the owning group to that of the directory.
  1741. //
  1742. //
  1743. // TODO: This should assert that FromKernelMode is FALSE,
  1744. // because it's not obvious what user/group ID to put as the owner
  1745. // if the creation comes from kernel mode. Current the assert
  1746. // cannot be put in because creation of shared memory objects
  1747. // happens from kernel mode. Fix shared memory objects to do
  1748. // "from user mode" path walks, and then re-add this assert.
  1749. //
  1750. Thread = KeGetCurrentThread();
  1751. RtlZeroMemory(&Properties, sizeof(FILE_PROPERTIES));
  1752. Properties.DeviceId = PathRoot->DeviceId;
  1753. Properties.Type = TypeOverride;
  1754. Properties.UserId = Thread->Identity.EffectiveUserId;
  1755. Properties.GroupId = Thread->Identity.EffectiveGroupId;
  1756. if ((DirectoryFileObject->Properties.Permissions &
  1757. FILE_PERMISSION_SET_GROUP_ID) != 0) {
  1758. Properties.GroupId = DirectoryFileObject->Properties.GroupId;
  1759. }
  1760. Properties.Permissions = CreatePermissions & FILE_PERMISSION_MASK;
  1761. Properties.HardLinkCount = 1;
  1762. KeGetSystemTime(&(Properties.AccessTime));
  1763. Properties.ModifiedTime = Properties.AccessTime;
  1764. Properties.StatusChangeTime = Properties.AccessTime;
  1765. Status = IopSendCreateRequest(PathRoot,
  1766. DirectoryFileObject,
  1767. Name,
  1768. NameSize,
  1769. &Properties);
  1770. //
  1771. // If the create request worked, create a file object for it. If
  1772. // this results in a create, then the reference on the path root is
  1773. // passed to the file object. If this just results in a lookup,
  1774. // then the path root needs to be released. This is handled below
  1775. // when the create is evaluated.
  1776. //
  1777. if (KSUCCESS(Status)) {
  1778. ASSERT(Properties.DeviceId == PathRoot->DeviceId);
  1779. FileObjectFlags = 0;
  1780. if ((OpenFlags & OPEN_FLAG_NON_CACHED) != 0) {
  1781. FileObjectFlags |= FILE_OBJECT_FLAG_NON_CACHED;
  1782. }
  1783. switch (Properties.Type) {
  1784. case IoObjectRegularFile:
  1785. case IoObjectRegularDirectory:
  1786. case IoObjectObjectDirectory:
  1787. case IoObjectSymbolicLink:
  1788. case IoObjectSharedMemoryObject:
  1789. case IoObjectSocket:
  1790. FileObjectFlags |= FILE_OBJECT_FLAG_EXTERNAL_IO_STATE;
  1791. break;
  1792. default:
  1793. break;
  1794. }
  1795. Status = IopCreateOrLookupFileObject(&Properties,
  1796. PathRoot,
  1797. FileObjectFlags,
  1798. &FileObject,
  1799. &Created);
  1800. if (!KSUCCESS(Status)) {
  1801. goto PathLookupThroughFileSystemEnd;
  1802. }
  1803. ASSERT(Created != FALSE);
  1804. //
  1805. // If requested, unlink the file now that it has been created
  1806. // and the necessary data recorded. If the unlink fails, leave
  1807. // the file in the file system, but fail the create call.
  1808. //
  1809. if ((OpenFlags & OPEN_FLAG_UNLINK_ON_CREATE) != 0) {
  1810. Status = IopSendUnlinkRequest(PathRoot,
  1811. FileObject,
  1812. DirectoryFileObject,
  1813. Name,
  1814. NameSize,
  1815. &Unlinked);
  1816. if (Unlinked == FALSE) {
  1817. ASSERT(FALSE);
  1818. Status = STATUS_FILE_EXISTS;
  1819. }
  1820. if (!KSUCCESS(Status)) {
  1821. goto PathLookupThroughFileSystemEnd;
  1822. }
  1823. }
  1824. //
  1825. // The creation request didn't work. It can only turn into an open
  1826. // request if it's a regular file. The path root is no longer
  1827. // needed, so release the reference.
  1828. //
  1829. } else {
  1830. if ((Status == STATUS_FILE_EXISTS) &&
  1831. (TypeOverride == IoObjectRegularFile) &&
  1832. ((OpenFlags & OPEN_FLAG_FAIL_IF_EXISTS) == 0)) {
  1833. TypeOverride = IoObjectInvalid;
  1834. } else {
  1835. goto PathLookupThroughFileSystemEnd;
  1836. }
  1837. }
  1838. }
  1839. //
  1840. // No override, open an existing file.
  1841. //
  1842. if (TypeOverride == IoObjectInvalid) {
  1843. DirectoryDevice = DirectoryFileObject->Device;
  1844. ASSERT(IS_DEVICE_OR_VOLUME(DirectoryDevice));
  1845. Status = IopSendLookupRequest(DirectoryDevice,
  1846. DirectoryFileObject,
  1847. Name,
  1848. NameSize,
  1849. &Properties);
  1850. if (!KSUCCESS(Status)) {
  1851. if (Status == STATUS_PATH_NOT_FOUND) {
  1852. Negative = TRUE;
  1853. } else {
  1854. goto PathLookupThroughFileSystemEnd;
  1855. }
  1856. //
  1857. // Successful lookup, create or look up a file object.
  1858. //
  1859. } else {
  1860. Properties.DeviceId = DirectoryFileObject->Properties.DeviceId;
  1861. FileObjectFlags = 0;
  1862. if ((OpenFlags & OPEN_FLAG_NON_CACHED) != 0) {
  1863. FileObjectFlags |= FILE_OBJECT_FLAG_NON_CACHED;
  1864. }
  1865. switch (Properties.Type) {
  1866. case IoObjectRegularFile:
  1867. case IoObjectRegularDirectory:
  1868. case IoObjectObjectDirectory:
  1869. case IoObjectSymbolicLink:
  1870. case IoObjectSharedMemoryObject:
  1871. case IoObjectSocket:
  1872. FileObjectFlags |= FILE_OBJECT_FLAG_EXTERNAL_IO_STATE;
  1873. break;
  1874. default:
  1875. break;
  1876. }
  1877. //
  1878. // Create a file object. If this results in a create, then the
  1879. // reference on the path root is passed to the file object. If
  1880. // this just results in a lookup, then the path root needs to be
  1881. // released. This is handled below when the create is evaluated.
  1882. //
  1883. Status = IopCreateOrLookupFileObject(&Properties,
  1884. DirectoryDevice,
  1885. FileObjectFlags,
  1886. &FileObject,
  1887. &Created);
  1888. if (!KSUCCESS(Status)) {
  1889. goto PathLookupThroughFileSystemEnd;
  1890. }
  1891. }
  1892. }
  1893. //
  1894. // An existing object was found. Check to make sure the caching flags
  1895. // match.
  1896. //
  1897. if ((Created == FALSE) && (FileObject != NULL)) {
  1898. if (((OpenFlags & OPEN_FLAG_NON_CACHED) != 0) &&
  1899. (IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE)) {
  1900. Status = STATUS_RESOURCE_IN_USE;
  1901. goto PathLookupThroughFileSystemEnd;
  1902. }
  1903. }
  1904. //
  1905. // The object manager handles this node.
  1906. //
  1907. } else {
  1908. //
  1909. // The file ID is actually a direct pointer to the object.
  1910. //
  1911. Object = (POBJECT_HEADER)(UINTN)DirectoryFileObject->Properties.FileId;
  1912. //
  1913. // Creates within the object manager are allowed only in very
  1914. // restricted situations.
  1915. //
  1916. if (TypeOverride != IoObjectInvalid) {
  1917. //
  1918. // Pipes are allowed in the pipes directory.
  1919. //
  1920. if ((TypeOverride == IoObjectPipe) &&
  1921. (Object == IopGetPipeDirectory())) {
  1922. Status = IopCreatePipe(Name,
  1923. NameSize,
  1924. CreatePermissions,
  1925. &FileObject);
  1926. if (!KSUCCESS(Status) &&
  1927. ((Status != STATUS_FILE_EXISTS) ||
  1928. ((OpenFlags & OPEN_FLAG_FAIL_IF_EXISTS) != 0))) {
  1929. goto PathLookupThroughFileSystemEnd;
  1930. }
  1931. } else if ((TypeOverride == IoObjectSharedMemoryObject) &&
  1932. (Object == IopGetSharedMemoryObjectDirectory())) {
  1933. Status = IopCreateSharedMemoryObject(Name,
  1934. NameSize,
  1935. OpenFlags,
  1936. CreatePermissions,
  1937. &FileObject);
  1938. if (!KSUCCESS(Status) &&
  1939. ((Status != STATUS_FILE_EXISTS) ||
  1940. ((OpenFlags & OPEN_FLAG_FAIL_IF_EXISTS) != 0))) {
  1941. goto PathLookupThroughFileSystemEnd;
  1942. }
  1943. //
  1944. // Directory creates are not permitted in the object manager system.
  1945. //
  1946. } else if (TypeOverride == IoObjectRegularDirectory) {
  1947. Status = STATUS_ACCESS_DENIED;
  1948. goto PathLookupThroughFileSystemEnd;
  1949. }
  1950. }
  1951. //
  1952. // Attempt to open an existing object with the given name.
  1953. //
  1954. if (FileObject == NULL) {
  1955. //
  1956. // Try to find the child by name. This will take a reference on
  1957. // the child. If the child is a volume or device and it wants to
  1958. // own the path, then the reference will be passed on to the file
  1959. // object. Otherwise, the reference will be transferred to the new
  1960. // properties created below (see comments).
  1961. //
  1962. Child = ObFindObject(Name, NameSize, Object);
  1963. if (Child == NULL) {
  1964. //
  1965. // Creates are generally not permitted in the object manager
  1966. // system.
  1967. //
  1968. if (TypeOverride != IoObjectInvalid) {
  1969. Status = STATUS_ACCESS_DENIED;
  1970. } else {
  1971. Status = STATUS_PATH_NOT_FOUND;
  1972. }
  1973. goto PathLookupThroughFileSystemEnd;
  1974. }
  1975. //
  1976. // Fail the create call if the object exists.
  1977. //
  1978. if ((OpenFlags & OPEN_FLAG_FAIL_IF_EXISTS) != 0) {
  1979. Status = STATUS_FILE_EXISTS;
  1980. goto PathLookupThroughFileSystemEnd;
  1981. }
  1982. //
  1983. // If the child is a device, send it a lookup to see if it wants to
  1984. // own the path.
  1985. //
  1986. Status = STATUS_UNSUCCESSFUL;
  1987. FileObjectFlags = 0;
  1988. if (Child->Type == ObjectDevice) {
  1989. Status = IopSendRootLookupRequest((PDEVICE)Child,
  1990. &Properties,
  1991. &RootLookupFlags);
  1992. if (KSUCCESS(Status)) {
  1993. PathRoot = (PDEVICE)Child;
  1994. Properties.DeviceId = PathRoot->DeviceId;
  1995. if ((RootLookupFlags & LOOKUP_FLAG_NON_CACHED) != 0) {
  1996. FileObjectFlags |= FILE_OBJECT_FLAG_NON_CACHED;
  1997. }
  1998. } else if (Status == STATUS_DEVICE_NOT_CONNECTED) {
  1999. goto PathLookupThroughFileSystemEnd;
  2000. }
  2001. }
  2002. //
  2003. // If the device didn't want it, create a file object for this
  2004. // object. Give the reference added during the find object routine
  2005. // to the file object structure.
  2006. //
  2007. if (!KSUCCESS(Status)) {
  2008. DoNotCache = TRUE;
  2009. IopFillOutFilePropertiesForObject(&Properties, Child);
  2010. //
  2011. // Update the properties to contain the appropriate type.
  2012. //
  2013. switch (Child->Type) {
  2014. case ObjectPipe:
  2015. Properties.Type = IoObjectPipe;
  2016. break;
  2017. case ObjectTerminalMaster:
  2018. Properties.Type = IoObjectTerminalMaster;
  2019. break;
  2020. case ObjectTerminalSlave:
  2021. Properties.Type = IoObjectTerminalSlave;
  2022. break;
  2023. case ObjectSharedMemoryObject:
  2024. Properties.Type = IoObjectSharedMemoryObject;
  2025. break;
  2026. default:
  2027. break;
  2028. }
  2029. //
  2030. // Take a reference on the path root to match the extra
  2031. // reference the child would have, so that the path root can
  2032. // just be dereferenced after creating the file object.
  2033. //
  2034. ASSERT(PathRoot != (PDEVICE)Child);
  2035. ObAddReference(PathRoot);
  2036. //
  2037. // Release the reference taken on the child by the find object
  2038. // routine, the file object took its own.
  2039. //
  2040. ObReleaseReference(Child);
  2041. Child = NULL;
  2042. }
  2043. switch (Properties.Type) {
  2044. case IoObjectRegularFile:
  2045. case IoObjectRegularDirectory:
  2046. case IoObjectObjectDirectory:
  2047. case IoObjectSymbolicLink:
  2048. case IoObjectSharedMemoryObject:
  2049. case IoObjectSocket:
  2050. FileObjectFlags |= FILE_OBJECT_FLAG_EXTERNAL_IO_STATE;
  2051. break;
  2052. default:
  2053. break;
  2054. }
  2055. Status = IopCreateOrLookupFileObject(&Properties,
  2056. PathRoot,
  2057. FileObjectFlags,
  2058. &FileObject,
  2059. &Created);
  2060. ObReleaseReference(PathRoot);
  2061. if (!KSUCCESS(Status)) {
  2062. //
  2063. // For volumes and devices that own the path, this does not
  2064. // execute as the child is not NULL. For other objects, this
  2065. // releases the reference taken on the child when the
  2066. // properties were filled out.
  2067. //
  2068. if (Child == NULL) {
  2069. ObReleaseReference((PVOID)(UINTN)(Properties.FileId));
  2070. }
  2071. Child = NULL;
  2072. goto PathLookupThroughFileSystemEnd;
  2073. }
  2074. //
  2075. // If an existing file object was found, then the references in
  2076. // the properties need to be released.
  2077. //
  2078. if (Created == FALSE) {
  2079. //
  2080. // The previous root lookup should have resulted in the same
  2081. // set of file object flags.
  2082. //
  2083. ASSERT((FileObject->Flags & FileObjectFlags) ==
  2084. FileObjectFlags);
  2085. //
  2086. // For volumes and devices that own the path, this does not
  2087. // execute as the child is not NULL. For other objects, this
  2088. // releases the reference taken on the child when the
  2089. // properties were filled out.
  2090. //
  2091. if (Child == NULL) {
  2092. ObReleaseReference((PVOID)(UINTN)(Properties.FileId));
  2093. }
  2094. }
  2095. Child = NULL;
  2096. }
  2097. }
  2098. //
  2099. // If it's a special type of object potentially create the special sauce
  2100. // for it. Note that with hard links several threads may be doing this at
  2101. // once, but the file object ready event should provide the needed
  2102. // synchronization.
  2103. //
  2104. if (FileObject != NULL) {
  2105. switch (FileObject->Properties.Type) {
  2106. case IoObjectPipe:
  2107. case IoObjectSocket:
  2108. case IoObjectTerminalMaster:
  2109. case IoObjectTerminalSlave:
  2110. case IoObjectSharedMemoryObject:
  2111. if (FileObject->SpecialIo == NULL) {
  2112. Status = IopCreateSpecialIoObject(OpenFlags,
  2113. FileObject->Properties.Type,
  2114. OverrideParameter,
  2115. CreatePermissions,
  2116. &FileObject);
  2117. if (!KSUCCESS(Status)) {
  2118. goto PathLookupThroughFileSystemEnd;
  2119. }
  2120. }
  2121. break;
  2122. default:
  2123. break;
  2124. }
  2125. }
  2126. //
  2127. // If a path point was already found, it's a negative one. Convert it.
  2128. //
  2129. if (FoundPathPoint != FALSE) {
  2130. ASSERT(Negative == FALSE);
  2131. ASSERT((Result->PathEntry->Negative != FALSE) &&
  2132. (Result->PathEntry->FileObject == NULL) &&
  2133. (FileObject->Device == PathRoot) &&
  2134. (Result->MountPoint == Directory->MountPoint));
  2135. Result->PathEntry->Negative = FALSE;
  2136. Result->PathEntry->DoNotCache = DoNotCache;
  2137. ASSERT(FileObject != NULL);
  2138. ASSERT(FileObject->ReferenceCount >= 2);
  2139. Result->PathEntry->FileObject = FileObject;
  2140. IopFileObjectAddPathEntryReference(Result->PathEntry->FileObject);
  2141. if ((OpenFlags & OPEN_FLAG_UNLINK_ON_CREATE) != 0) {
  2142. if (Result->PathEntry->SiblingListEntry.Next != NULL) {
  2143. LIST_REMOVE(&(Result->PathEntry->SiblingListEntry));
  2144. Result->PathEntry->SiblingListEntry.Next = NULL;
  2145. }
  2146. }
  2147. //
  2148. // Create and insert a new path entry.
  2149. //
  2150. } else {
  2151. PathEntry = IopCreatePathEntry(Name,
  2152. NameSize,
  2153. Hash,
  2154. DirectoryEntry,
  2155. FileObject);
  2156. if (PathEntry == NULL) {
  2157. Status = STATUS_INSUFFICIENT_RESOURCES;
  2158. goto PathLookupThroughFileSystemEnd;
  2159. }
  2160. ASSERT((Negative == FALSE) || (FileObject == NULL));
  2161. PathEntry->Negative = Negative;
  2162. PathEntry->DoNotCache = DoNotCache;
  2163. //
  2164. // Unless this routine unlinked the file as soon as it was created,
  2165. // there should be at least one hard link count and it needs to get
  2166. // inserted into the directory's list of children.
  2167. //
  2168. if ((OpenFlags & OPEN_FLAG_UNLINK_ON_CREATE) == 0) {
  2169. ASSERT((FileObject == NULL) ||
  2170. (FileObject->Properties.HardLinkCount != 0));
  2171. INSERT_BEFORE(&(PathEntry->SiblingListEntry),
  2172. &(DirectoryEntry->ChildList));
  2173. }
  2174. Result->PathEntry = PathEntry;
  2175. IoMountPointAddReference(Directory->MountPoint);
  2176. Result->MountPoint = Directory->MountPoint;
  2177. }
  2178. FileObject = NULL;
  2179. Status = STATUS_SUCCESS;
  2180. //
  2181. // If this was actually a negative path entry, return path not found.
  2182. //
  2183. if (Negative != FALSE) {
  2184. Status = STATUS_PATH_NOT_FOUND;
  2185. }
  2186. PathLookupThroughFileSystemEnd:
  2187. if (Child != NULL) {
  2188. ObReleaseReference(Child);
  2189. }
  2190. if (FileObject != NULL) {
  2191. IopFileObjectReleaseReference(FileObject);
  2192. }
  2193. return Status;
  2194. }
  2195. KSTATUS
  2196. IopFollowSymbolicLink (
  2197. BOOL FromKernelMode,
  2198. ULONG OpenFlags,
  2199. ULONG RecursionLevel,
  2200. PPATH_POINT Directory,
  2201. PPATH_POINT SymbolicLink,
  2202. PPATH_POINT Result
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. This routine attempts to follow the destination of a symbolic link.
  2207. Arguments:
  2208. FromKernelMode - Supplies a boolean indicating whether or not this request
  2209. is coming directly from kernel mode (and should use the kernel's root).
  2210. OpenFlags - Supplies a bitfield of flags governing the behavior of the
  2211. handle. See OPEN_FLAG_* definitions.
  2212. RecursionLevel - Supplies the level of recursion reached for this path
  2213. resolution. If this is greater than the maximum supported, then a
  2214. failing loop status is returned.
  2215. Directory - Supplies the path point of the directory containing the
  2216. symbolic link.
  2217. SymbolicLink - Supplies the path point to the symbolic link.
  2218. Result - Supplies a pointer to a path point that receives the resulting
  2219. path entry and mount point on success. The path entry and mount point
  2220. will come with an extra reference on them, so the caller must be sure
  2221. to release the references when finished.
  2222. Return Value:
  2223. Status code.
  2224. --*/
  2225. {
  2226. PIO_HANDLE Handle;
  2227. ULONG LinkOpenFlags;
  2228. PSTR LinkTarget;
  2229. ULONG LinkTargetSize;
  2230. PSTR RemainingPath;
  2231. ULONG RemainingPathSize;
  2232. KSTATUS Status;
  2233. Handle = NULL;
  2234. LinkTarget = NULL;
  2235. Result->PathEntry = NULL;
  2236. //
  2237. // The buck stops here with infinite recursion.
  2238. //
  2239. if (RecursionLevel >= MAX_SYMBOLIC_LINK_RECURSION) {
  2240. Status = STATUS_SYMBOLIC_LINK_LOOP;
  2241. goto FollowSymbolicLinkEnd;
  2242. }
  2243. LinkOpenFlags = OPEN_FLAG_NO_ACCESS_TIME | OPEN_FLAG_SYMBOLIC_LINK;
  2244. Status = IopOpenPathPoint(SymbolicLink,
  2245. IO_ACCESS_READ,
  2246. LinkOpenFlags,
  2247. &Handle);
  2248. if (!KSUCCESS(Status)) {
  2249. goto FollowSymbolicLinkEnd;
  2250. }
  2251. Status = IoReadSymbolicLink(Handle,
  2252. PATH_ALLOCATION_TAG,
  2253. &LinkTarget,
  2254. &LinkTargetSize);
  2255. if (!KSUCCESS(Status)) {
  2256. goto FollowSymbolicLinkEnd;
  2257. }
  2258. RemainingPath = LinkTarget;
  2259. RemainingPathSize = LinkTargetSize;
  2260. //
  2261. // Perform a path walk starting at the directory where the symlink was
  2262. // found. This gets reset if the symlink destination starts with a slash.
  2263. //
  2264. Status = IopPathWalkWorker(FromKernelMode,
  2265. Directory,
  2266. &RemainingPath,
  2267. &RemainingPathSize,
  2268. OpenFlags,
  2269. IoObjectInvalid,
  2270. NULL,
  2271. FILE_PERMISSION_NONE,
  2272. RecursionLevel + 1,
  2273. Result);
  2274. if (!KSUCCESS(Status)) {
  2275. goto FollowSymbolicLinkEnd;
  2276. }
  2277. FollowSymbolicLinkEnd:
  2278. if (Handle != NULL) {
  2279. IoClose(Handle);
  2280. }
  2281. if (LinkTarget != NULL) {
  2282. MmFreePagedPool(LinkTarget);
  2283. }
  2284. return Status;
  2285. }
  2286. ULONG
  2287. IopHashPathString (
  2288. PSTR String,
  2289. ULONG StringSize
  2290. )
  2291. /*++
  2292. Routine Description:
  2293. This routine generates the hash associated with a path name. This hash is
  2294. used to speed up comparisons.
  2295. Arguments:
  2296. String - Supplies a pointer to the string to hash.
  2297. StringSize - Supplies the size of the string, including the null terminator.
  2298. Return Value:
  2299. Returns the hash of the given string.
  2300. --*/
  2301. {
  2302. ASSERT(StringSize != 0);
  2303. return RtlComputeCrc32(0, String, StringSize - 1);
  2304. }
  2305. BOOL
  2306. IopArePathsEqual (
  2307. PSTR ExistingPath,
  2308. PSTR QueryPath,
  2309. ULONG QuerySize
  2310. )
  2311. /*++
  2312. Routine Description:
  2313. This routine compares two path components.
  2314. Arguments:
  2315. ExistingPath - Supplies a pointer to the existing null terminated path
  2316. string.
  2317. QueryPath - Supplies a pointer the query string, which may not be null
  2318. terminated.
  2319. QuerySize - Supplies the size of the string including the assumed
  2320. null terminator that is never checked.
  2321. Return Value:
  2322. TRUE if the paths are equals.
  2323. FALSE if the paths differ in some way.
  2324. --*/
  2325. {
  2326. ASSERT(QuerySize != 0);
  2327. if (RtlAreStringsEqual(ExistingPath, QueryPath, QuerySize - 1) == FALSE) {
  2328. return FALSE;
  2329. }
  2330. if (ExistingPath[QuerySize - 1] != STRING_TERMINATOR) {
  2331. return FALSE;
  2332. }
  2333. return TRUE;
  2334. }
  2335. BOOL
  2336. IopFindPathPoint (
  2337. PPATH_POINT Parent,
  2338. ULONG OpenFlags,
  2339. PSTR Name,
  2340. ULONG NameSize,
  2341. ULONG Hash,
  2342. PPATH_POINT Result
  2343. )
  2344. /*++
  2345. Routine Description:
  2346. This routine loops through the given path point's child path entries
  2347. looking for a child with the given name. It follows any mount points it
  2348. encounters unless the open flags specify otherwise. This routine assumes
  2349. the parent's file object lock is held.
  2350. Arguments:
  2351. Parent - Supplies a pointer to the parent path point whose children should
  2352. be searched. The parent's file object lock should already be held.
  2353. OpenFlags - Supplies a bitfield of flags governing the behavior of the
  2354. search. See OPEN_FLAG_* definitions.
  2355. Name - Supplies a pointer the query string, which may not be null
  2356. terminated.
  2357. NameSize - Supplies the size of the string including the assumed null
  2358. terminator that is never checked.
  2359. Hash - Supplies the hash of the name query string.
  2360. Result - Supplies a pointer to a path point that receives the found path
  2361. entry and associated mount point on success. References are taken on
  2362. both elements if found.
  2363. Return Value:
  2364. Returns TRUE if a matching path point was found, or FALSE otherwise.
  2365. --*/
  2366. {
  2367. PLIST_ENTRY CurrentEntry;
  2368. PPATH_ENTRY Entry;
  2369. PMOUNT_POINT FoundMountPoint;
  2370. PPATH_ENTRY FoundPathEntry;
  2371. PFILE_OBJECT ParentFileObject;
  2372. BOOL ResultValid;
  2373. ResultValid = FALSE;
  2374. ParentFileObject = Parent->PathEntry->FileObject;
  2375. ASSERT(NameSize != 0);
  2376. ASSERT(KeIsSharedExclusiveLockHeld(ParentFileObject->Lock) != FALSE);
  2377. //
  2378. // Cruise through the cached list looking for this entry.
  2379. //
  2380. CurrentEntry = Parent->PathEntry->ChildList.Next;
  2381. while (CurrentEntry != &(Parent->PathEntry->ChildList)) {
  2382. Entry = LIST_VALUE(CurrentEntry, PATH_ENTRY, SiblingListEntry);
  2383. CurrentEntry = CurrentEntry->Next;
  2384. //
  2385. // Quickly skip entries without a name or with the wrong hash.
  2386. //
  2387. if ((Entry->Hash != Hash) || (Entry->Name == NULL)) {
  2388. continue;
  2389. }
  2390. //
  2391. // If the names are not equal, this isn't the winner.
  2392. //
  2393. if (IopArePathsEqual(Entry->Name, Name, NameSize) == FALSE) {
  2394. continue;
  2395. }
  2396. //
  2397. // If the found entry is a mount point, then the parent mount point's
  2398. // children are searched for a matching mount point. Note that this
  2399. // search may fail as the path entry is not necessarily a mount point
  2400. // under the current mount tree. It takes a reference on success. Skip
  2401. // this if the open flags dictate that the final mount point should not
  2402. // be followed.
  2403. //
  2404. FoundMountPoint = NULL;
  2405. if ((Entry->MountCount != 0) &&
  2406. ((OpenFlags & OPEN_FLAG_NO_MOUNT_POINT) == 0)) {
  2407. FoundMountPoint = IopFindMountPoint(Parent->MountPoint, Entry);
  2408. if (FoundMountPoint != NULL) {
  2409. FoundPathEntry = FoundMountPoint->TargetEntry;
  2410. }
  2411. }
  2412. //
  2413. // Use the found entry and the same mount point as the parent if the
  2414. // entry was found to not be a mount point.
  2415. //
  2416. if (FoundMountPoint == NULL) {
  2417. FoundPathEntry = Entry;
  2418. FoundMountPoint = Parent->MountPoint;
  2419. IoMountPointAddReference(FoundMountPoint);
  2420. }
  2421. IoPathEntryAddReference(FoundPathEntry);
  2422. Result->PathEntry = FoundPathEntry;
  2423. Result->MountPoint = FoundMountPoint;
  2424. ResultValid = TRUE;
  2425. break;
  2426. }
  2427. return ResultValid;
  2428. }
  2429. VOID
  2430. IopPathEntryReleaseReference (
  2431. PPATH_ENTRY Entry,
  2432. BOOL EnforceCacheSize,
  2433. BOOL Destroy
  2434. )
  2435. /*++
  2436. Routine Description:
  2437. This routine decrements the reference count of the given path entry.
  2438. Arguments:
  2439. Entry - Supplies a pointer to the path entry.
  2440. EnforceCacheSize - Supplies a boolean indicating whether or not to destroy
  2441. extra path entries if the cache is too large. This is used to prevent
  2442. recursion of releasing references.
  2443. Destroy - Supplies a boolean indicating this path entry should be destroyed
  2444. regardless of the path entry cache. It is used by the path entry cache
  2445. to clean out entries.
  2446. Return Value:
  2447. None.
  2448. --*/
  2449. {
  2450. UINTN CacheTarget;
  2451. PLIST_ENTRY CurrentEntry;
  2452. PPATH_ENTRY DestroyEntry;
  2453. LIST_ENTRY DestroyList;
  2454. BOOL Inserted;
  2455. PPATH_ENTRY NextEntry;
  2456. PFILE_OBJECT NextFileObject;
  2457. ULONG OldReferenceCount;
  2458. PPATH_ENTRY Parent;
  2459. ASSERT(KeGetRunLevel() == RunLevelLow);
  2460. Inserted = FALSE;
  2461. NextFileObject = NULL;
  2462. while (Entry != NULL) {
  2463. //
  2464. // Acquire the parent's lock to avoid a situation where this routine
  2465. // decrements the reference count to zero, but before removing it
  2466. // someone else increments, decrements, removes and frees the object.
  2467. //
  2468. NextEntry = Entry->Parent;
  2469. if (NextEntry != NULL) {
  2470. NextFileObject = NextEntry->FileObject;
  2471. KeAcquireSharedExclusiveLockExclusive(NextFileObject->Lock);
  2472. }
  2473. OldReferenceCount = RtlAtomicAdd32(&(Entry->ReferenceCount), -1);
  2474. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  2475. if (OldReferenceCount == 1) {
  2476. //
  2477. // Look to see if this entry should stick around on the path entry
  2478. // cache list, unless it's being forcefully destroyed. Also skip
  2479. // caching if the path entry has been marked for unmount.
  2480. //
  2481. if ((Destroy == FALSE) &&
  2482. (Entry->DoNotCache == FALSE)) {
  2483. //
  2484. // Stick this on the LRU list. Don't cache anonymous path
  2485. // entries (like those created for pipes and sockets) and don't
  2486. // cache unlinked entries.
  2487. //
  2488. if ((Entry->SiblingListEntry.Next != NULL) &&
  2489. (NextEntry != NULL)) {
  2490. ASSERT(Entry->CacheListEntry.Next == NULL);
  2491. KeAcquireQueuedLock(IoPathEntryListLock);
  2492. INSERT_BEFORE(&(Entry->CacheListEntry), &IoPathEntryList);
  2493. IoPathEntryListSize += 1;
  2494. KeReleaseQueuedLock(IoPathEntryListLock);
  2495. Inserted = TRUE;
  2496. }
  2497. }
  2498. //
  2499. // Don't destroy the entry if it's in the cache.
  2500. //
  2501. if (Inserted != FALSE) {
  2502. ASSERT((Destroy == FALSE) && (Entry->DoNotCache == FALSE));
  2503. KeReleaseSharedExclusiveLockExclusive(NextFileObject->Lock);
  2504. break;
  2505. }
  2506. //
  2507. // Destroy the object, then loop back up to release the
  2508. // reference on the parent.
  2509. //
  2510. Parent = IopDestroyPathEntry(Entry);
  2511. ASSERT(Parent == NextEntry);
  2512. //
  2513. // The file object lock was released by the destory path entry
  2514. // routine.
  2515. //
  2516. Entry = NextEntry;
  2517. } else {
  2518. if (NextEntry != NULL) {
  2519. KeReleaseSharedExclusiveLockExclusive(NextFileObject->Lock);
  2520. }
  2521. Entry = NULL;
  2522. }
  2523. }
  2524. //
  2525. // If an entry was inserted in the cache and the cache size is to be
  2526. // enforced, iterate over the cache, pulling off any inactive path entries.
  2527. // This is not done above where the path entry list lock is acquired in
  2528. // order to release the parent's file object lock first. It is held in
  2529. // exclusive mode above.
  2530. //
  2531. if ((EnforceCacheSize != FALSE) && (Inserted != FALSE)) {
  2532. INITIALIZE_LIST_HEAD(&DestroyList);
  2533. KeAcquireQueuedLock(IoPathEntryListLock);
  2534. CacheTarget = IopGetPathEntryCacheTargetSize();
  2535. CurrentEntry = IoPathEntryList.Next;
  2536. while ((IoPathEntryListSize > CacheTarget) &&
  2537. (CurrentEntry != &IoPathEntryList)) {
  2538. DestroyEntry = LIST_VALUE(CurrentEntry, PATH_ENTRY, CacheListEntry);
  2539. CurrentEntry = CurrentEntry->Next;
  2540. //
  2541. // Add a reference to prevent others from manipulating the cache
  2542. // list entry (which they would do if the reference count went up
  2543. // to 1 and back down to 0).
  2544. //
  2545. OldReferenceCount = RtlAtomicAdd32(&(DestroyEntry->ReferenceCount),
  2546. 1);
  2547. //
  2548. // If this was not the first reference on the cached entry, then
  2549. // another thread is working to resurrect it. Don't add it to the
  2550. // list for destruction.
  2551. //
  2552. if (OldReferenceCount != 0) {
  2553. RtlAtomicAdd32(&(DestroyEntry->ReferenceCount), -1);
  2554. } else {
  2555. LIST_REMOVE(&(DestroyEntry->CacheListEntry));
  2556. INSERT_BEFORE(&(DestroyEntry->CacheListEntry), &DestroyList);
  2557. IoPathEntryListSize -= 1;
  2558. }
  2559. }
  2560. KeReleaseQueuedLock(IoPathEntryListLock);
  2561. //
  2562. // Destroy (or at least attempt to destroy) the entries on the destroy
  2563. // list. This doesn't infinitely recurse because the forceful destroy
  2564. // flag is set, circumventing this path.
  2565. //
  2566. CurrentEntry = DestroyList.Next;
  2567. while (CurrentEntry != &DestroyList) {
  2568. DestroyEntry = LIST_VALUE(CurrentEntry, PATH_ENTRY, CacheListEntry);
  2569. CurrentEntry = CurrentEntry->Next;
  2570. ASSERT(DestroyEntry->ReferenceCount >= 1);
  2571. DestroyEntry->CacheListEntry.Next = NULL;
  2572. IopPathEntryReleaseReference(DestroyEntry, FALSE, TRUE);
  2573. }
  2574. }
  2575. return;
  2576. }
  2577. PPATH_ENTRY
  2578. IopDestroyPathEntry (
  2579. PPATH_ENTRY Entry
  2580. )
  2581. /*++
  2582. Routine Description:
  2583. This routine frees the resources associated with the given path entry.
  2584. This entry requires that the parent's file object lock is held exclusive
  2585. upon entry. This routine will release that file object lock.
  2586. Arguments:
  2587. Entry - Supplies a pointer to the path entry to actually destroy.
  2588. Return Value:
  2589. Returns a pointer to the parent path entry whose reference now needs to be
  2590. decremented.
  2591. NULL if the path entry has no parent.
  2592. --*/
  2593. {
  2594. PPATH_ENTRY Parent;
  2595. PFILE_OBJECT ParentFileObject;
  2596. ParentFileObject = NULL;
  2597. //
  2598. // Acquire the parent's lock to avoid a situation where this routine
  2599. // decrements the reference count to zero, but before removing it
  2600. // someone else increments, decrements, removes and frees the object.
  2601. //
  2602. Parent = Entry->Parent;
  2603. if (Parent != NULL) {
  2604. ParentFileObject = Parent->FileObject;
  2605. //
  2606. // The caller should have acquired the parent file object lock
  2607. // exclusive.
  2608. //
  2609. ASSERT(KeIsSharedExclusiveLockHeldExclusive(ParentFileObject->Lock));
  2610. }
  2611. ASSERT(Entry->ReferenceCount == 0);
  2612. //
  2613. // Destroy the object.
  2614. //
  2615. ASSERT(LIST_EMPTY(&(Entry->ChildList)) != FALSE);
  2616. ASSERT(Entry->CacheListEntry.Next == NULL);
  2617. ASSERT(Entry != IoPathPointRoot.PathEntry);
  2618. if (Parent != NULL) {
  2619. //
  2620. // If a path entry is created but never actually added because
  2621. // someone beat it to the punch then it could have a parent
  2622. // but not be on the list. Hence the check for null. This is
  2623. // also necessary when releasing unmounted mount point path
  2624. // entries.
  2625. //
  2626. if (Entry->SiblingListEntry.Next != NULL) {
  2627. LIST_REMOVE(&(Entry->SiblingListEntry));
  2628. Entry->SiblingListEntry.Next = NULL;
  2629. }
  2630. ASSERT(ParentFileObject != NULL);
  2631. KeReleaseSharedExclusiveLockExclusive(ParentFileObject->Lock);
  2632. }
  2633. //
  2634. // By the time a path entry gets destroyed, it should not be mounted
  2635. // anywhere.
  2636. //
  2637. ASSERT(Entry->MountCount == 0);
  2638. //
  2639. // Release the file object and then the path root object. If they exist.
  2640. //
  2641. ASSERT((Entry->Negative != FALSE) || (Entry->FileObject != NULL));
  2642. //
  2643. // Decrement the count of path entries that own the file object.
  2644. //
  2645. if (Entry->Negative == FALSE) {
  2646. IopFileObjectReleasePathEntryReference(Entry->FileObject);
  2647. IopFileObjectReleaseReference(Entry->FileObject);
  2648. }
  2649. MmFreePagedPool(Entry);
  2650. return Parent;
  2651. }
  2652. UINTN
  2653. IopGetPathEntryCacheTargetSize (
  2654. VOID
  2655. )
  2656. /*++
  2657. Routine Description:
  2658. This routine returns the target size of the path entry cache.
  2659. Arguments:
  2660. None.
  2661. Return Value:
  2662. Returns the target size of the path entry cache.
  2663. --*/
  2664. {
  2665. UINTN CurrentSize;
  2666. MEMORY_WARNING_LEVEL WarningLevel;
  2667. WarningLevel = MmGetPhysicalMemoryWarningLevel();
  2668. if (WarningLevel == MemoryWarningLevelNone) {
  2669. return IoPathEntryListMaxSize;
  2670. //
  2671. // At memory warning level one, start shrinking the path entry cache.
  2672. //
  2673. } else if (WarningLevel == MemoryWarningLevel1) {
  2674. CurrentSize = IoPathEntryListSize;
  2675. if (CurrentSize > IoPathEntryListMaxSize) {
  2676. CurrentSize = IoPathEntryListMaxSize;
  2677. }
  2678. if (CurrentSize <= 1) {
  2679. return CurrentSize;
  2680. }
  2681. return CurrentSize - 2;
  2682. }
  2683. //
  2684. // At higher memory warning levels, dump the path entry cache.
  2685. //
  2686. return 0;
  2687. }