Leaked source code of windows server 2003
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.

767 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation.
  4. //
  5. // File: name_table.c
  6. //
  7. // Contents: The DFS Name Table
  8. //
  9. //--------------------------------------------------------------------------
  10. #define NAME_TABLE_C
  11. #ifdef KERNEL_MODE
  12. #include <ntifs.h>
  13. #include <string.h>
  14. #include <fsrtl.h>
  15. #include <zwapi.h>
  16. #include <wmlkm.h>
  17. #else
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <malloc.h>
  25. #endif
  26. #include "name_table.h"
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Function: DfsInitNameTable - Creates and initializes the DFS Name table.
  30. //
  31. // Synopsis: DfsInitNameTable allocates space for the space table. It then
  32. // initializes the lock and the hash buckets in the table and
  33. // returns the allocated name table.
  34. //
  35. // Arguments: NumBuckets - Number of Buckets in the name table hash.
  36. // ppNameTable - Pointer to name table pointer.
  37. //
  38. // Returns: Status
  39. // STATUS_SUCCESS if we could allocate the table.
  40. // STATUS_INSUFFICIENT_RESOURCES otherwise.
  41. //
  42. //
  43. // Description: The DFS NameTable is the starting point for all DFS namespace
  44. // lookups. The NameTable hash buckets hold the root objects of
  45. // all DFS's known to this server. The hash is based on the
  46. // netbios DFS Naming context (which is the netbios
  47. // domain/forest/machine name and the DFS Share name of the form
  48. // \NetbiosName\\Sharename.)
  49. //
  50. //--------------------------------------------------------------------------
  51. NTSTATUS
  52. DfsInitializeNameTable(
  53. IN ULONG NumBuckets,
  54. OUT PDFS_NAME_TABLE *ppNameTable)
  55. {
  56. PDFS_NAME_TABLE pNameTable = NULL;
  57. PDFS_NAME_TABLE_BUCKET pBucket = NULL;
  58. ULONG HashTableSize;
  59. PCRITICAL_SECTION pLock = NULL;
  60. ULONG i;
  61. NTSTATUS Status = STATUS_SUCCESS;
  62. if ( NumBuckets == 0 ) {
  63. NumBuckets = DEFAULT_NAME_TABLE_SIZE;
  64. }
  65. HashTableSize = sizeof(DFS_NAME_TABLE) +
  66. NumBuckets * sizeof(DFS_NAME_TABLE_BUCKET);
  67. do {
  68. pNameTable = ALLOCATE_MEMORY(HashTableSize + sizeof(CRITICAL_SECTION));
  69. if ( pNameTable == NULL ) {
  70. Status = STATUS_INSUFFICIENT_RESOURCES;
  71. break;
  72. }
  73. RtlZeroMemory(pNameTable, HashTableSize + sizeof(CRITICAL_SECTION));
  74. DfsInitializeHeader( &(pNameTable->DfsHeader),
  75. DFS_OT_NAME_TABLE,
  76. HashTableSize + sizeof(CRITICAL_SECTION));
  77. pLock = (PCRITICAL_SECTION)((ULONG_PTR)pNameTable + HashTableSize);
  78. if (InitializeCriticalSectionAndSpinCount(pLock, DFS_NAMETABLE_CRIT_SPIN_COUNT) != TRUE)
  79. {
  80. Status = GetLastError();
  81. break;
  82. }
  83. pNameTable->NumBuckets = NumBuckets;
  84. pNameTable->pLock = (PVOID)pLock;
  85. pNameTable->Flags = 0;
  86. for ( i = 0; i < NumBuckets; i++ ) {
  87. pBucket = &(pNameTable->HashBuckets[i]);
  88. InitializeListHead(&pBucket->ListHead);
  89. pBucket->Count = 0;
  90. }
  91. } while (FALSE);
  92. if ( Status == STATUS_SUCCESS ) {
  93. *ppNameTable = pNameTable;
  94. } else {
  95. if (pNameTable != NULL) {
  96. FREE_MEMORY( pNameTable );
  97. }
  98. }
  99. return Status;
  100. }
  101. //+-------------------------------------------------------------------------
  102. //
  103. // Function: DfsInsertInNameTable - Inserts the passed in Entry into table
  104. //
  105. // Synopsis: DfsInsertInNameTable checks and makes sure that another entry
  106. // with matching name does not already exist in the table.
  107. // It Inserts the passed in Entry in the appropriate hash bucket,
  108. // The callers needs to take a reference on the object and this
  109. // reference is passed on to the name table. The name table does
  110. // not explicitly take a reference on the Entry object.
  111. //
  112. //
  113. // Arguments: pEntry - The Entry to be inserted
  114. //
  115. // Returns: Status
  116. // STATUS_OBJECT_NAME_COLLISION if name already exists in table
  117. // STATUS_SUCCESS otherwise
  118. //
  119. //
  120. // Description: The object representing the entry is assumed to be completely
  121. // setup at the point it is
  122. // inserted in the name table. Future lookup requests will
  123. // find the entry.
  124. // This call checks the name table to see if the Named Entry in
  125. // specified Naming Context already exists. If it does, we cannot
  126. // insert this entry, and return STATUS_OBJECT_NAME_COLLISION.
  127. // In all other cases, the entry is inserted in the appro<priate
  128. // bucket, and we are done.
  129. // A reference is held on the Entry that is added to the name table.
  130. // This reference needs to be taken by the caller of this function.
  131. // The caller passes on that reference to the name table if this
  132. // function returns STATUS_SUCCESS. (In all other cases, the
  133. // caller needs to take appropriate action: either dereference the
  134. // Entry or destro<y it.)
  135. // This reference is released when the Entry is removed from the
  136. // name table.
  137. //
  138. //--------------------------------------------------------------------------
  139. NTSTATUS
  140. DfsInsertInNameTableLocked(
  141. IN PDFS_NAME_TABLE pNameTable,
  142. IN PUNICODE_STRING pName,
  143. IN PVOID pData )
  144. {
  145. ULONG BucketNum;
  146. NTSTATUS Status = STATUS_SUCCESS;
  147. PDFS_NAME_TABLE_ENTRY pEntry;
  148. PDFS_NAME_TABLE_ENTRY pMatchingEntry;
  149. PDFS_NAME_TABLE_BUCKET pBucket;
  150. GET_NAME_TABLE_BUCKET(pName, pNameTable, BucketNum);
  151. // No lock necessary to get the list head. The nametable is static.
  152. pBucket = &pNameTable->HashBuckets[BucketNum];
  153. // Check Name table will check the specified name in the given bucket.
  154. // and returns the status of the check. This call does not hold a reference
  155. // on the matching entry, if one exists. So handle with care. (Dont access it
  156. // after the bucket lock is released)
  157. Status = DfsCheckNameTable( pName,
  158. pBucket,
  159. &pMatchingEntry);
  160. // If the name already exists, then we fail the request. For all other
  161. // error conditions except OBJECT_NOT_FOUND, return failure status intact.
  162. // In case the object is not found, it is safe to insert this in the bucket,
  163. // and return success.
  164. if ( Status == STATUS_SUCCESS ) {
  165. Status = STATUS_OBJECT_NAME_COLLISION;
  166. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  167. pEntry = ALLOCATE_MEMORY(sizeof(DFS_NAME_TABLE_ENTRY));
  168. if (pEntry != NULL) {
  169. pEntry->pName = pName;
  170. pEntry->pData = pData;
  171. InsertHeadList(&pBucket->ListHead, &pEntry->NameTableLink);
  172. pBucket->Count++;
  173. Status = STATUS_SUCCESS;
  174. }
  175. else {
  176. Status = STATUS_INSUFFICIENT_RESOURCES;
  177. }
  178. }
  179. return Status;
  180. }
  181. //+-------------------------------------------------------------------------
  182. //
  183. // Function: DfsLookupNameTable - Looks for a name in the name table
  184. //
  185. // Arguments: lookupName - Unicode string of Entry
  186. // lookupNC - The Naming Context of interest
  187. // ppMatchEntry - The matching entry to return if found.
  188. //
  189. // Returns: Status
  190. // STATUS_OBJECT_NOT_FOUND if the matching name and NC is not
  191. // found in the name table.
  192. // STATUS_SUCCESS Otherwise.
  193. //
  194. //
  195. // Description: The Entry is assumed to be completely setup at the point it is
  196. // inserted in the name table. Future lookup requests will
  197. // lookup the entry.
  198. // This call checks the name table to see if the Named entry in the
  199. // specified Naming Context already exists. If it does, we cannot
  200. // insert this entry, and return STATUS_OBJECT_NAME_COLLISION.
  201. // In all other cases, the entry is inserted in the appropriate
  202. // bucket, and we are done.
  203. // A reference is held on the entry that is added to the name table.
  204. // This reference needs to be taken by the caller of this function.
  205. // The caller passes on that reference to the name table if this
  206. // function returns STATUS_SUCCESS. (In all other cases, the
  207. // caller needs to take appropriate action: either dereference the
  208. // entry or destroy it.)
  209. // This reference is released when the entry is removed from the
  210. // name table.
  211. //
  212. //--------------------------------------------------------------------------
  213. NTSTATUS
  214. DfsLookupNameTableLocked(
  215. IN PDFS_NAME_TABLE pNameTable,
  216. IN PUNICODE_STRING pLookupName,
  217. OUT PVOID *ppData )
  218. {
  219. ULONG BucketNum;
  220. NTSTATUS Status;
  221. PDFS_NAME_TABLE_BUCKET pBucket;
  222. PDFS_NAME_TABLE_ENTRY pMatchEntry;
  223. GET_NAME_TABLE_BUCKET( pLookupName, pNameTable, BucketNum );
  224. pBucket = &pNameTable->HashBuckets[BucketNum];
  225. Status = DfsCheckNameTable( pLookupName,
  226. pBucket,
  227. &pMatchEntry );
  228. if (Status == STATUS_SUCCESS) {
  229. *ppData = pMatchEntry->pData;
  230. }
  231. return Status;
  232. }
  233. //+-------------------------------------------------------------------------
  234. //
  235. // Function: DfsGetEntryNameTableLocked - Looks for a name in the name table
  236. //
  237. // Arguments: lookupName - Unicode string of Entry
  238. // lookupNC - The Naming Context of interest
  239. // ppMatchEntry - The matching entry to return if found.
  240. //
  241. // Returns: Status
  242. // STATUS_OBJECT_NOT_FOUND if the matching name and NC is not
  243. // found in the name table.
  244. // STATUS_SUCCESS Otherwise.
  245. //
  246. //
  247. // Description: The Entry is assumed to be completely setup at the point it is
  248. // inserted in the name table. Future lookup requests will
  249. // lookup the entry.
  250. // This call checks the name table to see if the Named entry in the
  251. // specified Naming Context already exists. If it does, we cannot
  252. // insert this entry, and return STATUS_OBJECT_NAME_COLLISION.
  253. // In all other cases, the entry is inserted in the appropriate
  254. // bucket, and we are done.
  255. // A reference is held on the entry that is added to the name table.
  256. // This reference needs to be taken by the caller of this function.
  257. // The caller passes on that reference to the name table if this
  258. // function returns STATUS_SUCCESS. (In all other cases, the
  259. // caller needs to take appropriate action: either dereference the
  260. // entry or destroy it.)
  261. // This reference is released when the entry is removed from the
  262. // name table.
  263. //
  264. //--------------------------------------------------------------------------
  265. NTSTATUS
  266. DfsGetEntryNameTableLocked(
  267. IN PDFS_NAME_TABLE pNameTable,
  268. OUT PVOID *ppData )
  269. {
  270. ULONG BucketNum;
  271. NTSTATUS Status = STATUS_NOT_FOUND;
  272. PDFS_NAME_TABLE_BUCKET pBucket;
  273. PDFS_NAME_TABLE_ENTRY pEntry;
  274. PLIST_ENTRY pListHead, pLink;
  275. for (BucketNum = 0; BucketNum < pNameTable->NumBuckets; BucketNum++)
  276. {
  277. pBucket = &pNameTable->HashBuckets[BucketNum];
  278. if (pBucket->Count == 0)
  279. {
  280. continue;
  281. }
  282. pListHead = &pBucket->ListHead;
  283. pLink = pListHead->Flink;
  284. if (pLink == pListHead)
  285. {
  286. continue;
  287. }
  288. pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
  289. *ppData = pEntry->pData;
  290. Status = STATUS_SUCCESS;
  291. break;
  292. }
  293. return Status;
  294. }
  295. //+-------------------------------------------------------------------------
  296. //
  297. // Function: DfsCheckNameTable - Check for a name in the name table
  298. //
  299. // Arguments: lookupName - Unicode string of name
  300. // lookupNC - The DFS Naming Context of interest
  301. // pBucket - The bucket of interest.
  302. // ppMatchEntry - The matching entry to return if found.
  303. //
  304. // Returns: Status
  305. // STATUS_OBJECT_NOT_FOUND if the matching name and NC is not
  306. // found in the name table.
  307. // STATUS_SUCCESS Otherwise.
  308. //
  309. //
  310. // Description: It is assumed that appropriate locks are taken to traverse
  311. // the links in the bucket.
  312. // If an entry is found, it is returned without taking any
  313. // references on the found object.
  314. //--------------------------------------------------------------------------
  315. NTSTATUS
  316. DfsCheckNameTable(
  317. IN PUNICODE_STRING pLookupName,
  318. IN PDFS_NAME_TABLE_BUCKET pBucket,
  319. OUT PDFS_NAME_TABLE_ENTRY *ppMatchEntry )
  320. {
  321. NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
  322. PLIST_ENTRY pListHead, pLink;
  323. PDFS_NAME_TABLE_ENTRY pEntry;
  324. pListHead = &pBucket->ListHead;
  325. for ( pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink ) {
  326. pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
  327. // If we find a matching Name, check if we are interested in a
  328. // specific Naming context. If no naming context is specified, or the
  329. // specified naming context matches, we have found our entry. Get a
  330. // reference on the entry while the bucket is locked so the entry does
  331. // not go away, and we can return avalid pointer to the caller.
  332. // The caller is responsible for releasing this reference.
  333. if (RtlCompareUnicodeString(pEntry->pName, pLookupName, TRUE) == 0) {
  334. Status = STATUS_SUCCESS;
  335. break;
  336. }
  337. }
  338. // If we did find an entry, return it
  339. if ( Status == STATUS_SUCCESS ) {
  340. *ppMatchEntry = pEntry;
  341. }
  342. return Status;
  343. }
  344. //+-------------------------------------------------------------------------
  345. //
  346. // Function: DfsRemoveFromNameTable - Removes the specified entry
  347. // from the name table
  348. //
  349. // Arguments: pEntry - The entry to be removed.
  350. //
  351. // Returns: Status
  352. // STATUS_SUCCESS if the specified entry was successfully removed.
  353. // STATUS_NOT_FOUND if the specifed entry is not the entry in the
  354. // table for that entry name.
  355. // STATUS_OBJECT_NAME_NOT_FOUND if the entry name does not exist
  356. // in the table
  357. //
  358. // Description: The passed in entry is expected to a valid pointer that will
  359. // not be freed up while we are referencing it.
  360. // We check for an object in the name table for a matching name.
  361. // If the object in the name table matches the passed in object,
  362. // we can safely remove it from the name table. When we do so,
  363. // we also release the reference on the object that was held
  364. // when the object was inserted into the table.
  365. // If the object is not found or the object does not match the
  366. // one in the table, error status is returned.
  367. //
  368. //--------------------------------------------------------------------------
  369. NTSTATUS
  370. DfsRemoveFromNameTableLocked(
  371. IN struct _DFS_NAME_TABLE *pNameTable,
  372. IN PUNICODE_STRING pLookupName,
  373. IN PVOID pData )
  374. {
  375. NTSTATUS Status;
  376. PDFS_NAME_TABLE_ENTRY pMatchingEntry;
  377. PDFS_NAME_TABLE_BUCKET pBucket;
  378. ULONG BucketNum;
  379. GET_NAME_TABLE_BUCKET(pLookupName, pNameTable, BucketNum );
  380. // No lock necessary to get the list head. The nametable is static.
  381. pBucket = &pNameTable->HashBuckets[BucketNum];
  382. // Check Name table will check the specified name in the given bucket.
  383. // and returns the status of the check. This call does not hold a reference
  384. // on the matching entry, if one exists. So handle with care. (Dont access
  385. // it after the bucket lock is released)
  386. Status = DfsCheckNameTable( pLookupName,
  387. pBucket,
  388. &pMatchingEntry);
  389. // If we found an entry for the specified Name and NC, and the entry
  390. // matches the pointer passed in, we remove the entry from the bucket.
  391. // If the object does not match, we set the status to STATUS_NOT_FOUND,
  392. // to indicate that the name of the object exists in the table, but
  393. // the object in the table is different.
  394. if ( Status == STATUS_SUCCESS ) {
  395. if ( (pData == NULL) || (pMatchingEntry->pData == pData) ) {
  396. RemoveEntryList(&pMatchingEntry->NameTableLink);
  397. FREE_MEMORY( pMatchingEntry );
  398. pBucket->Count--;
  399. } else {
  400. Status = STATUS_NOT_FOUND;
  401. }
  402. }
  403. return Status;
  404. }
  405. //+-------------------------------------------------------------------------
  406. //
  407. // Function: DfsReplaceInNameTable - Removes an entry by the specified name,
  408. // if one exists. The passed in entry is
  409. // inserted into the table.
  410. //
  411. // Arguments: pNewEntry - The entry to be inserted in the table
  412. //
  413. // Returns: Status
  414. // STATUS_SUCCESS if the passed in entry was inserted in the table
  415. //
  416. // Description: The caller needs to hold a reference to the passed in entry,
  417. // and this reference is transferred to the name table.
  418. // If the name exists in the name table, the object is removed
  419. // from the nametable and its reference is discarded.
  420. // The passed in object is inserted in the same bucket.
  421. // This call allows an atomic replace of the entry object,
  422. // avoiding a window during which a valid name may not be found
  423. // in the name table.
  424. //
  425. // Note that the newentry being passed in may already be
  426. // in the table (due to multiple threads doing this work) so
  427. // that special situation should work.
  428. //
  429. //--------------------------------------------------------------------------
  430. NTSTATUS
  431. DfsReplaceInNameTableLocked (
  432. IN PDFS_NAME_TABLE pNameTable,
  433. IN PUNICODE_STRING pLookupName,
  434. IN OUT PVOID *ppData )
  435. {
  436. PDFS_NAME_TABLE_ENTRY pEntry;
  437. PDFS_NAME_TABLE_BUCKET pBucket;
  438. ULONG BucketNum;
  439. PVOID pOldData = NULL;
  440. NTSTATUS Status;
  441. GET_NAME_TABLE_BUCKET(pLookupName, pNameTable, BucketNum );
  442. // No lock necessary to get the list head. The nametable is static.
  443. pBucket = &pNameTable->HashBuckets[BucketNum];
  444. // Check Name table will check the specified name in the given bucket.
  445. // and returns the status of the check. This call does not hold a reference
  446. // on the matching entry, if one exists. So handle with care. (Dont access
  447. // it after the bucket lock is released)
  448. Status = DfsCheckNameTable( pLookupName,
  449. pBucket,
  450. &pEntry );
  451. // If we found a matching name, we remove it from the name table.
  452. if ( Status == STATUS_SUCCESS ) {
  453. pOldData = pEntry->pData;
  454. pEntry->pName = pLookupName;
  455. pEntry->pData = *ppData;
  456. } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  457. pEntry = ALLOCATE_MEMORY(sizeof(DFS_NAME_TABLE_ENTRY));
  458. if (pEntry != NULL) {
  459. pEntry->pName = pLookupName;
  460. pEntry->pData = *ppData;
  461. InsertHeadList(&pBucket->ListHead, &pEntry->NameTableLink);
  462. pBucket->Count++;
  463. Status = STATUS_SUCCESS;
  464. } else {
  465. Status = STATUS_INSUFFICIENT_RESOURCES;
  466. }
  467. }
  468. if (Status == STATUS_SUCCESS) {
  469. *ppData = pOldData;
  470. }
  471. return Status;
  472. }
  473. VOID
  474. DumpNameTable(
  475. PDFS_NAME_TABLE pNameTable )
  476. {
  477. PDFS_NAME_TABLE_BUCKET pBucket;
  478. PLIST_ENTRY pListHead, pLink;
  479. PDFS_NAME_TABLE_ENTRY pEntry;
  480. ULONG i;
  481. printf("Table %p type %x size %d RefCnt %d\n",
  482. pNameTable,
  483. DfsGetHeaderType(&pNameTable->DfsHeader),
  484. DfsGetHeaderSize(&pNameTable->DfsHeader),
  485. DfsGetHeaderCount(&pNameTable->DfsHeader));
  486. printf("Number of buckets %d\n", pNameTable->NumBuckets);
  487. for ( i = 0; i < pNameTable->NumBuckets; i++ ) {
  488. pBucket = &pNameTable->HashBuckets[i];
  489. if ( pBucket->Count == 0 )
  490. continue;
  491. printf("Bucket %d Count in bucket %d\n",
  492. i,
  493. pBucket->Count);
  494. pListHead = &pBucket->ListHead;
  495. for ( pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink ) {
  496. pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
  497. printf("Found entry %p Name %wZ\n",
  498. pEntry, pEntry->pName);
  499. }
  500. }
  501. return;
  502. }
  503. NTSTATUS
  504. DfsDismantleNameTable(
  505. PDFS_NAME_TABLE pNameTable )
  506. {
  507. PDFS_NAME_TABLE_BUCKET pBucket;
  508. PLIST_ENTRY pListHead, pLink, pCurrent;
  509. PDFS_NAME_TABLE_ENTRY pEntry;
  510. ULONG i;
  511. for ( i = 0; i < pNameTable->NumBuckets; i++ ) {
  512. pBucket = &pNameTable->HashBuckets[i];
  513. pListHead = &pBucket->ListHead;
  514. for ( pLink = pListHead->Flink; pLink != pListHead; ) {
  515. pCurrent = pLink;
  516. pLink = pLink->Flink;
  517. pEntry = CONTAINING_RECORD(pCurrent, DFS_NAME_TABLE_ENTRY, NameTableLink);
  518. RemoveEntryList( pCurrent );
  519. }
  520. }
  521. return STATUS_SUCCESS;
  522. }
  523. NTSTATUS
  524. DfsReferenceNameTable(
  525. IN PDFS_NAME_TABLE pNameTable)
  526. {
  527. PDFS_OBJECT_HEADER pHeader = &pNameTable->DfsHeader;
  528. USHORT headerType = DfsGetHeaderType( pHeader );
  529. if ( headerType != DFS_OT_NAME_TABLE ) {
  530. return STATUS_UNSUCCESSFUL;
  531. }
  532. DfsIncrementReference( pHeader );
  533. return STATUS_SUCCESS;
  534. }
  535. NTSTATUS
  536. DfsDereferenceNameTable(
  537. IN PDFS_NAME_TABLE pNameTable)
  538. {
  539. PDFS_OBJECT_HEADER pHeader = &pNameTable->DfsHeader;
  540. USHORT headerType = DfsGetHeaderType( pHeader );
  541. LONG Ref;
  542. if ( headerType != DFS_OT_NAME_TABLE ) {
  543. return STATUS_UNSUCCESSFUL;
  544. }
  545. Ref = DfsDecrementReference( pHeader );
  546. if (Ref == 0) {
  547. DeleteCriticalSection(pNameTable->pLock);
  548. FREE_MEMORY(pNameTable);
  549. }
  550. return STATUS_SUCCESS;
  551. }
  552. NTSTATUS
  553. DfsNameTableAcquireWriteLock(
  554. IN PDFS_NAME_TABLE pNameTable )
  555. {
  556. NTSTATUS Status = STATUS_SUCCESS;
  557. DFS_LOCK_NAME_TABLE(pNameTable, Status);
  558. return Status;
  559. }
  560. NTSTATUS
  561. DfsNameTableAcquireReadLock(
  562. IN PDFS_NAME_TABLE pNameTable )
  563. {
  564. NTSTATUS Status = STATUS_SUCCESS;
  565. DFS_LOCK_NAME_TABLE(pNameTable, Status);
  566. return Status;
  567. }
  568. NTSTATUS
  569. DfsNameTableReleaseLock(
  570. IN PDFS_NAME_TABLE pNameTable )
  571. {
  572. NTSTATUS Status = STATUS_SUCCESS;
  573. DFS_UNLOCK_NAME_TABLE(pNameTable);
  574. return Status;
  575. }
  576. NTSTATUS
  577. DfsEnumerateNameTableLocked(
  578. IN PDFS_NAME_TABLE pNameTable,
  579. IN OUT PVOID *ppEnumerator,
  580. OUT PVOID *ppData )
  581. {
  582. PDFS_NAME_TABLE_ENTRY pEntry = (PDFS_NAME_TABLE_ENTRY)*ppEnumerator;
  583. ULONG BucketNum = 0;
  584. NTSTATUS NtStatus = STATUS_NO_MORE_MATCHES;
  585. PDFS_NAME_TABLE_BUCKET pBucket = NULL;
  586. PLIST_ENTRY pListHead, pLink;
  587. *ppEnumerator = NULL;
  588. *ppData = NULL;
  589. if (pEntry != NULL)
  590. {
  591. GET_NAME_TABLE_BUCKET(pEntry->pName, pNameTable, BucketNum);
  592. }
  593. for ( ; BucketNum < pNameTable->NumBuckets; BucketNum++)
  594. {
  595. pBucket = &pNameTable->HashBuckets[BucketNum];
  596. if (pBucket->Count == 0)
  597. {
  598. continue;
  599. }
  600. pListHead = &pBucket->ListHead;
  601. if (pEntry != NULL)
  602. {
  603. pLink = pEntry->NameTableLink.Flink;
  604. pEntry = NULL;
  605. }
  606. else
  607. {
  608. pLink = pListHead->Flink;
  609. }
  610. if (pLink == pListHead)
  611. {
  612. continue;
  613. }
  614. pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
  615. *ppEnumerator = (PVOID)pEntry;
  616. *ppData = pEntry->pData;
  617. NtStatus = STATUS_SUCCESS;
  618. break;
  619. }
  620. return NtStatus;
  621. }