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.

739 lines
22 KiB

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