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.

1115 lines
31 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 <ntifs.h>
  17. #include <ntddser.h>
  18. #include <windef.h>
  19. #else
  20. #include <nt.h>
  21. #include <ntrtl.h>
  22. #include <nturtl.h>
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <malloc.h>
  27. #endif
  28. #include <prefix.h>
  29. #include <dfsprefix.h>
  30. PDFS_PREFIX_TABLE_ENTRY
  31. DfspNextUnicodeTableEntry(
  32. IN PDFS_PREFIX_TABLE_ENTRY pEntry);
  33. VOID
  34. DfsDeletePrefixTable(
  35. IN PDFS_PREFIX_TABLE pTable);
  36. #ifdef ALLOC_PRAGMA
  37. #pragma alloc_text( PAGE, DfsFreePrefixTable )
  38. #pragma alloc_text( PAGE, DfsInitializePrefixTable )
  39. #pragma alloc_text( PAGE, DfsDeletePrefixTable )
  40. #pragma alloc_text( PAGE, DfsInsertInPrefixTable )
  41. #pragma alloc_text( PAGE, DfsFindUnicodePrefix )
  42. #pragma alloc_text( PAGE, DfsRemoveFromPrefixTable )
  43. #pragma alloc_text( PAGE, _LookupPrefixTable )
  44. #pragma alloc_text( PAGE, DfsRemoveFromPrefixTableEx )
  45. #pragma alloc_text( PAGE, DfsRemoveFromPrefixTableLockedEx )
  46. #endif // ALLOC_PRAGMA
  47. #if defined (PREFIX_TABLE_HEAP_MEMORY)
  48. HANDLE PrefixTableHeapHandle = NULL;
  49. #endif
  50. NTSTATUS
  51. DfsPrefixTableInit()
  52. {
  53. #if defined (PREFIX_TABLE_HEAP_MEMORY)
  54. PrefixTableHeapHandle = HeapCreate(0, 0, 0);
  55. if ( PrefixTableHeapHandle == NULL ) {
  56. return STATUS_INSUFFICIENT_RESOURCES;
  57. }
  58. /* printf("Prefix table using memory heap\n"); */
  59. #endif
  60. return STATUS_SUCCESS;
  61. }
  62. void
  63. DfsPrefixTableShutdown(void)
  64. {
  65. #if defined (PREFIX_TABLE_HEAP_MEMORY)
  66. if ( PrefixTableHeapHandle != NULL )
  67. {
  68. HeapDestroy(PrefixTableHeapHandle);
  69. PrefixTableHeapHandle = NULL;
  70. }
  71. /* printf("Prefix table using memory heap\n"); */
  72. #endif
  73. }
  74. //+---------------------------------------------------------------------------
  75. //
  76. // Function: DfsInitializePrefixTable
  77. //
  78. // Synopsis: API for initializing the prefix table
  79. //
  80. // Arguments: [pTable] -- the DFS prefix table instance
  81. //
  82. // Returns: one of the following NTSTATUS codes
  83. // STATUS_SUCCESS -- call was successfull.
  84. //
  85. // History: 04-18-94 SethuR Created
  86. //
  87. // Notes:
  88. //
  89. //----------------------------------------------------------------------------
  90. NTSTATUS
  91. DfsInitializePrefixTable(
  92. IN OUT PDFS_PREFIX_TABLE *ppTable,
  93. IN BOOLEAN fCaseSensitive,
  94. IN PVOID Lock)
  95. {
  96. PDFS_PREFIX_TABLE pTable = *ppTable;
  97. NTSTATUS Status = STATUS_SUCCESS;
  98. ULONG Flags = fCaseSensitive ? PREFIX_TABLE_CASE_SENSITIVE : 0;
  99. int i;
  100. if ( pTable == NULL ) {
  101. Flags |= PREFIX_TABLE_TABLE_ALLOCATED;
  102. pTable = ALLOCATE_PREFIX_TABLE();
  103. if ( pTable == NULL )
  104. Status = STATUS_INSUFFICIENT_RESOURCES;
  105. }
  106. if ( NT_SUCCESS(Status) ) {
  107. RtlZeroMemory(pTable, sizeof(DFS_PREFIX_TABLE));
  108. DfsInitializeHeader(&pTable->DfsHeader,
  109. DFS_OT_PREFIX_TABLE,
  110. sizeof(DFS_PREFIX_TABLE));
  111. pTable->Flags = Flags;
  112. pTable->LockCount = 0;
  113. // Initialize the root entry
  114. INITIALIZE_PREFIX_TABLE_ENTRY(&pTable->RootEntry);
  115. // Initialize the various buckets.
  116. for ( i = 0;i < NO_OF_HASH_BUCKETS;i++ ) {
  117. INITIALIZE_BUCKET(pTable->Buckets[i]);
  118. }
  119. pTable->pPrefixTableLock = Lock;
  120. if ( pTable->pPrefixTableLock == NULL ) {
  121. pTable->pPrefixTableLock = ALLOCATE_PREFIX_TABLE_LOCK();
  122. if ( pTable->pPrefixTableLock != NULL ) {
  123. pTable->Flags |= PREFIX_TABLE_LOCK_ALLOCATED;
  124. Status = INITIALIZE_PREFIX_TABLE_LOCK(pTable->pPrefixTableLock);
  125. if (NT_SUCCESS( Status )) {
  126. pTable->Flags |= PREFIX_TABLE_LOCK_INITIALIZED;
  127. }
  128. } else {
  129. Status = STATUS_INSUFFICIENT_RESOURCES;
  130. }
  131. }
  132. }
  133. if (!NT_SUCCESS( Status )) {
  134. if (pTable) {
  135. DfsDeletePrefixTable( pTable );
  136. pTable = NULL;
  137. }
  138. }
  139. *ppTable = pTable;
  140. return Status;
  141. }
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Function: DfsInsertInPrefixTableLocked
  145. //
  146. // Synopsis: API for inserting a path in the prefix table
  147. //
  148. // Arguments: [pTable] -- the DFS prefix table instance
  149. //
  150. // [pPath] -- the path to be looked up.
  151. //
  152. // [pData] -- BLOB associated with the path
  153. //
  154. // Returns: one of the following NTSTATUS codes
  155. // STATUS_SUCCESS -- call was successfull.
  156. //
  157. // History: 04-18-94 SethuR Created
  158. //
  159. // Notes:
  160. //
  161. //----------------------------------------------------------------------------
  162. NTSTATUS DfsInsertInPrefixTableLocked(
  163. IN PDFS_PREFIX_TABLE pTable,
  164. IN PUNICODE_STRING pPath,
  165. IN PVOID pData)
  166. {
  167. NTSTATUS status = STATUS_SUCCESS;
  168. WCHAR Buffer[MAX_PATH_SEGMENT_SIZE];
  169. PWCHAR NameBuffer = Buffer;
  170. ULONG BucketNo = 0;
  171. USHORT cbNameBuffer = sizeof(Buffer);
  172. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  173. PDFS_PREFIX_TABLE_ENTRY pParentEntry = NULL;
  174. PDFS_PREFIX_TABLE_ENTRY pLastInsertedEntry = NULL;
  175. BOOLEAN fNameFound = FALSE;
  176. UNICODE_STRING Path,Name;
  177. BOOLEAN NewParent = FALSE;
  178. if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
  179. return STATUS_INVALID_PARAMETER;
  180. }
  181. // There is one special case, i.e., in which the prefix is '\'.
  182. // Since this is the PATH_DELIMITER which is treated in a special
  183. // way, we do the >processing upfront.
  184. Path.Length = pPath->Length;
  185. Path.MaximumLength = pPath->MaximumLength;
  186. Path.Buffer = &pPath->Buffer[0];
  187. pParentEntry = &pTable->RootEntry;
  188. if ( pPath->Length == 0 ) {
  189. return STATUS_SUCCESS;
  190. } else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
  191. if ( pPath->Length == sizeof(WCHAR) ) {
  192. pTable->RootEntry.pData = pData;
  193. return STATUS_SUCCESS;
  194. } else {
  195. Path.Length -= sizeof(WCHAR);
  196. Path.Buffer++;
  197. }
  198. }
  199. if ( Path.Length >= MAX_PATH_SEGMENT_SIZE * sizeof(WCHAR) ) {
  200. NameBuffer = PREFIX_TABLE_ALLOCATE_MEMORY(Path.Length + sizeof(WCHAR));
  201. if ( NameBuffer == NULL ) {
  202. return( STATUS_INSUFFICIENT_RESOURCES );
  203. } else {
  204. cbNameBuffer = Path.Length + sizeof(WCHAR);
  205. }
  206. }
  207. while ( Path.Length > 0 ) {
  208. Name.Length = 0;
  209. Name.Buffer = NameBuffer;
  210. Name.MaximumLength = cbNameBuffer;
  211. // Process the name segment
  212. if ( pTable->Flags & PREFIX_TABLE_CASE_SENSITIVE ) {
  213. SPLIT_CASE_SENSITIVE_PATH(&Path,&Name,BucketNo);
  214. } else {
  215. SPLIT_CASE_INSENSITIVE_PATH(&Path,&Name,BucketNo);
  216. }
  217. if ( Name.Length > 0 ) {
  218. // Lookup the table to see if the name segment already exists.
  219. LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
  220. if ( pEntry == NULL ) {
  221. // Initialize the new entry and initialize the name segment.
  222. pEntry = ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable);
  223. if ( pEntry != NULL ) {
  224. INITIALIZE_PREFIX_TABLE_ENTRY(pEntry);
  225. // Allocate the name space entry if there is no entry in the
  226. // name page.
  227. {
  228. PWSTR pBuffer;
  229. // Allocate the entry in the name page.
  230. pBuffer = ALLOCATE_NAME_BUFFER((Name.Length/sizeof(WCHAR)));
  231. if ( pBuffer != NULL ) {
  232. RtlZeroMemory(pBuffer,Name.Length);
  233. RtlCopyMemory(pBuffer,Name.Buffer,Name.Length);
  234. pEntry->PathSegment = Name;
  235. pEntry->PathSegment.Buffer = pBuffer;
  236. } else {
  237. FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pEntry);
  238. status = STATUS_INSUFFICIENT_RESOURCES;
  239. break;
  240. }
  241. }
  242. // thread the entry to point to the parent.
  243. // Increment the no. of children associated with this entry
  244. if (NewParent == FALSE) {
  245. pParentEntry->Reference++;
  246. NewParent = TRUE;
  247. }
  248. pEntry->pParentEntry = pParentEntry;
  249. pLastInsertedEntry = pEntry;
  250. // Insert the entry in the bucket.
  251. INSERT_IN_BUCKET(pTable->Buckets[BucketNo],pEntry);
  252. // Insert the entry in the parent's children list.
  253. INSERT_IN_CHILD_LIST(pEntry, pParentEntry);
  254. } else {
  255. status = STATUS_INSUFFICIENT_RESOURCES;
  256. break;
  257. }
  258. }
  259. pParentEntry = pEntry;
  260. } else {
  261. status = STATUS_INVALID_PARAMETER;
  262. break;
  263. }
  264. }
  265. // If a new entry was not successfully inserted we need to walk up the chain
  266. // of parent entries to undo the increment to the reference count and
  267. // remove the entries from their parent links.
  268. if (NT_SUCCESS(status) &&
  269. pEntry != NULL /* to keep PREFAST happy */) {
  270. // The entry was successfully inserted in the prefix table. Update
  271. // the data (BLOB) associated with it.
  272. // We do it outside the loop to prevent redundant comparisons within
  273. // the loop.
  274. pEntry->pData = pData;
  275. pTable->TotalEntries += 1;
  276. } else {
  277. pParentEntry = pLastInsertedEntry;
  278. while ( pParentEntry != NULL ) {
  279. PDFS_PREFIX_TABLE_ENTRY pMaybeTempEntry;
  280. pMaybeTempEntry = pParentEntry;
  281. pParentEntry = pParentEntry->pParentEntry;
  282. if ( --pMaybeTempEntry->Reference == 0 ) {
  283. //
  284. // If pParentEntry == NULL, pMaybeTempEntry is
  285. // pTable->RootEntry. Do not try to remove it.
  286. //
  287. if ( pParentEntry != NULL ) {
  288. REMOVE_FROM_CHILD_LIST(pMaybeTempEntry);
  289. REMOVE_FROM_BUCKET(pMaybeTempEntry);
  290. FREE_NAME_BUFFER( pMaybeTempEntry->PathSegment.Buffer );
  291. FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pMaybeTempEntry);
  292. }
  293. }
  294. else
  295. {
  296. break;
  297. }
  298. }
  299. }
  300. if ( NameBuffer != Buffer ) {
  301. PREFIX_TABLE_FREE_MEMORY( NameBuffer );
  302. }
  303. return status;
  304. }
  305. //+---------------------------------------------------------------------------
  306. //
  307. // Function: DfsFindUnicodePrefixLocked
  308. //
  309. // Synopsis: fn. for looking up a name segment in a prefix table
  310. //
  311. // Arguments: [pTable] -- the DFS prefix table instance
  312. //
  313. // [pPath] -- the path to be looked up.
  314. //
  315. // [pSuffix] -- the suffix that could not be found.
  316. //
  317. // Returns: a valid ptr if successfull, NULL otherwise
  318. //
  319. // History: 04-18-94 SethuR Created
  320. //
  321. // Notes:
  322. //
  323. //----------------------------------------------------------------------------
  324. NTSTATUS
  325. DfsFindUnicodePrefixLocked(
  326. IN PDFS_PREFIX_TABLE pTable,
  327. IN PUNICODE_STRING pPath,
  328. IN PUNICODE_STRING pSuffix,
  329. IN PVOID *ppData,
  330. OUT PBOOLEAN pSubStringMatch)
  331. {
  332. NTSTATUS status = STATUS_SUCCESS;
  333. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  334. if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
  335. return STATUS_INVALID_PARAMETER;
  336. }
  337. *ppData = NULL;
  338. if ( pPath->Length == 0 ) {
  339. status = STATUS_INVALID_PARAMETER;
  340. } else {
  341. status = _LookupPrefixTable(pTable,pPath,pSuffix,&pEntry, pSubStringMatch);
  342. // Update the BLOB placeholder with the results of the lookup.
  343. if ( status == STATUS_SUCCESS ) {
  344. *ppData = pEntry->pData;
  345. }
  346. }
  347. return status;
  348. }
  349. //+---------------------------------------------------------------------------
  350. //
  351. // Function: DfsRemoveFromPrefixTable
  352. //
  353. // Synopsis: private fn. for looking up a name segment in a prefix table
  354. //
  355. // Arguments: [pTable] -- the DFS prefix table instance
  356. //
  357. // [pPath] -- the path to be looked up.
  358. //
  359. // Returns: one of the following NTSTATUS codes
  360. // STATUS_SUCCESS -- call was successfull.
  361. // STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
  362. //
  363. // History: 04-18-94 SethuR Created
  364. //
  365. // Notes:
  366. //
  367. //----------------------------------------------------------------------------
  368. NTSTATUS DfsRemoveFromPrefixTableLocked(
  369. IN PDFS_PREFIX_TABLE pTable,
  370. IN PUNICODE_STRING pPath,
  371. IN PVOID pMatchingData)
  372. {
  373. NTSTATUS status = STATUS_SUCCESS;
  374. UNICODE_STRING Path,Suffix;
  375. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  376. if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
  377. return STATUS_INVALID_PARAMETER;
  378. }
  379. Suffix.Length = 0;
  380. Suffix.Buffer = NULL;
  381. Path.Length = pPath->Length;
  382. Path.MaximumLength = pPath->MaximumLength;
  383. Path.Buffer = &pPath->Buffer[0];
  384. if ( pPath->Length == 0 ) {
  385. return STATUS_SUCCESS;
  386. } else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
  387. if ( pPath->Length == sizeof(WCHAR) ) {
  388. if ( pTable->RootEntry.pData == NULL ) {
  389. status = STATUS_OBJECT_PATH_NOT_FOUND;
  390. return status;
  391. } else {
  392. pTable->RootEntry.pData = NULL;
  393. return STATUS_SUCCESS;
  394. }
  395. } else {
  396. Path.Length -= sizeof(WCHAR);
  397. Path.Buffer++;
  398. }
  399. }
  400. status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry,NULL);
  401. if ( NT_SUCCESS(status)&& (Suffix.Length == 0) ) {
  402. if ( (pMatchingData == NULL) || (pMatchingData == pEntry->pData) )
  403. {
  404. DfsRemovePrefixTableEntry(pTable, pEntry);
  405. pTable->TotalEntries -= 1;
  406. }
  407. else
  408. {
  409. status = STATUS_NOT_FOUND;
  410. }
  411. }
  412. return status;
  413. }
  414. NTSTATUS DfsReplaceInPrefixTableLocked(
  415. IN PDFS_PREFIX_TABLE pTable,
  416. IN PUNICODE_STRING pPath,
  417. IN PVOID pReplaceData,
  418. IN PVOID *ppMatchingData)
  419. {
  420. NTSTATUS status = STATUS_SUCCESS;
  421. UNICODE_STRING Path,Suffix;
  422. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  423. if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
  424. return STATUS_INVALID_PARAMETER;
  425. }
  426. Suffix.Length = 0;
  427. Suffix.Buffer = NULL;
  428. Path.Length = pPath->Length;
  429. Path.MaximumLength = pPath->MaximumLength;
  430. Path.Buffer = &pPath->Buffer[0];
  431. if ( pPath->Length == 0 ) {
  432. return STATUS_SUCCESS;
  433. } else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
  434. if ( pPath->Length == sizeof(WCHAR) ) {
  435. if ( pTable->RootEntry.pData == NULL ) {
  436. status = STATUS_OBJECT_PATH_NOT_FOUND;
  437. return status;
  438. } else {
  439. pTable->RootEntry.pData = NULL;
  440. return STATUS_SUCCESS;
  441. }
  442. } else {
  443. Path.Length -= sizeof(WCHAR);
  444. Path.Buffer++;
  445. }
  446. }
  447. status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry,NULL);
  448. if ( NT_SUCCESS(status)&& (Suffix.Length == 0) ) {
  449. if ( (*ppMatchingData == NULL) || (*ppMatchingData == pEntry->pData) ) {
  450. *ppMatchingData = pEntry->pData;
  451. pEntry->pData = pReplaceData;
  452. } else {
  453. status = STATUS_NOT_FOUND;
  454. }
  455. }
  456. if ( (status != STATUS_SUCCESS) && (*ppMatchingData == NULL) ) {
  457. status = DfsInsertInPrefixTableLocked( pTable,
  458. pPath,
  459. pReplaceData );
  460. }
  461. return status;
  462. }
  463. VOID
  464. DfsRemovePrefixTableEntry(
  465. IN PDFS_PREFIX_TABLE pTable,
  466. IN PDFS_PREFIX_TABLE_ENTRY pEntry )
  467. {
  468. UNREFERENCED_PARAMETER(pTable);
  469. // Destroy the association between the data associated with
  470. // this prefix.
  471. pEntry->pData = NULL;
  472. // found an exact match for the given path name in the table.
  473. // traverse the list of parent pointers and delete them if
  474. // required.
  475. while ( pEntry != NULL ) {
  476. if ( (--pEntry->Reference) == 0 ) {
  477. PDFS_PREFIX_TABLE_ENTRY pTempEntry = pEntry;
  478. pEntry = pEntry->pParentEntry;
  479. //
  480. // pEntry == NULL means pTempEntry is pTable->RootEntry.
  481. // Do not try to remove it.
  482. //
  483. if ( pEntry != NULL ) {
  484. REMOVE_FROM_CHILD_LIST(pTempEntry);
  485. REMOVE_FROM_BUCKET(pTempEntry);
  486. FREE_NAME_BUFFER( pTempEntry->PathSegment.Buffer );
  487. FREE_DFS_PREFIX_TABLE_ENTRY(pTable,pTempEntry);
  488. }
  489. }
  490. else
  491. {
  492. break;
  493. }
  494. }
  495. return;
  496. }
  497. //+---------------------------------------------------------------------------
  498. //
  499. // Function: DfsFreePrefixTable
  500. //
  501. // Synopsis: API for freeing a prefix table
  502. //
  503. // Arguments: [pTable] -- the DFS prefix table instance
  504. //
  505. // Returns: one of the following NTSTATUS codes
  506. // STATUS_SUCCESS -- call was successfull.
  507. //
  508. // History: 08-01-99 JHarper Created
  509. //
  510. // Notes:
  511. //
  512. //----------------------------------------------------------------------------
  513. NTSTATUS
  514. DfsDismantlePrefixTable(
  515. IN PDFS_PREFIX_TABLE pTable,
  516. IN VOID (*ProcessFunction)(PVOID pEntry))
  517. {
  518. NTSTATUS Status = STATUS_SUCCESS;
  519. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  520. PDFS_PREFIX_TABLE_ENTRY pSentinelEntry = NULL;
  521. ULONG i = 0;
  522. WRITE_LOCK_PREFIX_TABLE(pTable, Status);
  523. if ( Status != STATUS_SUCCESS )
  524. goto done;
  525. for ( i = 0; i < NO_OF_HASH_BUCKETS; i++ ) {
  526. pSentinelEntry = &pTable->Buckets[i].SentinelEntry;
  527. while ( pSentinelEntry->pNextEntry != pSentinelEntry ) {
  528. pEntry = pSentinelEntry->pNextEntry;
  529. REMOVE_FROM_BUCKET(pEntry);
  530. if ( (ProcessFunction) && (pEntry->pData) ) {
  531. ProcessFunction(pEntry->pData);
  532. }
  533. FREE_NAME_BUFFER( pEntry->PathSegment.Buffer );
  534. FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pEntry);
  535. }
  536. pTable->Buckets[i].NoOfEntries = 0;
  537. }
  538. if ( pTable->RootEntry.PathSegment.Buffer != NULL )
  539. FREE_NAME_BUFFER(pTable->RootEntry.PathSegment.Buffer);
  540. UNLOCK_PREFIX_TABLE(pTable);
  541. done:
  542. return Status;
  543. }
  544. NTSTATUS
  545. DfsDereferencePrefixTable(
  546. IN PDFS_PREFIX_TABLE pTable)
  547. {
  548. PDFS_OBJECT_HEADER pHeader = NULL;
  549. USHORT headerType = 0;
  550. LONG Ref = 0;
  551. if(pTable == NULL)
  552. {
  553. return STATUS_INVALID_PARAMETER;
  554. }
  555. pHeader = &pTable->DfsHeader;
  556. headerType = DfsGetHeaderType( pHeader );
  557. if (headerType != DFS_OT_PREFIX_TABLE) {
  558. return STATUS_UNSUCCESSFUL;
  559. }
  560. Ref = DfsDecrementReference( pHeader );
  561. if (Ref == 0) {
  562. DfsDeletePrefixTable( pTable );
  563. pTable = NULL;
  564. }
  565. return STATUS_SUCCESS;
  566. }
  567. VOID
  568. DfsDeletePrefixTable(
  569. IN PDFS_PREFIX_TABLE pTable)
  570. {
  571. if (pTable != NULL) {
  572. if (pTable->Flags & PREFIX_TABLE_LOCK_INITIALIZED) {
  573. UNINITIALIZE_PREFIX_TABLE_LOCK( pTable->pPrefixTableLock );
  574. pTable->Flags &= ~(PREFIX_TABLE_LOCK_INITIALIZED);
  575. }
  576. if (pTable->Flags & PREFIX_TABLE_LOCK_ALLOCATED) {
  577. FREE_PREFIX_TABLE_LOCK( pTable->pPrefixTableLock );
  578. pTable->pPrefixTableLock = NULL;
  579. pTable->Flags &= ~(PREFIX_TABLE_LOCK_ALLOCATED);
  580. }
  581. if (pTable->Flags & PREFIX_TABLE_TABLE_ALLOCATED) {
  582. FREE_PREFIX_TABLE( pTable );
  583. }
  584. }
  585. return;
  586. }
  587. //+---------------------------------------------------------------------------
  588. //
  589. // Function: _LookupPrefixTable
  590. //
  591. // Synopsis: private fn. for looking up a name segment in a prefix table
  592. //
  593. // Arguments: [pTable] -- the DFS prefix table instance
  594. //
  595. // [pPath] -- the path to be looked up.
  596. //
  597. // [pSuffix] -- the suffix that could not be found.
  598. //
  599. // [ppEntry] -- placeholder for the matching entry for the prefix.
  600. //
  601. //
  602. // Returns: one of the following NTSTATUS codes
  603. // STATUS_SUCCESS -- call was successfull.
  604. // STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
  605. //
  606. // History: 04-18-94 SethuR Created
  607. //
  608. // Notes:
  609. //
  610. //----------------------------------------------------------------------------
  611. NTSTATUS _LookupPrefixTable(
  612. PDFS_PREFIX_TABLE pTable,
  613. UNICODE_STRING *pPath,
  614. UNICODE_STRING *pSuffix,
  615. PDFS_PREFIX_TABLE_ENTRY *ppEntry,
  616. OUT PBOOLEAN pSubStringMatch )
  617. {
  618. NTSTATUS status = STATUS_SUCCESS;
  619. UNICODE_STRING Path = *pPath;
  620. WCHAR Buffer[MAX_PATH_SEGMENT_SIZE];
  621. PWCHAR NameBuffer = Buffer;
  622. USHORT cbNameBuffer = sizeof(Buffer);
  623. UNICODE_STRING Name;
  624. ULONG BucketNo;
  625. BOOLEAN fPrefixFound = FALSE;
  626. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  627. PDFS_PREFIX_TABLE_ENTRY pParentEntry = &pTable->RootEntry;
  628. BOOLEAN fNameFound = FALSE;
  629. BOOLEAN SubStringMatch = TRUE;
  630. // The \ is treated as a special case. The test for all names starting with
  631. // a delimiter is done before we initiate the complete search process.
  632. if ( Path.Buffer[0] == PATH_DELIMITER ) {
  633. Path.Length = Path.Length - sizeof(WCHAR);
  634. Path.Buffer += 1; // Skip the path delimiter at the beginning.
  635. if ( pTable->RootEntry.pData != NULL ) {
  636. fPrefixFound = TRUE;
  637. *pSuffix = Path;
  638. *ppEntry = &pTable->RootEntry;
  639. }
  640. }
  641. if ( Path.Length >= MAX_PATH_SEGMENT_SIZE ) {
  642. NameBuffer = PREFIX_TABLE_ALLOCATE_MEMORY(Path.Length + sizeof(WCHAR));
  643. if ( NameBuffer == NULL ) {
  644. return( STATUS_INSUFFICIENT_RESOURCES );
  645. } else {
  646. cbNameBuffer = Path.Length + sizeof(WCHAR);
  647. }
  648. }
  649. while ( Path.Length > 0 ) {
  650. Name.Length = 0;
  651. Name.Buffer = NameBuffer;
  652. Name.MaximumLength = cbNameBuffer;
  653. if ( pTable->Flags & PREFIX_TABLE_CASE_SENSITIVE ) {
  654. SPLIT_CASE_SENSITIVE_PATH(&Path,&Name,BucketNo);
  655. } else {
  656. SPLIT_CASE_INSENSITIVE_PATH(&Path,&Name,BucketNo);
  657. }
  658. if ( Name.Length > 0 ) {
  659. // Process the name segment
  660. // Lookup the bucket to see if the entry exists.
  661. LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
  662. if ( pEntry != NULL ) {
  663. // Cache the data available for this prefix if any.
  664. if ( pEntry->pData != NULL ) {
  665. *pSuffix = Path;
  666. *ppEntry = pEntry;
  667. fPrefixFound = TRUE;
  668. }
  669. } else {
  670. SubStringMatch = FALSE;
  671. break;
  672. }
  673. // set the stage for processing the next name segment.
  674. pParentEntry = pEntry;
  675. }
  676. }
  677. if ( !fPrefixFound ) {
  678. status = STATUS_OBJECT_PATH_NOT_FOUND;
  679. }
  680. if ( NameBuffer != Buffer ) {
  681. PREFIX_TABLE_FREE_MEMORY( NameBuffer );
  682. }
  683. if (pSubStringMatch != NULL)
  684. {
  685. *pSubStringMatch = SubStringMatch;
  686. }
  687. return status;
  688. }
  689. NTSTATUS
  690. DfsInsertInPrefixTable(
  691. IN PDFS_PREFIX_TABLE pTable,
  692. IN PUNICODE_STRING pPath,
  693. IN PVOID pData)
  694. {
  695. NTSTATUS status;
  696. WRITE_LOCK_PREFIX_TABLE(pTable, status);
  697. if ( status != STATUS_SUCCESS )
  698. goto done;
  699. status = DfsInsertInPrefixTableLocked(pTable, pPath, pData);
  700. UNLOCK_PREFIX_TABLE(pTable);
  701. done:
  702. return status;
  703. }
  704. NTSTATUS
  705. DfsFindUnicodePrefix(
  706. IN PDFS_PREFIX_TABLE pTable,
  707. IN PUNICODE_STRING pPath,
  708. IN PUNICODE_STRING pSuffix,
  709. IN PVOID *ppData)
  710. {
  711. NTSTATUS Status;
  712. READ_LOCK_PREFIX_TABLE(pTable, Status);
  713. if ( Status != STATUS_SUCCESS )
  714. goto done;
  715. Status = DfsFindUnicodePrefixLocked(pTable, pPath, pSuffix, ppData,NULL);
  716. UNLOCK_PREFIX_TABLE(pTable);
  717. done:
  718. return Status;
  719. }
  720. NTSTATUS
  721. DfsRemoveFromPrefixTable(
  722. IN PDFS_PREFIX_TABLE pTable,
  723. IN PUNICODE_STRING pPath,
  724. IN PVOID pMatchingData)
  725. {
  726. NTSTATUS Status;
  727. WRITE_LOCK_PREFIX_TABLE(pTable, Status);
  728. if ( Status != STATUS_SUCCESS )
  729. goto done;
  730. Status = DfsRemoveFromPrefixTableLocked(pTable, pPath, pMatchingData);
  731. UNLOCK_PREFIX_TABLE(pTable);
  732. done:
  733. return Status;
  734. }
  735. NTSTATUS
  736. DfsRemoveFromPrefixTableLockedEx(
  737. IN PDFS_PREFIX_TABLE pTable,
  738. IN PUNICODE_STRING pPath,
  739. IN PVOID pMatchingData,
  740. IN PVOID *pReturnedData)
  741. {
  742. NTSTATUS status = STATUS_SUCCESS;
  743. UNICODE_STRING Path,Suffix;
  744. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  745. UNREFERENCED_PARAMETER(pMatchingData);
  746. if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
  747. return STATUS_INVALID_PARAMETER;
  748. }
  749. Suffix.Length = 0;
  750. Suffix.Buffer = NULL;
  751. Path.Length = pPath->Length;
  752. Path.MaximumLength = pPath->MaximumLength;
  753. Path.Buffer = &pPath->Buffer[0];
  754. if ( pPath->Length == 0 ) {
  755. return STATUS_SUCCESS;
  756. } else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
  757. if ( pPath->Length == sizeof(WCHAR) ) {
  758. if ( pTable->RootEntry.pData == NULL ) {
  759. status = STATUS_OBJECT_PATH_NOT_FOUND;
  760. return status;
  761. } else {
  762. pTable->RootEntry.pData = NULL;
  763. return STATUS_SUCCESS;
  764. }
  765. } else {
  766. Path.Length -= sizeof(WCHAR);
  767. Path.Buffer++;
  768. }
  769. }
  770. status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry,NULL);
  771. if ( NT_SUCCESS(status)&& (Suffix.Length == 0) )
  772. {
  773. *pReturnedData = pEntry->pData;
  774. DfsRemovePrefixTableEntry(pTable, pEntry);
  775. }
  776. return status;
  777. }
  778. NTSTATUS
  779. DfsRemoveFromPrefixTableEx(
  780. IN PDFS_PREFIX_TABLE pTable,
  781. IN PUNICODE_STRING pPath,
  782. IN PVOID pMatchingData,
  783. IN PVOID *pReturnedData)
  784. {
  785. NTSTATUS Status;
  786. WRITE_LOCK_PREFIX_TABLE(pTable, Status);
  787. if ( Status != STATUS_SUCCESS )
  788. goto done;
  789. Status = DfsRemoveFromPrefixTableLockedEx(pTable, pPath, pMatchingData, pReturnedData);
  790. UNLOCK_PREFIX_TABLE(pTable);
  791. done:
  792. return Status;
  793. }
  794. NTSTATUS
  795. DfsReplaceInPrefixTable(
  796. IN PDFS_PREFIX_TABLE pTable,
  797. IN PUNICODE_STRING pPath,
  798. IN PVOID pReplaceData,
  799. IN PVOID pMatchingData)
  800. {
  801. NTSTATUS Status;
  802. IN PVOID pGotData = pMatchingData;
  803. WRITE_LOCK_PREFIX_TABLE(pTable, Status);
  804. if ( Status != STATUS_SUCCESS )
  805. goto done;
  806. Status = DfsReplaceInPrefixTableLocked(pTable,
  807. pPath,
  808. pReplaceData,
  809. &pGotData);
  810. UNLOCK_PREFIX_TABLE(pTable);
  811. done:
  812. return Status;
  813. }
  814. #if !defined (KERNEL_MODE)
  815. VOID
  816. DumpParentName(
  817. IN PDFS_PREFIX_TABLE_ENTRY pEntry)
  818. {
  819. if ( pEntry->pParentEntry != NULL ) {
  820. DumpParentName(pEntry->pParentEntry);
  821. if ( pEntry->pParentEntry->PathSegment.Buffer != NULL )
  822. printf("\\%wZ", &pEntry->pParentEntry->PathSegment);
  823. }
  824. return;
  825. }
  826. VOID
  827. DfsDumpPrefixTable(
  828. PDFS_PREFIX_TABLE pPrefixTable,
  829. IN VOID (*DumpFunction)(PVOID pEntry))
  830. {
  831. PPREFIX_TABLE_BUCKET pBucket;
  832. PDFS_PREFIX_TABLE_ENTRY pCurEntry = NULL;
  833. ULONG i, NumEntries;
  834. NTSTATUS Status;
  835. printf("Prefix table %p\n", pPrefixTable);
  836. printf("Prefix table flags %x\n", pPrefixTable->Flags);
  837. printf("Prefix table Lock %p\n", pPrefixTable->pPrefixTableLock);
  838. READ_LOCK_PREFIX_TABLE(pPrefixTable, Status);
  839. if (Status != STATUS_SUCCESS)
  840. return NOTHING;
  841. for ( i = 0; i < NO_OF_HASH_BUCKETS; i++ ) {
  842. pBucket = &pPrefixTable->Buckets[i];
  843. pCurEntry = pBucket->SentinelEntry.pNextEntry;
  844. NumEntries = 0;
  845. while ( pCurEntry != &pBucket->SentinelEntry ) {
  846. NumEntries++;
  847. if ( pCurEntry->pData != NULL ) {
  848. printf("Found Prefix data %p in Bucket %d\n", pCurEntry->pData, i);
  849. DumpParentName(pCurEntry);
  850. printf("\\%wZ\n", &pCurEntry->PathSegment);
  851. if ( DumpFunction ) {
  852. DumpFunction(pCurEntry->pData);
  853. }
  854. }
  855. pCurEntry = pCurEntry->pNextEntry;
  856. }
  857. printf("Number of entries in Bucket %d is %d\n", i, NumEntries);
  858. }
  859. UNLOCK_PREFIX_TABLE(pPrefixTable);
  860. }
  861. #endif
  862. NTSTATUS
  863. DfsPrefixTableAcquireWriteLock(
  864. PDFS_PREFIX_TABLE pPrefixTable )
  865. {
  866. NTSTATUS Status;
  867. WRITE_LOCK_PREFIX_TABLE(pPrefixTable, Status);
  868. return Status;
  869. }
  870. NTSTATUS
  871. DfsPrefixTableAcquireReadLock(
  872. PDFS_PREFIX_TABLE pPrefixTable )
  873. {
  874. NTSTATUS Status;
  875. READ_LOCK_PREFIX_TABLE(pPrefixTable, Status);
  876. return Status;
  877. }
  878. NTSTATUS
  879. DfsPrefixTableReleaseLock(
  880. PDFS_PREFIX_TABLE pPrefixTable )
  881. {
  882. UNLOCK_PREFIX_TABLE(pPrefixTable);
  883. return STATUS_SUCCESS;
  884. }
  885. NTSTATUS
  886. DfsEnumeratePrefixTableLocked(
  887. IN PDFS_PREFIX_TABLE pTable,
  888. IN VOID (*ProcessFunction)(PVOID pEntry, PVOID pContext),
  889. LPVOID lpvClientContext)
  890. {
  891. NTSTATUS Status = STATUS_SUCCESS;
  892. PPREFIX_TABLE_BUCKET pBucket = NULL;
  893. PDFS_PREFIX_TABLE_ENTRY pCurEntry = NULL;
  894. ULONG i = 0;
  895. if(pTable->TotalEntries == 0)
  896. {
  897. return Status;
  898. }
  899. for ( i = 0; i < NO_OF_HASH_BUCKETS; i++ )
  900. {
  901. pBucket = &pTable->Buckets[i];
  902. pCurEntry = pBucket->SentinelEntry.pNextEntry;
  903. while ( pCurEntry != &pBucket->SentinelEntry )
  904. {
  905. if ( pCurEntry->pData != NULL )
  906. {
  907. ProcessFunction(pCurEntry->pData, lpvClientContext);
  908. }
  909. pCurEntry = pCurEntry->pNextEntry;
  910. }
  911. }
  912. return Status;
  913. }