mount.c 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. mount.c
  5. Abstract:
  6. This module implements support functionality for mounting and unmounting.
  7. Author:
  8. Chris Stevens 30-Jul-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "iop.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // ------------------------------------------------------ Data Type Definitions
  22. //
  23. //
  24. // ----------------------------------------------- Internal Function Prototypes
  25. //
  26. KSTATUS
  27. IopMount (
  28. BOOL FromKernelMode,
  29. PPATH_POINT Mount,
  30. PPATH_POINT Target,
  31. ULONG Flags
  32. );
  33. KSTATUS
  34. IopUnmount (
  35. PMOUNT_POINT MountPoint,
  36. ULONG Flags
  37. );
  38. BOOL
  39. IopIsMountPointBusy (
  40. PMOUNT_POINT MountPoint,
  41. PMOUNT_POINT OriginalMountPoint,
  42. ULONG Flags
  43. );
  44. PMOUNT_POINT
  45. IopCreateMountPoint (
  46. PPATH_POINT Mount,
  47. PPATH_POINT Target,
  48. PSTR TargetPath,
  49. ULONG TargetPathSize,
  50. ULONG Flags
  51. );
  52. VOID
  53. IopDestroyMountPoint (
  54. PMOUNT_POINT MountPoint
  55. );
  56. KSTATUS
  57. IopCreateAndCopyMountPoint (
  58. PPATH_POINT Mount,
  59. PPATH_POINT Target,
  60. PLIST_ENTRY MountList,
  61. PSTR TargetPath,
  62. ULONG TargetPathSize,
  63. ULONG Flags
  64. );
  65. KSTATUS
  66. IopCopyMountTree (
  67. PMOUNT_POINT NewRoot,
  68. PPATH_POINT Target,
  69. ULONG Flags
  70. );
  71. VOID
  72. IopDestroyMountTree (
  73. PMOUNT_POINT Root,
  74. PLIST_ENTRY DestroyList
  75. );
  76. KSTATUS
  77. IopLinkMountPoint (
  78. PMOUNT_POINT AutoMount,
  79. PPATH_POINT Target,
  80. PLIST_ENTRY MountList
  81. );
  82. VOID
  83. IopDestroyLinkedMountPoints (
  84. PMOUNT_POINT Mount,
  85. PLIST_ENTRY DestroyList
  86. );
  87. KSTATUS
  88. IopGetMountPointsFromTree (
  89. PPATH_POINT ProcessRoot,
  90. PMOUNT_POINT TreeRoot,
  91. PVOID *BufferOffset,
  92. PUINTN BytesRemaining,
  93. PUINTN RequiredSize
  94. );
  95. //
  96. // -------------------------------------------------------------------- Globals
  97. //
  98. PSHARED_EXCLUSIVE_LOCK IoMountLock;
  99. //
  100. // ------------------------------------------------------------------ Functions
  101. //
  102. KSTATUS
  103. IopInitializeMountPointSupport (
  104. VOID
  105. )
  106. /*++
  107. Routine Description:
  108. This routine initializes the support for mount points.
  109. Arguments:
  110. None.
  111. Return Value:
  112. Status code.
  113. --*/
  114. {
  115. PMOUNT_POINT MountPoint;
  116. KSTATUS Status;
  117. ASSERT(IoPathPointRoot.MountPoint == NULL);
  118. ASSERT(IoPathPointRoot.PathEntry != NULL);
  119. IoMountLock = KeCreateSharedExclusiveLock();
  120. if (IoMountLock == NULL) {
  121. Status = STATUS_INSUFFICIENT_RESOURCES;
  122. goto InitializeMountPointsSupportEnd;
  123. }
  124. //
  125. // Use the partially initialized root path point to create the root mount
  126. // point. The root path point's path entry is the "target" of this mount
  127. // point and there is no "mount", as it is the root of all mount points.
  128. //
  129. MountPoint = IopCreateMountPoint(NULL, &IoPathPointRoot, NULL, 0, 0);
  130. if (MountPoint == NULL) {
  131. Status = STATUS_INSUFFICIENT_RESOURCES;
  132. goto InitializeMountPointsSupportEnd;
  133. }
  134. IoPathPointRoot.MountPoint = MountPoint;
  135. Status = STATUS_SUCCESS;
  136. InitializeMountPointsSupportEnd:
  137. if (!KSUCCESS(Status)) {
  138. if (IoMountLock != NULL) {
  139. KeDestroySharedExclusiveLock(IoMountLock);
  140. }
  141. }
  142. return Status;
  143. }
  144. KERNEL_API
  145. KSTATUS
  146. IoMount (
  147. BOOL FromKernelMode,
  148. PSTR MountPointPath,
  149. ULONG MountPointPathSize,
  150. PSTR TargetPath,
  151. ULONG TargetPathSize,
  152. ULONG MountFlags,
  153. ULONG AccessFlags
  154. )
  155. /*++
  156. Routine Description:
  157. This routine attempts to mount the given target on the given mount point.
  158. Arguments:
  159. FromKernelMode - Supplies a boolean indicating the request is coming from
  160. kernel mode.
  161. MountPointPath - Supplies a pointer to the string containing the path to
  162. where the target is to be mounted.
  163. MountPointPathSize - Supplies the size of the mount point path string in
  164. bytes, including the null terminator.
  165. TargetPath - Supplies a pointer to the string containing the path to the
  166. target file, directory, volume, pipe, socket, or device that is to be
  167. mounted.
  168. TargetPathSize - Supplies the size of the target path string in bytes,
  169. including the null terminator.
  170. MountFlags - Supplies the flags associated with the mount operation. See
  171. MOUNT_FLAG_* for definitions.
  172. AccessFlags - Supplies the flags associated with the mount point's access
  173. permissions. See IO_ACCESS_FLAG_* for definitions.
  174. Return Value:
  175. Status code.
  176. --*/
  177. {
  178. PDEVICE Device;
  179. PFILE_OBJECT MountFileObject;
  180. IO_OBJECT_TYPE MountFileType;
  181. PATH_POINT MountPathPoint;
  182. KSTATUS Status;
  183. PFILE_OBJECT TargetFileObject;
  184. PATH_POINT TargetPathPoint;
  185. PVOLUME Volume;
  186. MountPathPoint.PathEntry = NULL;
  187. TargetPathPoint.PathEntry = NULL;
  188. Volume = NULL;
  189. //
  190. // Permission check for mounts.
  191. //
  192. if (FromKernelMode == FALSE) {
  193. Status = PsCheckPermission(PERMISSION_MOUNT);
  194. if (!KSUCCESS(Status)) {
  195. goto MountEnd;
  196. }
  197. }
  198. //
  199. // Open the mount point path point, but do not follow any mount points in
  200. // the final component.
  201. //
  202. Status = IopPathWalk(FromKernelMode,
  203. NULL,
  204. &MountPointPath,
  205. &MountPointPathSize,
  206. OPEN_FLAG_NO_MOUNT_POINT,
  207. IoObjectInvalid,
  208. NULL,
  209. FILE_PERMISSION_NONE,
  210. &MountPathPoint);
  211. //
  212. // If the entry does not exist, fail.
  213. //
  214. if (!KSUCCESS(Status)) {
  215. goto MountEnd;
  216. }
  217. //
  218. // Open the target path point and if it exists, try to mount the target at
  219. // the mount point.
  220. //
  221. Status = IopPathWalk(FromKernelMode,
  222. NULL,
  223. &TargetPath,
  224. &TargetPathSize,
  225. 0,
  226. IoObjectInvalid,
  227. NULL,
  228. FILE_PERMISSION_NONE,
  229. &TargetPathPoint);
  230. if (!KSUCCESS(Status)) {
  231. goto MountEnd;
  232. }
  233. //
  234. // Get the mount point file object for validation below.
  235. //
  236. MountFileObject = MountPathPoint.PathEntry->FileObject;
  237. MountFileType = MountFileObject->Properties.Type;
  238. //
  239. // Get the target's file object and determine what type of object it is.
  240. // Act according to the type.
  241. //
  242. TargetFileObject = TargetPathPoint.PathEntry->FileObject;
  243. switch (TargetFileObject->Properties.Type) {
  244. case IoObjectBlockDevice:
  245. Device = TargetFileObject->Device;
  246. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  247. //
  248. // Bind calls are only allowed on block devices if the mount point is
  249. // not a directory.
  250. //
  251. if ((MountFlags & MOUNT_FLAG_BIND) != 0) {
  252. if ((MountFileType == IoObjectRegularDirectory) ||
  253. (MountFileType == IoObjectObjectDirectory)) {
  254. Status = STATUS_FILE_IS_DIRECTORY;
  255. goto MountEnd;
  256. }
  257. Status = IopMount(FromKernelMode,
  258. &MountPathPoint,
  259. &TargetPathPoint,
  260. MountFlags);
  261. goto MountEnd;
  262. }
  263. //
  264. // The target file object must be a directory.
  265. //
  266. if ((MountFileType != IoObjectRegularDirectory) &&
  267. ((FromKernelMode == FALSE) ||
  268. (MountFileType != IoObjectObjectDirectory))) {
  269. Status = STATUS_NOT_A_DIRECTORY;
  270. goto MountEnd;
  271. }
  272. //
  273. // If the device is not mountable, then quit.
  274. //
  275. if ((Device->Flags & DEVICE_FLAG_MOUNTABLE) == 0) {
  276. Status = STATUS_NOT_MOUNTABLE;
  277. goto MountEnd;
  278. }
  279. //
  280. // Get the volume for this device.
  281. //
  282. Status = IopCreateOrLookupVolume(Device, &Volume);
  283. if (!KSUCCESS(Status)) {
  284. goto MountEnd;
  285. }
  286. ASSERT((MountFlags & MOUNT_FLAG_RECURSIVE) == 0);
  287. ASSERT(Volume->PathEntry != NULL);
  288. ASSERT(TargetPathPoint.PathEntry != NULL);
  289. //
  290. // The volume stores the anonymous path entry of its root directory.
  291. // Use that as a mount target. The volume holds a reference on the path
  292. // entry, so there is no need to acquire an additional reference.
  293. //
  294. IO_PATH_POINT_RELEASE_REFERENCE(&TargetPathPoint);
  295. TargetPathPoint.PathEntry = Volume->PathEntry;
  296. TargetPathPoint.MountPoint = NULL;
  297. //
  298. // Attempt to mount the target volume onto the mount point.
  299. //
  300. Status = IopMount(FromKernelMode,
  301. &MountPathPoint,
  302. &TargetPathPoint,
  303. MountFlags);
  304. TargetPathPoint.PathEntry = NULL;
  305. break;
  306. case IoObjectPipe:
  307. case IoObjectSocket:
  308. case IoObjectCharacterDevice:
  309. case IoObjectTerminalMaster:
  310. case IoObjectTerminalSlave:
  311. //
  312. // Only allow bind calls to proceed for these type of target files as
  313. // the allowed mounts are all considered busy.
  314. //
  315. if ((MountFlags & MOUNT_FLAG_BIND) == 0) {
  316. Status = STATUS_NOT_BLOCK_DEVICE;
  317. goto MountEnd;
  318. }
  319. //
  320. // These types of objects are not allowed to be mounted on directories.
  321. //
  322. if ((MountFileType == IoObjectRegularDirectory) ||
  323. (MountFileType == IoObjectObjectDirectory)) {
  324. Status = STATUS_FILE_IS_DIRECTORY;
  325. goto MountEnd;
  326. }
  327. //
  328. // Attempt to mount the target to the mount location.
  329. //
  330. Status = IopMount(FromKernelMode,
  331. &MountPathPoint,
  332. &TargetPathPoint,
  333. MountFlags);
  334. break;
  335. case IoObjectObjectDirectory:
  336. case IoObjectRegularDirectory:
  337. case IoObjectRegularFile:
  338. Device = TargetFileObject->Device;
  339. //
  340. // Only allow bind calls to proceed for these type of target files as
  341. // the allowed mounts are all considered busy.
  342. //
  343. if ((MountFlags & MOUNT_FLAG_BIND) == 0) {
  344. Status = STATUS_RESOURCE_IN_USE;
  345. goto MountEnd;
  346. }
  347. //
  348. // The target and mount point file types must be compatible. Do not
  349. // allow mount points on top of object directories.
  350. //
  351. if ((TargetFileObject->Properties.Type == IoObjectRegularDirectory) ||
  352. (TargetFileObject->Properties.Type == IoObjectObjectDirectory)) {
  353. if (MountFileType != IoObjectRegularDirectory) {
  354. Status = STATUS_NOT_A_DIRECTORY;
  355. goto MountEnd;
  356. }
  357. } else {
  358. ASSERT(TargetFileObject->Properties.Type == IoObjectRegularFile);
  359. if ((MountFileType == IoObjectRegularDirectory) ||
  360. (MountFileType == IoObjectObjectDirectory)) {
  361. Status = STATUS_FILE_IS_DIRECTORY;
  362. goto MountEnd;
  363. }
  364. }
  365. //
  366. // Attempt to mount the target to the mount location.
  367. //
  368. Status = IopMount(FromKernelMode,
  369. &MountPathPoint,
  370. &TargetPathPoint,
  371. MountFlags);
  372. break;
  373. //
  374. // Symbolic links fall through to the default cause because they should
  375. // never be the final result of a path walk that doesn't have the symbolic
  376. // link flag set.
  377. //
  378. case IoObjectSymbolicLink:
  379. default:
  380. ASSERT(FALSE);
  381. Status = STATUS_NOT_SUPPORTED;
  382. break;
  383. }
  384. MountEnd:
  385. if (Volume != NULL) {
  386. IoVolumeReleaseReference(Volume);
  387. }
  388. if (MountPathPoint.PathEntry != NULL) {
  389. IO_PATH_POINT_RELEASE_REFERENCE(&MountPathPoint);
  390. }
  391. if (TargetPathPoint.PathEntry != NULL) {
  392. IO_PATH_POINT_RELEASE_REFERENCE(&TargetPathPoint);
  393. }
  394. return Status;
  395. }
  396. KERNEL_API
  397. KSTATUS
  398. IoUnmount (
  399. BOOL FromKernelMode,
  400. PSTR MountPointPath,
  401. ULONG MountPointPathSize,
  402. ULONG MountFlags,
  403. ULONG AccessFlags
  404. )
  405. /*++
  406. Routine Description:
  407. This routine attempts to remove a mount point at the given path.
  408. Arguments:
  409. FromKernelMode - Supplies a boolean indicating the request is coming from
  410. kernel mode.
  411. MountPointPath - Supplies a pointer to the string containing the path to
  412. where the unmount should take place.
  413. MountPointPathSize - Supplies the size of the mount point path string in
  414. bytes, including the null terminator.
  415. MountFlags - Supplies the flags associated with the mount operation. See
  416. MOUNT_FLAG_* for definitions.
  417. AccessFlags - Supplies the flags associated with the mount point's access
  418. permissions. See IO_ACCESS_FLAG_* for definitions.
  419. Return Value:
  420. Status code.
  421. --*/
  422. {
  423. PATH_POINT PathPoint;
  424. KSTATUS Status;
  425. PathPoint.PathEntry = NULL;
  426. //
  427. // Permission check for unmounting.
  428. //
  429. if (FromKernelMode == FALSE) {
  430. Status = PsCheckPermission(PERMISSION_MOUNT);
  431. if (!KSUCCESS(Status)) {
  432. goto UnmountEnd;
  433. }
  434. }
  435. //
  436. // Open the mount point's path point.
  437. //
  438. Status = IopPathWalk(FromKernelMode,
  439. NULL,
  440. &MountPointPath,
  441. &MountPointPathSize,
  442. 0,
  443. IoObjectInvalid,
  444. NULL,
  445. FILE_PERMISSION_NONE,
  446. &PathPoint);
  447. //
  448. // If the entry does not exist, fail.
  449. //
  450. if (!KSUCCESS(Status)) {
  451. goto UnmountEnd;
  452. }
  453. //
  454. // If this target is not a mount point, fail.
  455. //
  456. if (IO_IS_MOUNT_POINT(&PathPoint) == FALSE) {
  457. Status = STATUS_NOT_A_MOUNT_POINT;
  458. goto UnmountEnd;
  459. }
  460. //
  461. // Go ahead and unmount the mount point.
  462. //
  463. Status = IopUnmount(PathPoint.MountPoint, MountFlags);
  464. if (!KSUCCESS(Status)) {
  465. goto UnmountEnd;
  466. }
  467. UnmountEnd:
  468. if (PathPoint.PathEntry != NULL) {
  469. IO_PATH_POINT_RELEASE_REFERENCE(&PathPoint);
  470. }
  471. return Status;
  472. }
  473. KSTATUS
  474. IopGetSetMountPointInformation (
  475. PVOID Data,
  476. PUINTN DataSize,
  477. BOOL Set
  478. )
  479. /*++
  480. Routine Description:
  481. This routine gets or sets mount point information.
  482. Arguments:
  483. Data - Supplies a pointer to the data buffer where the data is either
  484. returned for a get operation or given for a set operation.
  485. DataSize - Supplies a pointer that on input contains the size of the
  486. data buffer. On output, contains the required size of the data buffer.
  487. Set - Supplies a boolean indicating if this is a get operation (FALSE) or
  488. a set operation (TRUE).
  489. Return Value:
  490. Status code.
  491. --*/
  492. {
  493. if (Set != FALSE) {
  494. *DataSize = 0;
  495. return STATUS_NOT_SUPPORTED;
  496. }
  497. return IoGetMountPoints(Data, DataSize);
  498. }
  499. KERNEL_API
  500. KSTATUS
  501. IoGetMountPoints (
  502. PVOID Buffer,
  503. PUINTN BufferSize
  504. )
  505. /*++
  506. Routine Description:
  507. This routine returns the list of mount points for the current process,
  508. filling the supplied buffer with the data.
  509. Arguments:
  510. Buffer - Supplies a pointer to a buffer that receives the mount point data.
  511. BufferSize - Supplies a pointer to the size of the buffer. Upon return this
  512. either holds the number of bytes actually used or if the buffer is
  513. to small, it receives the expected buffer size.
  514. Return Value:
  515. Status code.
  516. --*/
  517. {
  518. UINTN BytesRemaining;
  519. BOOL CheckChildren;
  520. PLIST_ENTRY CurrentEntry;
  521. PVOID CurrentOffset;
  522. BOOL DescendantPath;
  523. PMOUNT_POINT MountPoint;
  524. PKPROCESS Process;
  525. UINTN RequiredSize;
  526. PPATH_POINT Root;
  527. PATH_POINT RootCopy;
  528. PMOUNT_POINT RootMount;
  529. KSTATUS Status;
  530. UINTN TreeRequiredSize;
  531. BytesRemaining = *BufferSize;
  532. CurrentOffset = Buffer;
  533. RequiredSize = 0;
  534. Root = NULL;
  535. //
  536. // Get the caller's root.
  537. //
  538. Process = PsGetCurrentProcess();
  539. KeAcquireQueuedLock(Process->Paths.Lock);
  540. if (Process->Paths.Root.PathEntry != NULL) {
  541. IO_COPY_PATH_POINT(&RootCopy, &(Process->Paths.Root));
  542. IO_PATH_POINT_ADD_REFERENCE(&RootCopy);
  543. Root = &RootCopy;
  544. }
  545. KeReleaseQueuedLock(Process->Paths.Lock);
  546. //
  547. // If the process does not have a root return all mounts points under the
  548. // root.
  549. //
  550. CheckChildren = FALSE;
  551. if (Root == NULL) {
  552. RootMount = IoPathPointRoot.MountPoint;
  553. //
  554. // Otherwise be careful to only return the mount points visible to the
  555. // caller. Keep in mind that the process's root path point might not be the
  556. // root of a mount point.
  557. //
  558. } else {
  559. RootMount = Root->MountPoint;
  560. if (IO_IS_MOUNT_POINT(Root) == FALSE) {
  561. CheckChildren = TRUE;
  562. }
  563. }
  564. KeAcquireSharedExclusiveLockShared(IoMountLock);
  565. //
  566. // If the process does not have a root, skip the root mount and process
  567. // only its children; it isn't a real mount point. If the process root is
  568. // not a mount point, then only the correct descendant mount points should
  569. // be processed.
  570. //
  571. if ((Root == NULL) || (CheckChildren != FALSE)) {
  572. CurrentEntry = RootMount->ChildListHead.Previous;
  573. while (CurrentEntry != &(RootMount->ChildListHead)) {
  574. MountPoint = LIST_VALUE(CurrentEntry,
  575. MOUNT_POINT,
  576. SiblingListEntry);
  577. CurrentEntry = CurrentEntry->Previous;
  578. if (CheckChildren != FALSE) {
  579. DescendantPath = IopIsDescendantPath(Root->PathEntry,
  580. MountPoint->MountEntry);
  581. if (DescendantPath == FALSE) {
  582. continue;
  583. }
  584. }
  585. Status = IopGetMountPointsFromTree(Root,
  586. MountPoint,
  587. &CurrentOffset,
  588. &BytesRemaining,
  589. &TreeRequiredSize);
  590. RequiredSize += TreeRequiredSize;
  591. if (!KSUCCESS(Status)) {
  592. goto GetMountPointsEnd;
  593. }
  594. }
  595. //
  596. // Otherwise the process root is a mount point. Just run through the whole
  597. // tree.
  598. //
  599. } else {
  600. Status = IopGetMountPointsFromTree(Root,
  601. RootMount,
  602. &CurrentOffset,
  603. &BytesRemaining,
  604. &RequiredSize);
  605. if (!KSUCCESS(Status)) {
  606. goto GetMountPointsEnd;
  607. }
  608. }
  609. //
  610. // If the required size ended up being bigger than the buffer size. Fail.
  611. //
  612. if (RequiredSize > *BufferSize) {
  613. Status = STATUS_BUFFER_TOO_SMALL;
  614. goto GetMountPointsEnd;
  615. }
  616. Status = STATUS_SUCCESS;
  617. GetMountPointsEnd:
  618. KeReleaseSharedExclusiveLockShared(IoMountLock);
  619. if (Root != NULL) {
  620. IO_PATH_POINT_RELEASE_REFERENCE(Root);
  621. }
  622. //
  623. // Always return the required size to the caller. This is either the amount
  624. // of data written to the buffer, or the size the buffer needs to be.
  625. //
  626. *BufferSize = RequiredSize;
  627. //
  628. // Handle failure cases, zeroing out the buffer to prevent handing partial
  629. // data back to user-mode.
  630. //
  631. if (!KSUCCESS(Status)) {
  632. RtlZeroMemory(Buffer, *BufferSize);
  633. }
  634. return Status;
  635. }
  636. VOID
  637. IopRemoveMountPoints (
  638. PPATH_POINT RootPath
  639. )
  640. /*++
  641. Routine Description:
  642. This routine lazily unmounts all the mount points that exist under the
  643. given root path point, including itself.
  644. Arguments:
  645. RootPath - Supplies a pointer to the root path point, under which all
  646. mount points will be removed.
  647. Return Value:
  648. None.
  649. --*/
  650. {
  651. PLIST_ENTRY CurrentEntry;
  652. PMOUNT_POINT CurrentMount;
  653. BOOL DescendantPath;
  654. LIST_ENTRY DestroyList;
  655. //
  656. // If the root is a mount point, then it is as simple as calling unmount.
  657. //
  658. if (IO_IS_MOUNT_POINT(RootPath) != FALSE) {
  659. IopUnmount(RootPath->MountPoint,
  660. MOUNT_FLAG_DETACH | MOUNT_FLAG_RECURSIVE);
  661. //
  662. // Otherwise unmount each mount point that is a descendant of the root.
  663. //
  664. } else {
  665. INITIALIZE_LIST_HEAD(&DestroyList);
  666. KeAcquireSharedExclusiveLockExclusive(IoMountLock);
  667. CurrentEntry = RootPath->MountPoint->ChildListHead.Previous;
  668. while (CurrentEntry != &(RootPath->MountPoint->ChildListHead)) {
  669. CurrentMount = LIST_VALUE(CurrentEntry,
  670. MOUNT_POINT,
  671. SiblingListEntry);
  672. CurrentEntry = CurrentEntry->Previous;
  673. DescendantPath = IopIsDescendantPath(RootPath->PathEntry,
  674. CurrentMount->MountEntry);
  675. if (DescendantPath == FALSE) {
  676. continue;
  677. }
  678. IopDestroyMountTree(CurrentMount, &DestroyList);
  679. }
  680. KeReleaseSharedExclusiveLockExclusive(IoMountLock);
  681. //
  682. // Go through and destroy each mount point by releasing the original
  683. // reference and decrementing the mount count on the path entry.
  684. //
  685. CurrentEntry = DestroyList.Next;
  686. while (CurrentEntry != &DestroyList) {
  687. CurrentMount = LIST_VALUE(CurrentEntry,
  688. MOUNT_POINT,
  689. SiblingListEntry);
  690. CurrentEntry = CurrentEntry->Next;
  691. CurrentMount->SiblingListEntry.Next = NULL;
  692. IopPathEntryDecrementMountCount(CurrentMount->MountEntry);
  693. IoMountPointReleaseReference(CurrentMount);
  694. }
  695. }
  696. return;
  697. }
  698. PMOUNT_POINT
  699. IopFindMountPoint (
  700. PMOUNT_POINT Parent,
  701. PPATH_ENTRY PathEntry
  702. )
  703. /*++
  704. Routine Description:
  705. This routine searches for a child mount point of the given parent whose
  706. mount path entry matches the given path entry. If found, a reference is
  707. taken on the returned mount point.
  708. Arguments:
  709. Parent - Supplies a pointer to a parent mount point whose children are
  710. searched for a mount point that matches the path entry.
  711. PathEntry - Supplies a pointer to a path entry to search for.
  712. Return Value:
  713. Returns a pointer to the found mount point on success, or NULL on failure.
  714. --*/
  715. {
  716. PLIST_ENTRY CurrentEntry;
  717. PMOUNT_POINT FoundMountPoint;
  718. PMOUNT_POINT MountPoint;
  719. //
  720. // Do nothing if the path entry is not mounted anywhere or if the mount
  721. // point has no children to search.
  722. //
  723. if ((PathEntry->MountCount == 0) ||
  724. (LIST_EMPTY(&(Parent->ChildListHead)) != FALSE)) {
  725. return NULL;
  726. }
  727. //
  728. // Search over the list of child mount points looking for one whose mount
  729. // path entry matches the given path entry. Search from beginning to end
  730. // to find the most recent mount point using the given path entry.
  731. //
  732. FoundMountPoint = NULL;
  733. KeAcquireSharedExclusiveLockShared(IoMountLock);
  734. CurrentEntry = Parent->ChildListHead.Next;
  735. while (CurrentEntry != &(Parent->ChildListHead)) {
  736. MountPoint = LIST_VALUE(CurrentEntry, MOUNT_POINT, SiblingListEntry);
  737. if (MountPoint->MountEntry == PathEntry) {
  738. FoundMountPoint = MountPoint;
  739. IoMountPointAddReference(FoundMountPoint);
  740. break;
  741. }
  742. CurrentEntry = CurrentEntry->Next;
  743. }
  744. KeReleaseSharedExclusiveLockShared(IoMountLock);
  745. return FoundMountPoint;
  746. }
  747. PMOUNT_POINT
  748. IopGetMountPointParent (
  749. PMOUNT_POINT MountPoint
  750. )
  751. /*++
  752. Routine Description:
  753. This routine gets a mount point's parent. The parent can disappear at any
  754. moment with a lazy unmount, so this routine acquires the mount lock in
  755. shared mode to check the parent.
  756. Arguments:
  757. MountPoint - Supplies a pointer to a mount point.
  758. Return Value:
  759. Returns a pointer to the parent mount point on success, or NULL otherwise.
  760. --*/
  761. {
  762. PMOUNT_POINT Parent;
  763. if (MountPoint->Parent == NULL) {
  764. return NULL;
  765. }
  766. KeAcquireSharedExclusiveLockShared(IoMountLock);
  767. Parent = MountPoint->Parent;
  768. if (Parent != NULL) {
  769. IoMountPointAddReference(MountPoint->Parent);
  770. }
  771. KeReleaseSharedExclusiveLockShared(IoMountLock);
  772. return Parent;
  773. }
  774. VOID
  775. IoMountPointAddReference (
  776. PMOUNT_POINT MountPoint
  777. )
  778. /*++
  779. Routine Description:
  780. This routine increments the reference count for the given mount point.
  781. Arguments:
  782. MountPoint - Supplies a pointer to a mount point.
  783. Return Value:
  784. None.
  785. --*/
  786. {
  787. ULONG OldReferenceCount;
  788. if (MountPoint != NULL) {
  789. OldReferenceCount = RtlAtomicAdd32(&(MountPoint->ReferenceCount), 1);
  790. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  791. }
  792. return;
  793. }
  794. VOID
  795. IoMountPointReleaseReference (
  796. PMOUNT_POINT MountPoint
  797. )
  798. /*++
  799. Routine Description:
  800. This routine decrements the reference count for the given mount point.
  801. Arguments:
  802. MountPoint - Supplies a pointer to a mount point.
  803. Return Value:
  804. None.
  805. --*/
  806. {
  807. ULONG OldReferenceCount;
  808. if (MountPoint != NULL) {
  809. OldReferenceCount = RtlAtomicAdd32(&(MountPoint->ReferenceCount),
  810. (ULONG)-1);
  811. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  812. if (OldReferenceCount == 1) {
  813. IopDestroyMountPoint(MountPoint);
  814. }
  815. }
  816. return;
  817. }
  818. //
  819. // --------------------------------------------------------- Internal Functions
  820. //
  821. KSTATUS
  822. IopMount (
  823. BOOL FromKernelMode,
  824. PPATH_POINT Mount,
  825. PPATH_POINT Target,
  826. ULONG Flags
  827. )
  828. /*++
  829. Routine Description:
  830. This routine mounts the target path point on the mount point entry.
  831. Arguments:
  832. FromKernelMode - Supplies a boolean indicating the request is coming from
  833. kernel mode.
  834. Mount - Supplies a pointer to the path point that is to be mounted on.
  835. Target - Supplies a pointer to the path point that is to be mounted at the
  836. mount point.
  837. Flags - Supplies a bitmaks of mount flags. See MOUNT_FLAG_* for definitions.
  838. Return Value:
  839. Status code.
  840. --*/
  841. {
  842. LIST_ENTRY DestroyList;
  843. PFILE_OBJECT FileObject;
  844. BOOL FirstMount;
  845. BOOL LockHeld;
  846. BOOL MountCountIncremented;
  847. LIST_ENTRY MountList;
  848. PMOUNT_POINT MountPoint;
  849. PKPROCESS Process;
  850. PPATH_POINT Root;
  851. PATH_POINT RootCopy;
  852. KSTATUS Status;
  853. PSTR TargetPath;
  854. ULONG TargetPathSize;
  855. LockHeld = FALSE;
  856. MountCountIncremented = FALSE;
  857. INITIALIZE_LIST_HEAD(&MountList);
  858. //
  859. // The mount supplied should not be the root of a mount point. Otherwise
  860. // the new mount point would be the child of the wrong mount point.
  861. //
  862. ASSERT(IO_IS_MOUNT_POINT(Mount) == FALSE);
  863. //
  864. // Get the caller's root.
  865. //
  866. Root = NULL;
  867. if (FromKernelMode == FALSE) {
  868. Process = PsGetCurrentProcess();
  869. KeAcquireQueuedLock(Process->Paths.Lock);
  870. if (Process->Paths.Root.PathEntry != NULL) {
  871. IO_COPY_PATH_POINT(&RootCopy, &(Process->Paths.Root));
  872. IO_PATH_POINT_ADD_REFERENCE(&RootCopy);
  873. Root = &RootCopy;
  874. }
  875. KeReleaseQueuedLock(Process->Paths.Lock);
  876. }
  877. MountPoint = NULL;
  878. Status = IopGetPathFromRoot(Target,
  879. Root,
  880. &TargetPath,
  881. &TargetPathSize);
  882. if (Root != NULL) {
  883. IO_PATH_POINT_RELEASE_REFERENCE(Root);
  884. }
  885. if (!KSUCCESS(Status)) {
  886. goto MountEnd;
  887. }
  888. //
  889. // Increment the mount count for the path entry on top of which the mount
  890. // will be placed. Due to lock ordering with the mount lock, this is done
  891. // first to potentially increment the path entry's mount count from 0 to 1.
  892. // This allows the routine to freely increment the path entry's mount count
  893. // while the mount lock is held without also acquiring the file object
  894. // lock, which would be an order inversion. A path entry cannot be deleted
  895. // or renamed while it has a non-zero mount count, but it's up to the
  896. // caller to synchronize those actions with mount.
  897. //
  898. FileObject = Mount->PathEntry->FileObject;
  899. KeAcquireSharedExclusiveLockShared(FileObject->Lock);
  900. IopPathEntryIncrementMountCount(Mount->PathEntry);
  901. MountCountIncremented = TRUE;
  902. KeReleaseSharedExclusiveLockShared(FileObject->Lock);
  903. //
  904. // Acquire the mount lock exclusively throughout the whole mount process.
  905. //
  906. KeAcquireSharedExclusiveLockExclusive(IoMountLock);
  907. LockHeld = TRUE;
  908. //
  909. // Allocate the new mount point and copy the child mount points of the
  910. // target path point as necessary.
  911. //
  912. Status = IopCreateAndCopyMountPoint(Mount,
  913. Target,
  914. &MountList,
  915. TargetPath,
  916. TargetPathSize,
  917. Flags);
  918. if (!KSUCCESS(Status)) {
  919. goto MountEnd;
  920. }
  921. //
  922. // If this is a linked mount point, it should be propogated to all other
  923. // locations in the namespace where the mount path entry may be found. The
  924. // mount point created above should be first on the list.
  925. //
  926. if ((Flags & MOUNT_FLAG_LINKED) != 0) {
  927. ASSERT(LIST_EMPTY(&MountList) == FALSE);
  928. MountPoint = LIST_VALUE(MountList.Next, MOUNT_POINT, SiblingListEntry);
  929. Status = IopLinkMountPoint(MountPoint, Target, &MountList);
  930. if (!KSUCCESS(Status)) {
  931. goto MountEnd;
  932. }
  933. }
  934. //
  935. // All newly created mount points are on the local mount list. Run through
  936. // the list and add them to their parents' lists of children. The first one
  937. // on the list is the initial mount point requested by the caller and any
  938. // additional mount points are a result of propogating a linked mount
  939. // request to other portions of the mount tree. As a result, the first
  940. // mount gets placed first on its parent's list of children and subsequent
  941. // mounts get placed last of their parents' lists of children.
  942. //
  943. FirstMount = TRUE;
  944. while (LIST_EMPTY(&MountList) == FALSE) {
  945. MountPoint = LIST_VALUE(MountList.Next, MOUNT_POINT, SiblingListEntry);
  946. LIST_REMOVE(&(MountPoint->SiblingListEntry));
  947. ASSERT(MountPoint->Parent != NULL);
  948. if (FirstMount != FALSE) {
  949. INSERT_AFTER(&(MountPoint->SiblingListEntry),
  950. &(MountPoint->Parent->ChildListHead));
  951. FirstMount = FALSE;
  952. } else {
  953. INSERT_BEFORE(&(MountPoint->SiblingListEntry),
  954. &(MountPoint->Parent->ChildListHead));
  955. }
  956. }
  957. MountEnd:
  958. if (LockHeld != FALSE) {
  959. KeReleaseSharedExclusiveLockExclusive(IoMountLock);
  960. }
  961. //
  962. // If the mount attempt was not successful, all of the created mount points
  963. // need to be destroyed. None of them should be live in the tree of mount
  964. // points. Run through the mount list and destroy each entry and its
  965. // descendants.
  966. //
  967. if (!KSUCCESS(Status)) {
  968. INITIALIZE_LIST_HEAD(&DestroyList);
  969. while (LIST_EMPTY(&MountList) == FALSE) {
  970. MountPoint = LIST_VALUE(MountList.Next,
  971. MOUNT_POINT,
  972. SiblingListEntry);
  973. IopDestroyMountTree(MountPoint, &DestroyList);
  974. }
  975. while (LIST_EMPTY(&DestroyList) == FALSE) {
  976. MountPoint = LIST_VALUE(DestroyList.Next,
  977. MOUNT_POINT,
  978. SiblingListEntry);
  979. LIST_REMOVE(&(MountPoint->SiblingListEntry));
  980. MountPoint->SiblingListEntry.Next = NULL;
  981. IopPathEntryDecrementMountCount(MountPoint->MountEntry);
  982. IoMountPointReleaseReference(MountPoint);
  983. }
  984. }
  985. //
  986. // Always decrement the mount count if it was incremented before. The count
  987. // was additionally incremented when any mounts were created.
  988. //
  989. if (MountCountIncremented != FALSE) {
  990. IopPathEntryDecrementMountCount(Mount->PathEntry);
  991. }
  992. if (TargetPath != NULL) {
  993. MmFreePagedPool(TargetPath);
  994. }
  995. return Status;
  996. }
  997. KSTATUS
  998. IopUnmount (
  999. PMOUNT_POINT MountPoint,
  1000. ULONG Flags
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. This routine unmounts the given mount point.
  1005. Arguments:
  1006. MountPoint - Supplies a pointer to the mount point that is to be unmounted.
  1007. Flags - Supplies a bitmask of unmount flags. See MOUNT_FLAG_* for
  1008. definitions.
  1009. Return Value:
  1010. Status code.
  1011. --*/
  1012. {
  1013. ULONG BusyFlags;
  1014. PLIST_ENTRY CurrentEntry;
  1015. PMOUNT_POINT CurrentMount;
  1016. LIST_ENTRY DestroyList;
  1017. KSTATUS Status;
  1018. INITIALIZE_LIST_HEAD(&DestroyList);
  1019. //
  1020. // Synchronize the whole unmount operation with mounts and other unmounts.
  1021. //
  1022. KeAcquireSharedExclusiveLockExclusive(IoMountLock);
  1023. //
  1024. // A different lazy (detach) unmount may have beat this to the punch.
  1025. //
  1026. if (MountPoint->Parent == NULL) {
  1027. ASSERT(LIST_EMPTY(&(MountPoint->ChildListHead)) != FALSE);
  1028. Status = STATUS_NOT_A_MOUNT_POINT;
  1029. goto UnmountEnd;
  1030. }
  1031. //
  1032. // If the call is not lazy, then make sure there are no references on the
  1033. // mount point, its children, or any linked mount points before it is
  1034. // removed.
  1035. //
  1036. if ((Flags & MOUNT_FLAG_DETACH) == 0) {
  1037. BusyFlags = Flags | (MountPoint->Flags & MOUNT_FLAG_LINKED);
  1038. if (IopIsMountPointBusy(MountPoint, MountPoint, BusyFlags) != FALSE) {
  1039. Status = STATUS_RESOURCE_IN_USE;
  1040. goto UnmountEnd;
  1041. }
  1042. }
  1043. //
  1044. // Destroy the the mount tree. If this is a linked mount point, then also
  1045. // destroy the other instances of the mount.
  1046. //
  1047. IopDestroyMountTree(MountPoint, &DestroyList);
  1048. if ((MountPoint->Flags & MOUNT_FLAG_LINKED) != 0) {
  1049. IopDestroyLinkedMountPoints(MountPoint, &DestroyList);
  1050. }
  1051. Status = STATUS_SUCCESS;
  1052. UnmountEnd:
  1053. KeReleaseSharedExclusiveLockExclusive(IoMountLock);
  1054. //
  1055. // Destroy any mount points that were plucked off the tree.
  1056. //
  1057. CurrentEntry = DestroyList.Next;
  1058. while (CurrentEntry != &DestroyList) {
  1059. CurrentMount = LIST_VALUE(CurrentEntry, MOUNT_POINT, SiblingListEntry);
  1060. CurrentEntry = CurrentEntry->Next;
  1061. CurrentMount->SiblingListEntry.Next = NULL;
  1062. IopPathEntryDecrementMountCount(CurrentMount->MountEntry);
  1063. IoMountPointReleaseReference(CurrentMount);
  1064. }
  1065. return Status;
  1066. }
  1067. BOOL
  1068. IopIsMountPointBusy (
  1069. PMOUNT_POINT MountPoint,
  1070. PMOUNT_POINT OriginalMountPoint,
  1071. ULONG Flags
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. This routine determines whether or not the given mount point is busy. It
  1076. takes all children and linked mount points into consideration depending on
  1077. the supplied set of mount flags.
  1078. Arguments:
  1079. MountPoint - Supplies a pointer to the mount point to be checked.
  1080. OriginalMountPoint - Supplies a pointer to the mount point that was
  1081. originally being checked for busy state (before this routine recurses).
  1082. Flags - Supplies a bitmask of flags used to determine which child or linked
  1083. mount points should also be checked for busy status. Seet MOUNT_FLAG_*
  1084. for definitions.
  1085. Return Value:
  1086. Returns TRUE if the mount point is busy or FALSE otherwise.
  1087. --*/
  1088. {
  1089. BOOL Busy;
  1090. BOOL CheckChildren;
  1091. ULONG CheckFlags;
  1092. PMOUNT_POINT CurrentMount;
  1093. PMOUNT_POINT TreeRoot;
  1094. ASSERT(KeIsSharedExclusiveLockHeldExclusive(IoMountLock) != FALSE);
  1095. Busy = FALSE;
  1096. //
  1097. // If the current mount point is the original mount point, then it is busy
  1098. // if it has more than two references (the original reference and the
  1099. // reference taken by the caller).
  1100. //
  1101. if (MountPoint == OriginalMountPoint) {
  1102. if (MountPoint->ReferenceCount > 2) {
  1103. Busy = TRUE;
  1104. goto IsMountPointBusyEnd;
  1105. }
  1106. //
  1107. // Other mount points are considered busy if they have more than the
  1108. // original base reference.
  1109. //
  1110. } else {
  1111. if (MountPoint->ReferenceCount > 1) {
  1112. Busy = TRUE;
  1113. goto IsMountPointBusyEnd;
  1114. }
  1115. }
  1116. //
  1117. // Handle any child mount points. They do not take a reference on their
  1118. // parent, so their existence alone makes the parent busy.
  1119. //
  1120. if (LIST_EMPTY(&(MountPoint->ChildListHead)) == FALSE) {
  1121. //
  1122. // If this is not a recursive unmount then it is too busy to unmount
  1123. // only if there are any non-linked descendants or a linked descendant
  1124. // with a reference.
  1125. //
  1126. CheckFlags = 0;
  1127. if ((Flags & MOUNT_FLAG_RECURSIVE) == 0) {
  1128. CheckFlags = MOUNT_FLAG_LINKED;
  1129. }
  1130. //
  1131. // Check the children to make sure they all have one reference. A
  1132. // recursive call can only succeed if all mount points can be removed.
  1133. // Non-recursive calls can only succeed if there are no non-linked
  1134. // children and if all the linked children only have one reference.
  1135. //
  1136. CurrentMount = LIST_VALUE(MountPoint->ChildListHead.Next,
  1137. MOUNT_POINT,
  1138. SiblingListEntry);
  1139. while (CurrentMount != MountPoint) {
  1140. if (CurrentMount != OriginalMountPoint) {
  1141. if ((CurrentMount->Flags & CheckFlags) != CheckFlags) {
  1142. Busy = TRUE;
  1143. goto IsMountPointBusyEnd;
  1144. }
  1145. if (CurrentMount->ReferenceCount > 1) {
  1146. Busy = TRUE;
  1147. goto IsMountPointBusyEnd;
  1148. }
  1149. //
  1150. // Iterate to the current mount point's first child if it
  1151. // exists.
  1152. //
  1153. if (LIST_EMPTY(&(CurrentMount->ChildListHead)) == FALSE) {
  1154. CurrentMount = LIST_VALUE(CurrentMount->ChildListHead.Next,
  1155. MOUNT_POINT,
  1156. SiblingListEntry);
  1157. continue;
  1158. }
  1159. }
  1160. //
  1161. // Move to a sibling or ancestor's sibling.
  1162. //
  1163. while (CurrentMount != MountPoint) {
  1164. if (CurrentMount->SiblingListEntry.Next !=
  1165. &(CurrentMount->Parent->ChildListHead)) {
  1166. CurrentMount = LIST_VALUE(
  1167. CurrentMount->SiblingListEntry.Next,
  1168. MOUNT_POINT,
  1169. SiblingListEntry);
  1170. break;
  1171. }
  1172. CurrentMount = CurrentMount->Parent;
  1173. }
  1174. }
  1175. }
  1176. //
  1177. // If the mount point is linked, then it may be busy if its other instances
  1178. // have references or descendants with references.
  1179. //
  1180. if ((Flags & MOUNT_FLAG_LINKED) != 0) {
  1181. //
  1182. // Remove the linked flag so that this routine does not recurse more
  1183. // than one level.
  1184. //
  1185. Flags &= ~MOUNT_FLAG_LINKED;
  1186. //
  1187. // Iterate over the tree of mount points starting at the root.
  1188. //
  1189. TreeRoot = IoPathPointRoot.MountPoint;
  1190. CurrentMount = TreeRoot;
  1191. do {
  1192. CheckChildren = TRUE;
  1193. if ((CurrentMount != MountPoint) &&
  1194. ((CurrentMount->Flags & MOUNT_FLAG_LINKED) != 0) &&
  1195. (CurrentMount->TargetEntry == MountPoint->TargetEntry)) {
  1196. Busy = IopIsMountPointBusy(CurrentMount,
  1197. OriginalMountPoint,
  1198. Flags);
  1199. if (Busy != FALSE) {
  1200. goto IsMountPointBusyEnd;
  1201. }
  1202. CheckChildren = FALSE;
  1203. }
  1204. if ((CheckChildren != FALSE) &&
  1205. (LIST_EMPTY(&(CurrentMount->ChildListHead)) == FALSE)) {
  1206. CurrentMount = LIST_VALUE(CurrentMount->ChildListHead.Previous,
  1207. MOUNT_POINT,
  1208. SiblingListEntry);
  1209. continue;
  1210. }
  1211. while (CurrentMount != TreeRoot) {
  1212. if (CurrentMount->SiblingListEntry.Previous !=
  1213. &(CurrentMount->Parent->ChildListHead)) {
  1214. CurrentMount = LIST_VALUE(
  1215. CurrentMount->SiblingListEntry.Previous,
  1216. MOUNT_POINT,
  1217. SiblingListEntry);
  1218. break;
  1219. }
  1220. CurrentMount = CurrentMount->Parent;
  1221. }
  1222. } while (CurrentMount != TreeRoot);
  1223. }
  1224. IsMountPointBusyEnd:
  1225. return Busy;
  1226. }
  1227. PMOUNT_POINT
  1228. IopCreateMountPoint (
  1229. PPATH_POINT Mount,
  1230. PPATH_POINT Target,
  1231. PSTR TargetPath,
  1232. ULONG TargetPathSize,
  1233. ULONG Flags
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine creates a mount point entry.
  1238. Arguments:
  1239. Mount - Supplies an optional pointer to the path point that is to be
  1240. mounted on.
  1241. Target - Supplies a pointer to the path point that is to be mounted at the
  1242. mount point.
  1243. TargetPath - Supplies a string containing the path to target.
  1244. TargetPathSize - Supplies the size of the target string, in bytes.
  1245. Flags - Supplies a bitmask of flags for the mount point. See MOUNT_FLAG_*
  1246. for definitions.
  1247. Return Value:
  1248. Returns a pointer to a new mount source on success, or NULL on failure.
  1249. --*/
  1250. {
  1251. ULONG AllocationSize;
  1252. PMOUNT_POINT MountPoint;
  1253. POBJECT_HEADER TargetRootObject;
  1254. AllocationSize = sizeof(MOUNT_POINT) + TargetPathSize;
  1255. MountPoint = MmAllocatePagedPool(AllocationSize, IO_ALLOCATION_TAG);
  1256. if (MountPoint == NULL) {
  1257. return NULL;
  1258. }
  1259. //
  1260. // With potential failures out of the way, initialize the mount point entry.
  1261. // Note that a mount point does not take a reference on its parent. It's
  1262. // the parent's duty to detect if any child mount points are present before
  1263. // being unmounted (unless it is a lazy unmount).
  1264. //
  1265. RtlZeroMemory(MountPoint, sizeof(MOUNT_POINT));
  1266. INITIALIZE_LIST_HEAD(&(MountPoint->ChildListHead));
  1267. if (Mount != NULL) {
  1268. MountPoint->Parent = Mount->MountPoint;
  1269. MountPoint->MountEntry = Mount->PathEntry;
  1270. IoPathEntryAddReference(MountPoint->MountEntry);
  1271. //
  1272. // This should not be the first mount count added to the path entry.
  1273. //
  1274. ASSERT(MountPoint->MountEntry->MountCount != 0);
  1275. IopPathEntryIncrementMountCount(MountPoint->MountEntry);
  1276. }
  1277. //
  1278. // If the target's object root is a volume, add a reference to the volume.
  1279. //
  1280. TargetRootObject = (POBJECT_HEADER)(Target->PathEntry->FileObject->Device);
  1281. if (TargetRootObject->Type == ObjectVolume) {
  1282. IoVolumeAddReference((PVOLUME)TargetRootObject);
  1283. }
  1284. MountPoint->TargetEntry = Target->PathEntry;
  1285. IoPathEntryAddReference(MountPoint->TargetEntry);
  1286. MountPoint->Flags = Flags;
  1287. MountPoint->ReferenceCount = 1;
  1288. if (TargetPathSize != 0) {
  1289. MountPoint->TargetPath = (PSTR)(MountPoint + 1);
  1290. RtlStringCopy(MountPoint->TargetPath, TargetPath, TargetPathSize);
  1291. }
  1292. return MountPoint;
  1293. }
  1294. VOID
  1295. IopDestroyMountPoint (
  1296. PMOUNT_POINT MountPoint
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine destroys a mount point, releasing any references it took.
  1301. Arguments:
  1302. MountPoint - Supplies a pointer to the mount point that is to be destroyed.
  1303. Return Value:
  1304. None.
  1305. --*/
  1306. {
  1307. POBJECT_HEADER TargetRootObject;
  1308. ASSERT(MountPoint->SiblingListEntry.Next == NULL);
  1309. ASSERT(LIST_EMPTY(&(MountPoint->ChildListHead)) != FALSE);
  1310. ASSERT(MountPoint->MountEntry != NULL);
  1311. ASSERT(MountPoint->TargetEntry != NULL);
  1312. ASSERT(MountPoint->ReferenceCount == 0);
  1313. //
  1314. // In case this is a mount point whose target's root object is a volume,
  1315. // save the target path's root object for dereferencing.
  1316. //
  1317. TargetRootObject =
  1318. (POBJECT_HEADER)(MountPoint->TargetEntry->FileObject->Device);
  1319. IoPathEntryReleaseReference(MountPoint->MountEntry);
  1320. IoPathEntryReleaseReference(MountPoint->TargetEntry);
  1321. MmFreePagedPool(MountPoint);
  1322. //
  1323. // Decrement the volume reference count.
  1324. //
  1325. if (TargetRootObject->Type == ObjectVolume) {
  1326. IoVolumeReleaseReference((PVOLUME)TargetRootObject);
  1327. }
  1328. return;
  1329. }
  1330. KSTATUS
  1331. IopCreateAndCopyMountPoint (
  1332. PPATH_POINT Mount,
  1333. PPATH_POINT Target,
  1334. PLIST_ENTRY MountList,
  1335. PSTR TargetPath,
  1336. ULONG TargetPathSize,
  1337. ULONG Flags
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. This routine creates a mount point and copies the given targets children
  1342. mount points to the new mount point, if necessary.
  1343. Arguments:
  1344. Mount - Supplies an optional pointer to the path point that is to be
  1345. mounted on.
  1346. Target - Supplies a pointer to the path point that is to be mounted at the
  1347. mount point.
  1348. MountList - Supplies a pointer to the head of the list to which any newly
  1349. created mount points will be added.
  1350. TargetPath - Supplies a string containing the path to target.
  1351. TargetPathSize - Supplies the size of the target string, in bytes.
  1352. Flags - Supplies a bitmask of flags for the mount point. See MOUNT_FLAG_*
  1353. for definitions.
  1354. Return Value:
  1355. Returns a pointer to a new mount source on success, or NULL on failure.
  1356. --*/
  1357. {
  1358. ULONG CopyFlags;
  1359. PMOUNT_POINT CurrentMount;
  1360. PMOUNT_POINT FoundMount;
  1361. PMOUNT_POINT MountPoint;
  1362. KSTATUS Status;
  1363. PMOUNT_POINT TreeRoot;
  1364. ASSERT(KeIsSharedExclusiveLockHeldExclusive(IoMountLock) != FALSE);
  1365. FoundMount = NULL;
  1366. //
  1367. // Allocate any resources that might be needed for the new mount point.
  1368. //
  1369. MountPoint = IopCreateMountPoint(Mount,
  1370. Target,
  1371. TargetPath,
  1372. TargetPathSize,
  1373. Flags);
  1374. if (MountPoint == NULL) {
  1375. Status = STATUS_INSUFFICIENT_RESOURCES;
  1376. goto CreateAndInsertMountPointEnd;
  1377. }
  1378. //
  1379. // If this is a recursive bind call, find all the mount points under the
  1380. // target mount and create the appropriate mount points under the new
  1381. // mount. Otherwise, just copy all the automatic mount points under the
  1382. // target mount.
  1383. //
  1384. if (((Flags & MOUNT_FLAG_BIND) != 0) &&
  1385. ((Flags & MOUNT_FLAG_RECURSIVE) != 0)) {
  1386. CopyFlags = 0;
  1387. } else {
  1388. CopyFlags = MOUNT_FLAG_LINKED;
  1389. }
  1390. //
  1391. // Be careful as the target may not have an associated mount point. If it
  1392. // does not, attempt to find another place it is mounted and copy that tree.
  1393. //
  1394. if (Target->MountPoint == NULL) {
  1395. ASSERT(CopyFlags == MOUNT_FLAG_LINKED);
  1396. TreeRoot = IoPathPointRoot.MountPoint;
  1397. CurrentMount = TreeRoot;
  1398. do {
  1399. if (CurrentMount->TargetEntry == Target->PathEntry) {
  1400. FoundMount = CurrentMount;
  1401. Target->MountPoint = FoundMount;
  1402. break;
  1403. }
  1404. if (LIST_EMPTY(&(CurrentMount->ChildListHead)) == FALSE) {
  1405. CurrentMount = LIST_VALUE(CurrentMount->ChildListHead.Previous,
  1406. MOUNT_POINT,
  1407. SiblingListEntry);
  1408. continue;
  1409. }
  1410. while (CurrentMount != TreeRoot) {
  1411. if (CurrentMount->SiblingListEntry.Previous !=
  1412. &(CurrentMount->Parent->ChildListHead)) {
  1413. CurrentMount = LIST_VALUE(
  1414. CurrentMount->SiblingListEntry.Previous,
  1415. MOUNT_POINT,
  1416. SiblingListEntry);
  1417. break;
  1418. }
  1419. CurrentMount = CurrentMount->Parent;
  1420. }
  1421. } while (CurrentMount != TreeRoot);
  1422. }
  1423. Status = IopCopyMountTree(MountPoint, Target, CopyFlags);
  1424. if (!KSUCCESS(Status)) {
  1425. goto CreateAndInsertMountPointEnd;
  1426. }
  1427. CreateAndInsertMountPointEnd:
  1428. if (FoundMount != NULL) {
  1429. Target->MountPoint = NULL;
  1430. }
  1431. //
  1432. // If a new mount point was created, insert it on the list of mounts, even
  1433. // if this routine failed creating a copy of its chldren. The mount point
  1434. // and its children cannot be destroyed while the mount lock is held, so it
  1435. // is up to the caller to do so.
  1436. //
  1437. if (MountPoint != NULL) {
  1438. INSERT_BEFORE(&(MountPoint->SiblingListEntry), MountList);
  1439. }
  1440. return Status;
  1441. }
  1442. KSTATUS
  1443. IopCopyMountTree (
  1444. PMOUNT_POINT NewRoot,
  1445. PPATH_POINT Target,
  1446. ULONG Flags
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. This routine copies an mount points that exist below the given target path
  1451. point to the given mount point root.
  1452. Arguments:
  1453. NewRoot - Supplies a pointer to the mount point that is the root of the new
  1454. tree.
  1455. Target - Supplies a pointer to the path point under which any mount points
  1456. are to be copied.
  1457. Flags - Supplies a bitmask of mount flags. See MOUNT_FLAG_* for definitions.
  1458. Return Value:
  1459. Status code.
  1460. --*/
  1461. {
  1462. PLIST_ENTRY CurrentEntry;
  1463. PMOUNT_POINT CurrentMount;
  1464. PATH_POINT CurrentPathPoint;
  1465. PMOUNT_POINT CurrentRoot;
  1466. BOOL DescendantPath;
  1467. PMOUNT_POINT NewMountParent;
  1468. PMOUNT_POINT NewMountPoint;
  1469. PATH_POINT NewPathPoint;
  1470. PMOUNT_POINT OldRoot;
  1471. KSTATUS Status;
  1472. ULONG TargetPathSize;
  1473. ASSERT(KeIsSharedExclusiveLockHeldExclusive(IoMountLock) != FALSE);
  1474. //
  1475. // The new root should not be live in the mount tree.
  1476. //
  1477. ASSERT(NewRoot->SiblingListEntry.Next == NULL);
  1478. OldRoot = Target->MountPoint;
  1479. if (OldRoot == NULL) {
  1480. return STATUS_SUCCESS;
  1481. }
  1482. //
  1483. // If the old root has no children, then this is quick work.
  1484. //
  1485. if (LIST_EMPTY(&(OldRoot->ChildListHead)) != FALSE) {
  1486. return STATUS_SUCCESS;
  1487. }
  1488. //
  1489. // Iterate over the list backwards. This causes older mount points to get
  1490. // inserted into the child lists before newer mount points, keeping things
  1491. // in the correct order. Acquiring the lock in shared mode is OK because
  1492. // the routine is not altering the live mount tree, just iterating over it
  1493. // to copy mount points onto a new mount tree that will be exclusively
  1494. // linked later.
  1495. //
  1496. CurrentEntry = OldRoot->ChildListHead.Previous;
  1497. while (CurrentEntry != &(OldRoot->ChildListHead)) {
  1498. CurrentRoot = LIST_VALUE(CurrentEntry, MOUNT_POINT, SiblingListEntry);
  1499. CurrentEntry = CurrentEntry->Previous;
  1500. //
  1501. // Make sure the copy flags match.
  1502. //
  1503. if ((CurrentRoot->Flags & Flags) != Flags) {
  1504. continue;
  1505. }
  1506. //
  1507. // Check to make sure this mount point is a descendant of the target
  1508. // path entry only if the target path entry isn't the root of the old
  1509. // mount point.
  1510. //
  1511. if (IO_IS_MOUNT_POINT(Target) == FALSE) {
  1512. DescendantPath = IopIsDescendantPath(Target->PathEntry,
  1513. CurrentRoot->MountEntry);
  1514. if (DescendantPath == FALSE) {
  1515. continue;
  1516. }
  1517. }
  1518. //
  1519. // Now copy the entire mount tree under the old mount point.
  1520. //
  1521. CurrentMount = CurrentRoot;
  1522. NewMountParent = NewRoot;
  1523. do {
  1524. if ((CurrentMount->Flags & Flags) == Flags) {
  1525. CurrentPathPoint.PathEntry = CurrentMount->TargetEntry;
  1526. CurrentPathPoint.MountPoint = CurrentMount;
  1527. NewPathPoint.PathEntry = CurrentMount->MountEntry;
  1528. NewPathPoint.MountPoint = NewMountParent;
  1529. TargetPathSize = RtlStringLength(CurrentMount->TargetPath) + 1;
  1530. NewMountPoint = IopCreateMountPoint(&NewPathPoint,
  1531. &CurrentPathPoint,
  1532. CurrentRoot->TargetPath,
  1533. TargetPathSize,
  1534. CurrentMount->Flags);
  1535. if (NewMountPoint == NULL) {
  1536. Status = STATUS_INSUFFICIENT_RESOURCES;
  1537. goto CopyMountTreeEnd;
  1538. }
  1539. ASSERT(NewMountPoint->Parent == NewMountParent);
  1540. INSERT_AFTER(&(NewMountPoint->SiblingListEntry),
  1541. &(NewMountParent->ChildListHead));
  1542. //
  1543. // Iterate to the current mount point's last child if it exists.
  1544. //
  1545. if (LIST_EMPTY(&(CurrentMount->ChildListHead)) == FALSE) {
  1546. CurrentMount = LIST_VALUE(
  1547. CurrentMount->ChildListHead.Previous,
  1548. MOUNT_POINT,
  1549. SiblingListEntry);
  1550. NewMountParent = NewMountPoint;
  1551. continue;
  1552. }
  1553. }
  1554. //
  1555. // Move to a sibling or ancestor's sibling.
  1556. //
  1557. while (CurrentMount != CurrentRoot) {
  1558. if (CurrentMount->SiblingListEntry.Previous !=
  1559. &(CurrentMount->Parent->ChildListHead)) {
  1560. CurrentMount = LIST_VALUE(
  1561. CurrentMount->SiblingListEntry.Previous,
  1562. MOUNT_POINT,
  1563. SiblingListEntry);
  1564. break;
  1565. }
  1566. CurrentMount = CurrentMount->Parent;
  1567. NewMountParent = NewMountParent->Parent;
  1568. }
  1569. } while (CurrentMount != CurrentRoot);
  1570. }
  1571. Status = STATUS_SUCCESS;
  1572. CopyMountTreeEnd:
  1573. return Status;
  1574. }
  1575. VOID
  1576. IopDestroyMountTree (
  1577. PMOUNT_POINT Root,
  1578. PLIST_ENTRY DestroyList
  1579. )
  1580. /*++
  1581. Routine Description:
  1582. This routine destroys the tree of mounts starting at the root. It does not
  1583. check reference counts. As such, it is useful for lazy recursive unmounts.
  1584. It appends all the destroyed mount points to the end of the given destroy
  1585. list. This transfers the original reference on the mount from the tree to
  1586. given list. The caller should iterate over the list, dereferencing each
  1587. element and decrementing the mount count.
  1588. Arguments:
  1589. Root - Supplies a pointer to the root path entry.
  1590. DestroyList - Supplies a pointer to the head of a list where all the
  1591. destroyed mount points will be placed.
  1592. Return Value:
  1593. None.
  1594. --*/
  1595. {
  1596. PLIST_ENTRY ChildEntry;
  1597. PMOUNT_POINT ChildMount;
  1598. PLIST_ENTRY CurrentEntry;
  1599. PMOUNT_POINT CurrentMount;
  1600. LIST_ENTRY ProcessList;
  1601. INITIALIZE_LIST_HEAD(&ProcessList);
  1602. //
  1603. // Add the root mount point onto the process list. Remove it from its
  1604. // parent list first. It always gets destroyed; the flags don't matter.
  1605. //
  1606. if (Root->SiblingListEntry.Next != NULL) {
  1607. LIST_REMOVE(&(Root->SiblingListEntry));
  1608. }
  1609. INSERT_BEFORE(&(Root->SiblingListEntry), &ProcessList);
  1610. //
  1611. // Now iterate over the process list, processing and adding the children of
  1612. // each element to the end of the destroy list to be processed.
  1613. //
  1614. CurrentEntry = ProcessList.Next;
  1615. while (CurrentEntry != &ProcessList) {
  1616. CurrentMount = LIST_VALUE(CurrentEntry, MOUNT_POINT, SiblingListEntry);
  1617. //
  1618. // Erase any memory of its parent now that it is out of the tree.
  1619. //
  1620. ASSERT(CurrentMount->Parent != NULL);
  1621. CurrentMount->Parent = NULL;
  1622. //
  1623. // Now process any of its children, adding them to the end of the
  1624. // list to be processed.
  1625. //
  1626. ChildEntry = CurrentMount->ChildListHead.Next;
  1627. while (ChildEntry != &(CurrentMount->ChildListHead)) {
  1628. ChildMount = LIST_VALUE(ChildEntry, MOUNT_POINT, SiblingListEntry);
  1629. ChildEntry = ChildEntry->Next;
  1630. INSERT_BEFORE(&(ChildMount->SiblingListEntry), &ProcessList);
  1631. }
  1632. //
  1633. // All the children are on the process list. Re-initialize the curent
  1634. // mount's child list.
  1635. //
  1636. INITIALIZE_LIST_HEAD(&(CurrentMount->ChildListHead));
  1637. CurrentEntry = CurrentEntry->Next;
  1638. }
  1639. //
  1640. // Now append the process list to the destroy list.
  1641. //
  1642. APPEND_LIST(&ProcessList, DestroyList);
  1643. return;
  1644. }
  1645. KSTATUS
  1646. IopLinkMountPoint (
  1647. PMOUNT_POINT MountPoint,
  1648. PPATH_POINT Target,
  1649. PLIST_ENTRY MountList
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. This routine links the given mount point to other locations in the mount
  1654. tree where its mount path entry can be found. At those locations, it will
  1655. create new mount points that join the mount path entry to the given target.
  1656. This routine assumes the global mount lock is held exclusively.
  1657. Arguments:
  1658. MountPoint - Supplies a pointer to the mount point that is to be linked.
  1659. Target - Supplies a pointer to the target path point for the linked mount
  1660. points.
  1661. MountList - Supplies a pointer to the head of the list where all newly
  1662. created mount points will be stored, on both success and failure, so
  1663. that the caller can either insert them into the live mount tree or
  1664. destroy them once the mount lock is released.
  1665. Return Value:
  1666. Status code.
  1667. --*/
  1668. {
  1669. ULONG AllocationSize;
  1670. PMOUNT_POINT *Array;
  1671. ULONG ArrayCount;
  1672. PMOUNT_POINT CurrentMount;
  1673. PPATH_ENTRY CurrentPathEntry;
  1674. ULONG Index;
  1675. PATH_POINT Mount;
  1676. ULONG MountCount;
  1677. KSTATUS Status;
  1678. PSTR TargetPath;
  1679. ULONG TargetPathSize;
  1680. PMOUNT_POINT TreeRoot;
  1681. ASSERT(KeIsSharedExclusiveLockHeldExclusive(IoMountLock) != FALSE);
  1682. ASSERT(MountPoint->Parent != NULL);
  1683. ASSERT((MountPoint->Flags & MOUNT_FLAG_LINKED) != 0);
  1684. ASSERT(MountPoint->TargetEntry == Target->PathEntry);
  1685. Array = NULL;
  1686. ArrayCount = 0;
  1687. Mount.PathEntry = NULL;
  1688. MountCount = 0;
  1689. TargetPath = MountPoint->TargetPath;
  1690. TargetPathSize = RtlStringLength(MountPoint->TargetPath) + 1;
  1691. TreeRoot = IoPathPointRoot.MountPoint;
  1692. //
  1693. // Walk up the mount point's mount path entry tree searching for other
  1694. // locations where a path element is mounted. For each mount point found,
  1695. // add a linked mount point.
  1696. //
  1697. CurrentPathEntry = MountPoint->MountEntry->Parent;
  1698. while (CurrentPathEntry != NULL) {
  1699. //
  1700. // Make the array big enough to match the number of mounts.
  1701. //
  1702. if (MountCount > ArrayCount) {
  1703. if (Array != NULL) {
  1704. MmFreePagedPool(Array);
  1705. }
  1706. ArrayCount = MountCount;
  1707. AllocationSize = ArrayCount * sizeof(MOUNT_POINT);
  1708. Array = MmAllocatePagedPool(AllocationSize, IO_ALLOCATION_TAG);
  1709. if (Array == NULL) {
  1710. Status = STATUS_INSUFFICIENT_RESOURCES;
  1711. goto LinkMountPointEnd;
  1712. }
  1713. }
  1714. //
  1715. // Find the mounts that target the current path entry. Skip the given
  1716. // mount's parent to avoid duplicates.
  1717. //
  1718. MountCount = 0;
  1719. CurrentMount = TreeRoot;
  1720. do {
  1721. if ((CurrentMount->TargetEntry == CurrentPathEntry) &&
  1722. (CurrentMount != MountPoint->Parent)) {
  1723. if (MountCount < ArrayCount) {
  1724. Array[MountCount] = CurrentMount;
  1725. }
  1726. MountCount += 1;
  1727. }
  1728. if (LIST_EMPTY(&(CurrentMount->ChildListHead)) == FALSE) {
  1729. CurrentMount = LIST_VALUE(CurrentMount->ChildListHead.Previous,
  1730. MOUNT_POINT,
  1731. SiblingListEntry);
  1732. continue;
  1733. }
  1734. while (CurrentMount != TreeRoot) {
  1735. if (CurrentMount->SiblingListEntry.Previous !=
  1736. &(CurrentMount->Parent->ChildListHead)) {
  1737. CurrentMount = LIST_VALUE(
  1738. CurrentMount->SiblingListEntry.Previous,
  1739. MOUNT_POINT,
  1740. SiblingListEntry);
  1741. break;
  1742. }
  1743. CurrentMount = CurrentMount->Parent;
  1744. }
  1745. } while (CurrentMount != TreeRoot);
  1746. //
  1747. // Skip to the next path entry if no mount points were found.
  1748. //
  1749. if (MountCount == 0) {
  1750. CurrentPathEntry = CurrentPathEntry->Parent;
  1751. continue;
  1752. }
  1753. //
  1754. // If the mount count is greater than the array count, then the array
  1755. // was not big enough. Try again with the appropriate sized array.
  1756. //
  1757. if (MountCount > ArrayCount) {
  1758. continue;
  1759. }
  1760. //
  1761. // For each mount point in the array, create and insert a new mount
  1762. // point below the current mount point and on top of the same path
  1763. // entry as the given mount. The new mounts are added to the mount list
  1764. // and will be inserted into the live mount tree by the caller.
  1765. //
  1766. for (Index = 0; Index < MountCount; Index += 1) {
  1767. Mount.PathEntry = MountPoint->MountEntry;
  1768. Mount.MountPoint = Array[Index];
  1769. Status = IopCreateAndCopyMountPoint(&Mount,
  1770. Target,
  1771. MountList,
  1772. TargetPath,
  1773. TargetPathSize,
  1774. MountPoint->Flags);
  1775. if (!KSUCCESS(Status)) {
  1776. goto LinkMountPointEnd;
  1777. }
  1778. }
  1779. CurrentPathEntry = CurrentPathEntry->Parent;
  1780. }
  1781. Status = STATUS_SUCCESS;
  1782. LinkMountPointEnd:
  1783. if (Array != NULL) {
  1784. MmFreePagedPool(Array);
  1785. }
  1786. return Status;
  1787. }
  1788. VOID
  1789. IopDestroyLinkedMountPoints (
  1790. PMOUNT_POINT Mount,
  1791. PLIST_ENTRY DestroyList
  1792. )
  1793. /*++
  1794. Routine Description:
  1795. This routine destroys any mount points linked to the given mount point.
  1796. Arguments:
  1797. Mount - Supplies a pointer to the mount point whose linked mounts are to
  1798. be destroyed.
  1799. DestroyList - Supplies a pointer to the head of a list where all the
  1800. destroyed mount points will be placed.
  1801. Return Value:
  1802. None.
  1803. --*/
  1804. {
  1805. PMOUNT_POINT CurrentMount;
  1806. PMOUNT_POINT NextMount;
  1807. PMOUNT_POINT TreeRoot;
  1808. TreeRoot = IoPathPointRoot.MountPoint;
  1809. //
  1810. // Iterate over the tree of mount points starting at the root in search of
  1811. // linked mount points that have a target path entry matching that of the
  1812. // given mount point.
  1813. //
  1814. CurrentMount = TreeRoot;
  1815. do {
  1816. if ((CurrentMount->TargetEntry == Mount->TargetEntry) &&
  1817. ((CurrentMount->Flags & MOUNT_FLAG_LINKED) != 0)) {
  1818. //
  1819. // This mount point is about to be removed from the tree. Get its
  1820. // next sibling or one if its ancestor's siblings.
  1821. //
  1822. NextMount = CurrentMount;
  1823. while (NextMount != TreeRoot) {
  1824. if (NextMount->SiblingListEntry.Previous !=
  1825. &(NextMount->Parent->ChildListHead)) {
  1826. NextMount = LIST_VALUE(NextMount->SiblingListEntry.Previous,
  1827. MOUNT_POINT,
  1828. SiblingListEntry);
  1829. break;
  1830. }
  1831. NextMount = NextMount->Parent;
  1832. }
  1833. IopDestroyMountTree(CurrentMount, DestroyList);
  1834. CurrentMount = NextMount;
  1835. //
  1836. // Check the children for any linked mount points.
  1837. //
  1838. } else if (LIST_EMPTY(&(CurrentMount->ChildListHead)) == FALSE) {
  1839. CurrentMount = LIST_VALUE(CurrentMount->ChildListHead.Previous,
  1840. MOUNT_POINT,
  1841. SiblingListEntry);
  1842. //
  1843. // Otherwise back up to a sibling or ancestor's sibling.
  1844. //
  1845. } else {
  1846. while (CurrentMount != TreeRoot) {
  1847. if (CurrentMount->SiblingListEntry.Previous !=
  1848. &(CurrentMount->Parent->ChildListHead)) {
  1849. CurrentMount = LIST_VALUE(
  1850. CurrentMount->SiblingListEntry.Previous,
  1851. MOUNT_POINT,
  1852. SiblingListEntry);
  1853. break;
  1854. }
  1855. CurrentMount = CurrentMount->Parent;
  1856. }
  1857. }
  1858. } while (CurrentMount != TreeRoot);
  1859. return;
  1860. }
  1861. KSTATUS
  1862. IopGetMountPointsFromTree (
  1863. PPATH_POINT ProcessRoot,
  1864. PMOUNT_POINT TreeRoot,
  1865. PVOID *BufferOffset,
  1866. PUINTN BytesRemaining,
  1867. PUINTN RequiredSize
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. This routine converts all the mount points in the given mount tree into
  1872. mount point entries. That is, it collects the mount point and target paths
  1873. and stores them into the given buffer starting at the given offset.
  1874. Arguments:
  1875. ProcessRoot - Supplies the root path point of the calling process.
  1876. TreeRoot - Supplies the root mount point of the mount tree that is to be
  1877. converted.
  1878. BufferOffset - Supplies a pointer to the buffer that is to store the
  1879. converted data. This routine increments the pointer as it writes to the
  1880. buffer.
  1881. BytesRemaining - Supplies a pointer to the number of bytes remaining in the
  1882. given buffer. This routine decrements the bytes remaining if it writes
  1883. to the buffer.
  1884. RequiredSize - Supplies a pointer that receives the total number of bytes
  1885. required to convert the given mount tree.
  1886. Return Value:
  1887. Status code.
  1888. --*/
  1889. {
  1890. PSTR Destination;
  1891. PMOUNT_POINT MountPoint;
  1892. PMOUNT_POINT_ENTRY MountPointEntry;
  1893. UINTN MountPointEntrySize;
  1894. PSTR MountPointPath;
  1895. UINTN MountPointPathSize;
  1896. PATH_POINT PathPoint;
  1897. KSTATUS Status;
  1898. UINTN TargetPathSize;
  1899. *RequiredSize = 0;
  1900. MountPointPath = NULL;
  1901. //
  1902. // Iterate over the tree of mount points starting at the root.
  1903. //
  1904. MountPoint = TreeRoot;
  1905. do {
  1906. //
  1907. // Get the path to the mount point.
  1908. //
  1909. PathPoint.PathEntry = MountPoint->TargetEntry;
  1910. PathPoint.MountPoint = MountPoint;
  1911. Status = IopGetPathFromRootUnlocked(&PathPoint,
  1912. ProcessRoot,
  1913. &MountPointPath,
  1914. &MountPointPathSize);
  1915. if (!KSUCCESS(Status)) {
  1916. goto GetMountPointsFromTreeEnd;
  1917. }
  1918. //
  1919. // Calculate the size of this mount point.
  1920. //
  1921. ASSERT(MountPoint->TargetPath != NULL);
  1922. TargetPathSize = RtlStringLength(MountPoint->TargetPath) + 1;
  1923. MountPointEntrySize = sizeof(MOUNT_POINT_ENTRY) +
  1924. MountPointPathSize +
  1925. TargetPathSize;
  1926. //
  1927. // Write the mount point to the buffer if it is big enough.
  1928. //
  1929. if (*BytesRemaining >= MountPointEntrySize) {
  1930. MountPointEntry = (PMOUNT_POINT_ENTRY)*BufferOffset;
  1931. MountPointEntry->Flags = 0;
  1932. if ((MountPoint->Flags & MOUNT_FLAG_BIND) != 0) {
  1933. MountPointEntry->Flags |= SYS_MOUNT_FLAG_BIND;
  1934. }
  1935. if ((MountPoint->Flags & MOUNT_FLAG_RECURSIVE) != 0) {
  1936. MountPointEntry->Flags |= SYS_MOUNT_FLAG_RECURSIVE;
  1937. }
  1938. if ((MountPoint->TargetEntry->Parent != NULL) &&
  1939. (MountPoint->TargetEntry->SiblingListEntry.Next == NULL)) {
  1940. MountPointEntry->Flags |= SYS_MOUNT_FLAG_TARGET_UNLINKED;
  1941. }
  1942. MountPointEntry->MountPointPathOffset = sizeof(MOUNT_POINT_ENTRY);
  1943. MountPointEntry->TargetPathOffset = sizeof(MOUNT_POINT_ENTRY) +
  1944. MountPointPathSize;
  1945. Destination = (PVOID)MountPointEntry +
  1946. MountPointEntry->MountPointPathOffset;
  1947. RtlStringCopy(Destination, MountPointPath, MountPointPathSize);
  1948. Destination = (PVOID)MountPointEntry +
  1949. MountPointEntry->TargetPathOffset;
  1950. RtlStringCopy(Destination, MountPoint->TargetPath, TargetPathSize);
  1951. *BufferOffset += MountPointEntrySize;
  1952. *BytesRemaining -= MountPointEntrySize;
  1953. }
  1954. //
  1955. // Release the target path.
  1956. //
  1957. MmFreePagedPool(MountPointPath);
  1958. MountPointPath = NULL;
  1959. //
  1960. // Even if the buffer is not big enough, increment the required size
  1961. // and continue.
  1962. //
  1963. *RequiredSize += MountPointEntrySize;
  1964. //
  1965. // If the current mount point has children, then the next mount point
  1966. // is the first child.
  1967. //
  1968. if (LIST_EMPTY(&(MountPoint->ChildListHead)) == FALSE) {
  1969. MountPoint = LIST_VALUE(MountPoint->ChildListHead.Previous,
  1970. MOUNT_POINT,
  1971. SiblingListEntry);
  1972. continue;
  1973. }
  1974. //
  1975. // Otherwise get the next sibling or ancestor's sibling.
  1976. //
  1977. while (MountPoint != TreeRoot) {
  1978. if (MountPoint->SiblingListEntry.Previous !=
  1979. &(MountPoint->Parent->ChildListHead)) {
  1980. MountPoint = LIST_VALUE(MountPoint->SiblingListEntry.Previous,
  1981. MOUNT_POINT,
  1982. SiblingListEntry);
  1983. break;
  1984. }
  1985. MountPoint = MountPoint->Parent;
  1986. }
  1987. } while (MountPoint != TreeRoot);
  1988. Status = STATUS_SUCCESS;
  1989. GetMountPointsFromTreeEnd:
  1990. if (MountPointPath != NULL) {
  1991. MmFreePagedPool(MountPointPath);
  1992. }
  1993. return Status;
  1994. }