Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

809 lines
23 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: prefix.c
  7. //
  8. // Contents: PREFIX table implementation
  9. //
  10. // History: SethuR -- Implemented
  11. //
  12. // Notes:
  13. //
  14. //--------------------------------------------------------------------------
  15. #ifdef KERNEL_MODE
  16. #include <dfsprocs.h>
  17. #define Dbg DEBUG_TRACE_RTL
  18. #else
  19. #define DebugTrace(x,y,z,a)
  20. #endif
  21. #include <prefix.h>
  22. #include <prefixp.h>
  23. PDFS_PREFIX_TABLE_ENTRY
  24. DfspNextUnicodeTableEntry(
  25. IN PDFS_PREFIX_TABLE_ENTRY pEntry);
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text( PAGE, DfsInitializePrefixTable )
  28. #pragma alloc_text( PAGE, DfsFreePrefixTable )
  29. #pragma alloc_text( PAGE, DfsInsertInPrefixTable )
  30. #pragma alloc_text( PAGE, DfsLookupPrefixTable )
  31. #pragma alloc_text( PAGE, DfsFindUnicodePrefix )
  32. #pragma alloc_text( PAGE, DfsRemoveFromPrefixTable )
  33. #pragma alloc_text( PAGE, RemoveFirstComponent )
  34. #endif // ALLOC_PRAGMA
  35. //+---------------------------------------------------------------------------
  36. //
  37. // Function: DfsInitializePrefixTable
  38. //
  39. // Synopsis: API for initializing the prefix table
  40. //
  41. // Arguments: [pTable] -- the DFS prefix table instance
  42. //
  43. // Returns: one of the following NTSTATUS codes
  44. // STATUS_SUCCESS -- call was successfull.
  45. //
  46. // History: 04-18-94 SethuR Created
  47. //
  48. // Notes:
  49. //
  50. //----------------------------------------------------------------------------
  51. NTSTATUS
  52. DfsInitializePrefixTable(
  53. PDFS_PREFIX_TABLE pTable,
  54. BOOLEAN fCaseSensitive)
  55. {
  56. NTSTATUS status = STATUS_SUCCESS;
  57. DebugTrace(+1, Dbg,"DfsInitializePrefixTable -- Entry\n", 0);
  58. if (pTable != NULL)
  59. {
  60. ULONG i;
  61. // Initialize flags
  62. pTable->CaseSensitive = fCaseSensitive;
  63. // Initialize the root entry
  64. INITIALIZE_PREFIX_TABLE_ENTRY(&pTable->RootEntry);
  65. // Initialize the various buckets.
  66. for (i = 0;i < NO_OF_HASH_BUCKETS;i++)
  67. {
  68. INITIALIZE_BUCKET(pTable->Buckets[i]);
  69. }
  70. // Initialize the name page list.
  71. pTable->NamePageList.pFirstPage = ALLOCATE_NAME_PAGE();
  72. if (pTable->NamePageList.pFirstPage != NULL)
  73. {
  74. INITIALIZE_NAME_PAGE(pTable->NamePageList.pFirstPage);
  75. // Initialize the prefix table entry allocation mechanism.
  76. status = _InitializePrefixTableEntryAllocation(pTable);
  77. }
  78. else
  79. {
  80. status = STATUS_NO_MEMORY;
  81. DebugTrace(0, Dbg,"DfsInitializePrefixTable Error -- %lx\n", ULongToPtr( status ));
  82. }
  83. }
  84. else
  85. {
  86. status = STATUS_INVALID_PARAMETER;
  87. DebugTrace(0, Dbg,"DfsInitializePrefixTable Error -- %lx\n", ULongToPtr( status ));
  88. }
  89. DebugTrace(-1, Dbg, "DfsInitializePrefixTable -- Exit\n", 0);
  90. return status;
  91. }
  92. //+---------------------------------------------------------------------------
  93. //
  94. // Function: DfsFreePrefixTable
  95. //
  96. // Synopsis: API for freeing a prefix table
  97. //
  98. // Arguments: [pTable] -- the DFS prefix table instance
  99. //
  100. // Returns: one of the following NTSTATUS codes
  101. // STATUS_SUCCESS -- call was successfull.
  102. //
  103. // History: 08-01-99 JHarper Created
  104. //
  105. // Notes:
  106. //
  107. //----------------------------------------------------------------------------
  108. NTSTATUS
  109. DfsFreePrefixTable(
  110. PDFS_PREFIX_TABLE pTable)
  111. {
  112. NTSTATUS status = STATUS_SUCCESS;
  113. PNAME_PAGE pNamePage = NULL;
  114. PNAME_PAGE pNextPage = NULL;
  115. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  116. PDFS_PREFIX_TABLE_ENTRY pSentinelEntry = NULL;
  117. ULONG i;
  118. DebugTrace(+1, Dbg,"DfsFreePrefixTable -- Entry\n", 0);
  119. if (pTable != NULL) {
  120. for (i = 0; i < NO_OF_HASH_BUCKETS; i++) {
  121. pSentinelEntry = &pTable->Buckets[i].SentinelEntry;
  122. while (pSentinelEntry->pNextEntry != pSentinelEntry) {
  123. pEntry = pSentinelEntry->pNextEntry;
  124. REMOVE_FROM_BUCKET(pEntry);
  125. if (pEntry->PathSegment.Buffer != NULL)
  126. ExFreePool(pEntry->PathSegment.Buffer);
  127. ExFreePool(pEntry);
  128. }
  129. pTable->Buckets[i].NoOfEntries = 0;
  130. }
  131. if (pTable->RootEntry.PathSegment.Buffer != NULL)
  132. ExFreePool(pTable->RootEntry.PathSegment.Buffer);
  133. for (pNamePage = pTable->NamePageList.pFirstPage;
  134. pNamePage;
  135. pNamePage = pNextPage
  136. ) {
  137. pNextPage = pNamePage->pNextPage;
  138. ExFreePool(pNamePage);
  139. }
  140. } else {
  141. status = STATUS_INVALID_PARAMETER;
  142. DebugTrace(0, Dbg,"DfsFreePrefixTable Error -- %lx\n", ULongToPtr( status ));
  143. }
  144. DebugTrace(-1, Dbg, "DfsFreePrefixTable -- Exit\n", 0);
  145. return status;
  146. }
  147. //+---------------------------------------------------------------------------
  148. //
  149. // Function: DfsInsertInPrefixTable
  150. //
  151. // Synopsis: API for inserting a path in the prefix table
  152. //
  153. // Arguments: [pTable] -- the DFS prefix table instance
  154. //
  155. // [pPath] -- the path to be looked up.
  156. //
  157. // [pData] -- BLOB associated with the path
  158. //
  159. // Returns: one of the following NTSTATUS codes
  160. // STATUS_SUCCESS -- call was successfull.
  161. //
  162. // History: 04-18-94 SethuR Created
  163. //
  164. // Notes:
  165. //
  166. //----------------------------------------------------------------------------
  167. NTSTATUS
  168. DfsInsertInPrefixTable(
  169. PDFS_PREFIX_TABLE pTable,
  170. PUNICODE_STRING pPath,
  171. PVOID pData)
  172. {
  173. NTSTATUS status = STATUS_SUCCESS;
  174. WCHAR Buffer[MAX_PATH_SEGMENT_SIZE];
  175. PWCHAR NameBuffer = Buffer;
  176. USHORT cbNameBuffer = sizeof(Buffer);
  177. UNICODE_STRING Path,Name;
  178. ULONG BucketNo;
  179. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  180. PDFS_PREFIX_TABLE_ENTRY pParentEntry = NULL;
  181. BOOLEAN fNameFound = FALSE;
  182. BOOLEAN pEntryAllocated = FALSE;
  183. DebugTrace(+1, Dbg, "DfsInsertInPrefixTable -- Entry\n", 0);
  184. RemoveFirstComponent(pPath, &Path);
  185. // There is one special case, i.e., in which the prefix is '\'.
  186. // Since this is the PATH_DELIMITER which is treated in a special
  187. // way, we do the processing upfront.
  188. if (Path.Length == 0)
  189. {
  190. return STATUS_SUCCESS;
  191. }
  192. else if ((Path.Length == sizeof(WCHAR)) &&
  193. (Path.Buffer[0] == PATH_DELIMITER))
  194. {
  195. pTable->RootEntry.pData = pData;
  196. return STATUS_SUCCESS;
  197. }
  198. else
  199. {
  200. Path.Length -= sizeof(WCHAR);
  201. Path.MaximumLength = Path.MaximumLength;
  202. Path.Buffer++;
  203. pParentEntry = &pTable->RootEntry;
  204. }
  205. if (Path.Length > MAX_PATH_SEGMENT_SIZE * sizeof(WCHAR) ) {
  206. NameBuffer = ExAllocatePoolWithTag( NonPagedPool, Path.Length + sizeof(WCHAR), ' sfD' );
  207. if (NameBuffer == NULL) {
  208. DebugTrace(0, Dbg, "Unable to allocate %d non-paged bytes\n", (Path.Length + sizeof(WCHAR)) );
  209. return( STATUS_INSUFFICIENT_RESOURCES );
  210. } else {
  211. cbNameBuffer = Path.Length + sizeof(WCHAR);
  212. }
  213. }
  214. while (Path.Length > 0)
  215. {
  216. Name.Length = 0;
  217. Name.Buffer = NameBuffer;
  218. Name.MaximumLength = cbNameBuffer;
  219. // Process the name segment
  220. if (pTable->CaseSensitive)
  221. {
  222. SPLIT_CASE_SENSITIVE_PATH(&Path,&Name,BucketNo);
  223. }
  224. else
  225. {
  226. SPLIT_CASE_INSENSITIVE_PATH(&Path,&Name,BucketNo);
  227. }
  228. if (Name.Length > 0)
  229. {
  230. // Lookup the table to see if the name segment already exists.
  231. DebugTrace(0, Dbg, "LOOKUP_BUCKET: Bucket(%ld)\n", ULongToPtr( BucketNo ));
  232. DebugTrace(0, Dbg, " for Name(%wZ)\n", &Name);
  233. LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
  234. DebugTrace(0, Dbg, "returned pEntry(%lx)", pEntry);
  235. DebugTrace(0, Dbg, " fNameFound(%s)\n", fNameFound ? "TRUE" : "FALSE");
  236. if (pEntry == NULL)
  237. {
  238. // Initialize the new entry and initialize the name segment.
  239. pEntry = ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable);
  240. if (pEntry != NULL)
  241. {
  242. pEntryAllocated = TRUE;
  243. INITIALIZE_PREFIX_TABLE_ENTRY(pEntry);
  244. // Allocate the name space entry if there is no entry in the
  245. // name page.
  246. if (!fNameFound || fNameFound)
  247. {
  248. PWSTR pBuffer;
  249. // Allocate the entry in the name page.
  250. pBuffer = ALLOCATE_NAME_PAGE_ENTRY((pTable->NamePageList),(Name.Length/sizeof(WCHAR)));
  251. if (pBuffer != NULL)
  252. {
  253. RtlCopyMemory(pBuffer,Name.Buffer,Name.Length);
  254. pEntry->PathSegment = Name;
  255. pEntry->PathSegment.Buffer = pBuffer;
  256. }
  257. else
  258. {
  259. status = STATUS_NO_MEMORY;
  260. break;
  261. }
  262. }
  263. else
  264. pEntry->PathSegment = Name;
  265. // thread the entry to point to the parent.
  266. pEntry->pParentEntry = pParentEntry;
  267. // Insert the entry in the bucket.
  268. INSERT_IN_BUCKET(pTable->Buckets[BucketNo],pEntry);
  269. // Insert the entry in the parent's children list.
  270. INSERT_IN_CHILD_LIST(pEntry, pParentEntry);
  271. }
  272. else
  273. {
  274. status = STATUS_NO_MEMORY;
  275. DebugTrace(0, Dbg, "DfsInsertInPrefixTable Error -- %lx\n", ULongToPtr( status ));
  276. break;
  277. }
  278. }
  279. else
  280. {
  281. // Increment the no. of children associated with this entry
  282. pEntry->NoOfChildren++;
  283. }
  284. pParentEntry = pEntry;
  285. pEntryAllocated = FALSE;
  286. }
  287. else
  288. {
  289. status = STATUS_INVALID_PARAMETER;
  290. DebugTrace(0, Dbg, "DfsInsertInPrefixTable Error -- %lx\n", ULongToPtr( status ));
  291. break;
  292. }
  293. }
  294. // If a new entry was not successfully inserted we need to walk up the chain
  295. // of parent entries to undo the increment to the reference count and
  296. // remove the entries from their parent links.
  297. if (NT_SUCCESS(status))
  298. {
  299. // The entry was successfully inserted in the prefix table. Update
  300. // the data (BLOB) associated with it.
  301. // We do it outside the loop to prevent redundant comparisons within
  302. // the loop.
  303. if (pEntry != NULL) {
  304. pEntry->pData = pData;
  305. }
  306. }
  307. else
  308. {
  309. while (pParentEntry != NULL)
  310. {
  311. PDFS_PREFIX_TABLE_ENTRY pMaybeTempEntry;
  312. pMaybeTempEntry = pParentEntry;
  313. pParentEntry = pParentEntry->pParentEntry;
  314. if (--pMaybeTempEntry->NoOfChildren == 0) {
  315. //
  316. // If pParentEntry == NULL, pMaybeTempEntry is
  317. // pTable->RootEntry. Do not try to remove it.
  318. //
  319. if (pParentEntry != NULL) {
  320. REMOVE_FROM_CHILD_LIST(pMaybeTempEntry);
  321. REMOVE_FROM_BUCKET(pMaybeTempEntry);
  322. FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pMaybeTempEntry);
  323. }
  324. }
  325. }
  326. if (pEntryAllocated) {
  327. FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pEntry);
  328. }
  329. }
  330. if (NameBuffer != Buffer) {
  331. ExFreePool( NameBuffer );
  332. }
  333. DebugTrace(-1, Dbg, "DfsInsertInPrefixTable -- Exit\n", 0);
  334. return status;
  335. }
  336. //+---------------------------------------------------------------------------
  337. //
  338. // Function: DfsLookupPrefixTable
  339. //
  340. // Synopsis: private fn. for looking up a name segment in a prefix table
  341. //
  342. // Arguments: [pTable] -- the DFS prefix table instance
  343. //
  344. // [pPath] -- the path to be looked up.
  345. //
  346. // [pSuffix] -- the suffix that could not be found.
  347. //
  348. // [ppData] -- placeholder for the BLOB for the prefix.
  349. //
  350. //
  351. // Returns: one of the following NTSTATUS codes
  352. // STATUS_SUCCESS -- call was successfull.
  353. // STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
  354. //
  355. // History: 04-18-94 SethuR Created
  356. //
  357. // Notes:
  358. //
  359. //----------------------------------------------------------------------------
  360. NTSTATUS
  361. DfsLookupPrefixTable(
  362. PDFS_PREFIX_TABLE pTable,
  363. PUNICODE_STRING pPath,
  364. PUNICODE_STRING pSuffix,
  365. PVOID *ppData)
  366. {
  367. NTSTATUS status = STATUS_SUCCESS;
  368. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  369. UNICODE_STRING Path;
  370. DebugTrace(+1, Dbg, "DfsLookupInPrefixTable -- Entry\n", 0);
  371. RemoveFirstComponent(pPath, &Path);
  372. if (Path.Length == 0)
  373. {
  374. DebugTrace(-1, Dbg, "DfsLookupInPrefixTable Exited - Null Path!\n", 0);
  375. return STATUS_SUCCESS;
  376. }
  377. status = _LookupPrefixTable(pTable,&Path,pSuffix,&pEntry);
  378. // Update the BLOB placeholder with the results of the lookup.
  379. if (NT_SUCCESS(status))
  380. {
  381. *ppData = pEntry->pData;
  382. }
  383. DebugTrace(-1, Dbg, "DfsLookupInPrefixTable -- Exit\n", 0);
  384. return status;
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Function: DfsFindUnicodePrefix
  389. //
  390. // Synopsis: fn. for looking up a name segment in a prefix table
  391. //
  392. // Arguments: [pTable] -- the DFS prefix table instance
  393. //
  394. // [pPath] -- the path to be looked up.
  395. //
  396. // [pSuffix] -- the suffix that could not be found.
  397. //
  398. // Returns: a valid ptr if successfull, NULL otherwise
  399. //
  400. // History: 04-18-94 SethuR Created
  401. //
  402. // Notes:
  403. //
  404. //----------------------------------------------------------------------------
  405. PVOID
  406. DfsFindUnicodePrefix(
  407. PDFS_PREFIX_TABLE pTable,
  408. PUNICODE_STRING pPath,
  409. PUNICODE_STRING pSuffix)
  410. {
  411. NTSTATUS status = STATUS_SUCCESS;
  412. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  413. PVOID pData = NULL;
  414. UNICODE_STRING Path;
  415. DebugTrace(+1, Dbg, "DfsFindUnicodePrefix -- Entry\n", 0);
  416. RemoveFirstComponent(pPath, &Path);
  417. if (Path.Length == 0)
  418. {
  419. DebugTrace(-1, Dbg, "DfsFindUnicodePrefix Exited - Null Path!\n", 0);
  420. return NULL;
  421. }
  422. else
  423. {
  424. status = _LookupPrefixTable(pTable,&Path,pSuffix,&pEntry);
  425. // Update the BLOB placeholder with the results of the lookup.
  426. if (NT_SUCCESS(status))
  427. {
  428. pData = pEntry->pData;
  429. }
  430. DebugTrace(-1, Dbg, "DfsFindUnicodePrefix -- Exit\n", 0);
  431. return pData;
  432. }
  433. }
  434. //+---------------------------------------------------------------------------
  435. //
  436. // Function: DfsRemoveFromPrefixTable
  437. //
  438. // Synopsis: private fn. for looking up a name segment in a prefix table
  439. //
  440. // Arguments: [pTable] -- the DFS prefix table instance
  441. //
  442. // [pPath] -- the path to be looked up.
  443. //
  444. // Returns: one of the following NTSTATUS codes
  445. // STATUS_SUCCESS -- call was successfull.
  446. // STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
  447. //
  448. // History: 04-18-94 SethuR Created
  449. //
  450. // Notes:
  451. //
  452. //----------------------------------------------------------------------------
  453. NTSTATUS
  454. DfsRemoveFromPrefixTable(
  455. PDFS_PREFIX_TABLE pTable,
  456. PUNICODE_STRING pPath)
  457. {
  458. NTSTATUS status = STATUS_SUCCESS;
  459. UNICODE_STRING Path,Suffix;
  460. ULONG BucketNo;
  461. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  462. DebugTrace(+1, Dbg, "DfsRemoveFromPrefixTable -- Entry\n", 0);
  463. Suffix.Length = 0;
  464. Suffix.Buffer = NULL;
  465. RemoveFirstComponent(pPath, &Path);
  466. if (Path.Length == 0)
  467. {
  468. DebugTrace(-1, Dbg, "DfsRemoveFromPrefixTable Exited -- Null Path!\n", 0);
  469. return STATUS_SUCCESS;
  470. }
  471. else if ((Path.Length == sizeof(WCHAR)) &&
  472. (Path.Buffer[0] == PATH_DELIMITER))
  473. {
  474. if (pTable->RootEntry.pData == NULL)
  475. {
  476. status = STATUS_OBJECT_PATH_NOT_FOUND;
  477. }
  478. else
  479. {
  480. pTable->RootEntry.pData = NULL;
  481. DebugTrace(-1, Dbg, "DfsRemoveFromPrefixTable Exited.\n", 0);
  482. return STATUS_SUCCESS;
  483. }
  484. }
  485. else
  486. {
  487. Path.Length -= sizeof(WCHAR);
  488. Path.MaximumLength = Path.Length;
  489. Path.Buffer++;
  490. status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry);
  491. if (NT_SUCCESS(status) && (Suffix.Length == 0))
  492. {
  493. // Destroy the association between the data associated with
  494. // this prefix.
  495. pEntry->pData = NULL;
  496. // found an exact match for the given path name in the table.
  497. // traverse the list of parent pointers and delete them if
  498. // required.
  499. while (pEntry != NULL)
  500. {
  501. if ((--pEntry->NoOfChildren) == 0)
  502. {
  503. PDFS_PREFIX_TABLE_ENTRY pTempEntry = pEntry;
  504. pEntry = pEntry->pParentEntry;
  505. //
  506. // pEntry == NULL means pTempEntry is pTable->RootEntry.
  507. // Do not try to remove it.
  508. //
  509. if (pEntry != NULL) {
  510. REMOVE_FROM_CHILD_LIST(pTempEntry);
  511. REMOVE_FROM_BUCKET(pTempEntry);
  512. FREE_DFS_PREFIX_TABLE_ENTRY(pTable,pTempEntry);
  513. }
  514. }
  515. else
  516. break;
  517. }
  518. }
  519. }
  520. DebugTrace(-1, Dbg, "DfsRemoveFromPrefixTable -- Exit\n", 0);
  521. return status;
  522. }
  523. //+----------------------------------------------------------------------------
  524. //
  525. // Function: DfsNextUnicodePrefix
  526. //
  527. // Synopsis: Enumerates the entries in the table in ordered fashion.
  528. // Note that state is maintained between calls to
  529. // DfsNextUnicodePrefix - the caller must ensure that the table
  530. // is not modified between calls to DfsNextUnicodePrefix.
  531. //
  532. // Arguments: [pTable] -- The table to enumerate over.
  533. // [fRestart] -- If TRUE, starts the enumeration. If FALSE,
  534. // continues from where the enumeration left off.
  535. //
  536. // Returns: Valid pointer to data associated with the next Prefix Table
  537. // entry, or NULL if at the end of the enumeration.
  538. //
  539. //
  540. //-----------------------------------------------------------------------------
  541. PVOID DfsNextUnicodePrefix(
  542. IN PDFS_PREFIX_TABLE pTable,
  543. IN BOOLEAN fRestart)
  544. {
  545. PDFS_PREFIX_TABLE_ENTRY pEntry, pNextEntry;
  546. if (fRestart) {
  547. pNextEntry = &pTable->RootEntry;
  548. while (pNextEntry != NULL && pNextEntry->pData == NULL) {
  549. pNextEntry = DfspNextUnicodeTableEntry( pNextEntry );
  550. }
  551. } else {
  552. pNextEntry = pTable->NextEntry;
  553. }
  554. pEntry = pNextEntry;
  555. if (pNextEntry != NULL) {
  556. do {
  557. pNextEntry = DfspNextUnicodeTableEntry( pNextEntry );
  558. } while ( pNextEntry != NULL && pNextEntry->pData == NULL );
  559. pTable->NextEntry = pNextEntry;
  560. }
  561. if (pEntry != NULL) {
  562. return( pEntry->pData );
  563. } else {
  564. return( NULL );
  565. }
  566. }
  567. //+----------------------------------------------------------------------------
  568. //
  569. // Function: DfspNextUnicodeTableEntry
  570. //
  571. // Synopsis: Given a pointer to a Prefix Table Entry, this function will
  572. // return a pointer to the "next" prefix table entry.
  573. //
  574. // The "next" entry is chosen as follows:
  575. // If the start entry has a valid child, the child is
  576. // is returned.
  577. // else if the start entry has a valid sibling, the sibling
  578. // is returned
  579. // else the first valid sibling of the closest ancestor is
  580. // returned.
  581. //
  582. // Arguments: [pEntry] -- The entry to start from.
  583. //
  584. // Returns: Pointer to the next DFS_PREFIX_TABLE_ENTRY that has a valid
  585. // pData, or NULL if there are no more entries.
  586. //
  587. //-----------------------------------------------------------------------------
  588. PDFS_PREFIX_TABLE_ENTRY
  589. DfspNextUnicodeTableEntry(
  590. IN PDFS_PREFIX_TABLE_ENTRY pEntry)
  591. {
  592. PDFS_PREFIX_TABLE_ENTRY pNextEntry;
  593. if (pEntry->pFirstChildEntry != NULL) {
  594. pNextEntry = pEntry->pFirstChildEntry;
  595. } else if (pEntry->pSiblingEntry != NULL) {
  596. pNextEntry = pEntry->pSiblingEntry;
  597. } else {
  598. for (pNextEntry = pEntry->pParentEntry;
  599. pNextEntry != NULL && pNextEntry->pSiblingEntry == NULL;
  600. pNextEntry = pNextEntry->pParentEntry) {
  601. NOTHING;
  602. }
  603. if (pNextEntry != NULL) {
  604. pNextEntry = pNextEntry->pSiblingEntry;
  605. }
  606. }
  607. return( pNextEntry );
  608. }
  609. //+----------------------------------------------------------------------------
  610. //
  611. // Function: DfsNextUnicodePrefixChild
  612. //
  613. // Synopsis: Enumerates the immediate children of a given prefix.
  614. //
  615. // Arguments: [pTable] -- The DFS prefix table to use.
  616. // [pPath] -- The prefix whose children are to be enumerated.
  617. // [pCookie] -- On first call, this point to a NULL. On return,
  618. // it will be set to a cookie that should be returned
  619. // on subsequent calls to continue the enumeration.
  620. //
  621. // Returns: On successful return, a pointer to the child prefix that has a
  622. // valid pData, or NULL if at the end of the enumeration, or if
  623. // pPath is not a valid prefix in the table to begin with.
  624. //
  625. //-----------------------------------------------------------------------------
  626. PVOID
  627. DfsNextUnicodePrefixChild(
  628. IN PDFS_PREFIX_TABLE pTable,
  629. IN PUNICODE_STRING pPath,
  630. OUT PVOID *ppCookie)
  631. {
  632. NTSTATUS status = STATUS_SUCCESS;
  633. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  634. UNICODE_STRING suffix;
  635. PVOID pData;
  636. if ((*ppCookie) == NULL) {
  637. if (pPath->Length > 0) {
  638. status = _LookupPrefixTable(pTable,pPath,&suffix,&pEntry);
  639. if (NT_SUCCESS(status)) {
  640. pEntry = pEntry->pFirstChildEntry;
  641. }
  642. }
  643. } else if ((*ppCookie) == (PVOID) -1) {
  644. status = STATUS_NO_MORE_ENTRIES;
  645. } else {
  646. pEntry = (PDFS_PREFIX_TABLE_ENTRY) (*ppCookie);
  647. pEntry = pEntry->pSiblingEntry;
  648. }
  649. pData = NULL;
  650. (*ppCookie) = (PVOID) -1;
  651. if (NT_SUCCESS(status)) {
  652. if (pEntry != NULL) {
  653. (*ppCookie) = (PVOID) pEntry;
  654. pData = pEntry->pData;
  655. }
  656. }
  657. return( pData );
  658. }
  659. VOID
  660. RemoveFirstComponent(
  661. PUNICODE_STRING Path,
  662. PUNICODE_STRING Remainder)
  663. {
  664. *Remainder = *Path;
  665. if (Remainder->Length == 0 ||
  666. Remainder->Length == sizeof(WCHAR)) {
  667. return;
  668. }
  669. //
  670. // Strip leading \'s
  671. while (Remainder->Length > 0 && Remainder->Buffer[0] == PATH_DELIMITER) {
  672. Remainder->Length -= sizeof(WCHAR);
  673. Remainder->Buffer++;
  674. }
  675. while (Remainder->Length > 0 && Remainder->Buffer[0] != PATH_DELIMITER) {
  676. Remainder->Length -= sizeof(WCHAR);
  677. Remainder->Buffer++;
  678. }
  679. }