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.

575 lines
18 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 DfsDbgTrace(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, DfsFreePrefixTable )
  28. #pragma alloc_text( PAGE, DfsInitializePrefixTable )
  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. #endif // ALLOC_PRAGMA
  34. //+---------------------------------------------------------------------------
  35. //
  36. // Function: DfsInitializePrefixTable
  37. //
  38. // Synopsis: API for initializing the prefix table
  39. //
  40. // Arguments: [pTable] -- the DFS prefix table instance
  41. //
  42. // Returns: one of the following NTSTATUS codes
  43. // STATUS_SUCCESS -- call was successfull.
  44. //
  45. // History: 04-18-94 SethuR Created
  46. //
  47. // Notes:
  48. //
  49. //----------------------------------------------------------------------------
  50. NTSTATUS DfsInitializePrefixTable(PDFS_PREFIX_TABLE pTable, BOOLEAN fCaseSensitive)
  51. {
  52. NTSTATUS status = STATUS_SUCCESS;
  53. DfsDbgTrace(+1, Dbg,"DfsInitializePrefixTable -- Entry\n", 0);
  54. if (pTable != NULL)
  55. {
  56. ULONG i;
  57. // Initialize flags
  58. pTable->CaseSensitive = fCaseSensitive;
  59. // Initialize the root entry
  60. INITIALIZE_PREFIX_TABLE_ENTRY(&pTable->RootEntry);
  61. // Initialize the various buckets.
  62. for (i = 0;i < NO_OF_HASH_BUCKETS;i++)
  63. {
  64. INITIALIZE_BUCKET(pTable->Buckets[i]);
  65. }
  66. // Initialize the name page list.
  67. pTable->NamePageList.pFirstPage = ALLOCATE_NAME_PAGE();
  68. if (pTable->NamePageList.pFirstPage != NULL)
  69. {
  70. INITIALIZE_NAME_PAGE(pTable->NamePageList.pFirstPage);
  71. // Initialize the prefix table entry allocation mechanism.
  72. status = _InitializePrefixTableEntryAllocation(pTable);
  73. }
  74. else
  75. {
  76. status = STATUS_NO_MEMORY;
  77. DfsDbgTrace(0, Dbg,"DfsInitializePrefixTable Error -- %lx\n", ULongToPtr(status) );
  78. }
  79. }
  80. else
  81. {
  82. status = STATUS_INVALID_PARAMETER;
  83. DfsDbgTrace(0, Dbg,"DfsInitializePrefixTable Error -- %lx\n", ULongToPtr(status) );
  84. }
  85. DfsDbgTrace(-1, Dbg, "DfsInitializePrefixTable -- Exit\n", 0);
  86. return status;
  87. }
  88. //+---------------------------------------------------------------------------
  89. //
  90. // Function: DfsInsertInPrefixTable
  91. //
  92. // Synopsis: API for inserting a path in the prefix table
  93. //
  94. // Arguments: [pTable] -- the DFS prefix table instance
  95. //
  96. // [pPath] -- the path to be looked up.
  97. //
  98. // [pData] -- BLOB associated with the path
  99. //
  100. // Returns: one of the following NTSTATUS codes
  101. // STATUS_SUCCESS -- call was successfull.
  102. //
  103. // History: 04-18-94 SethuR Created
  104. //
  105. // Notes:
  106. //
  107. //----------------------------------------------------------------------------
  108. NTSTATUS DfsInsertInPrefixTable(PDFS_PREFIX_TABLE pTable,
  109. PUNICODE_STRING pPath,
  110. PVOID pData)
  111. {
  112. NTSTATUS status = STATUS_SUCCESS;
  113. WCHAR Buffer[MAX_PATH_SEGMENT_SIZE];
  114. PWCHAR NameBuffer = Buffer;
  115. USHORT cbNameBuffer = sizeof(Buffer);
  116. UNICODE_STRING Path,Name;
  117. ULONG BucketNo;
  118. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  119. PDFS_PREFIX_TABLE_ENTRY pParentEntry = NULL;
  120. BOOLEAN fNameFound = FALSE;
  121. DfsDbgTrace(+1, Dbg, "DfsInsertInPrefixTable -- Entry\n", 0);
  122. // There is one special case, i.e., in which the prefix is '\'.
  123. // Since this is the PATH_DELIMITER which is treated in a special
  124. // way, we do the processing upfront.
  125. if (pPath->Length == 0)
  126. {
  127. return STATUS_SUCCESS;
  128. }
  129. else if ((pPath->Length == sizeof(WCHAR)) &&
  130. (pPath->Buffer[0] == PATH_DELIMITER))
  131. {
  132. pTable->RootEntry.pData = pData;
  133. return STATUS_SUCCESS;
  134. }
  135. else
  136. {
  137. Path.Length = pPath->Length - sizeof(WCHAR);
  138. Path.MaximumLength = pPath->MaximumLength;
  139. Path.Buffer = &pPath->Buffer[1];
  140. pParentEntry = &pTable->RootEntry;
  141. }
  142. if (Path.Length > MAX_PATH_SEGMENT_SIZE * sizeof(WCHAR) ) {
  143. NameBuffer = ExAllocatePoolWithTag( NonPagedPool, Path.Length + sizeof(WCHAR), ' puM' );
  144. if (NameBuffer == NULL) {
  145. DfsDbgTrace(0, Dbg, "Unable to allocate %d non-paged bytes\n", (Path.Length + sizeof(WCHAR)) );
  146. return( STATUS_INSUFFICIENT_RESOURCES );
  147. } else {
  148. cbNameBuffer = Path.Length + sizeof(WCHAR);
  149. }
  150. }
  151. while (Path.Length > 0)
  152. {
  153. Name.Length = 0;
  154. Name.Buffer = NameBuffer;
  155. Name.MaximumLength = cbNameBuffer;
  156. // Process the name segment
  157. if (pTable->CaseSensitive)
  158. {
  159. SPLIT_CASE_SENSITIVE_PATH(&Path,&Name,BucketNo);
  160. }
  161. else
  162. {
  163. SPLIT_CASE_INSENSITIVE_PATH(&Path,&Name,BucketNo);
  164. }
  165. if (Name.Length > 0)
  166. {
  167. // Lookup the table to see if the name segment already exists.
  168. DfsDbgTrace(0, Dbg, "LOOKUP_BUCKET: Bucket(%ld)\n", ULongToPtr(BucketNo) );
  169. DfsDbgTrace(0, Dbg, " for Name(%wZ)\n", &Name);
  170. LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
  171. DfsDbgTrace(0, Dbg, "returned pEntry(%lx)", pEntry);
  172. DfsDbgTrace(0, Dbg, " fNameFound(%s)\n", fNameFound ? "TRUE" : "FALSE");
  173. if (pEntry == NULL)
  174. {
  175. // Initialize the new entry and initialize the name segment.
  176. pEntry = ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable);
  177. if (pEntry != NULL)
  178. {
  179. INITIALIZE_PREFIX_TABLE_ENTRY(pEntry);
  180. // Allocate the name space entry if there is no entry in the
  181. // name page.
  182. if (!fNameFound || fNameFound)
  183. {
  184. PWSTR pBuffer;
  185. // Allocate the entry in the name page.
  186. pBuffer = ALLOCATE_NAME_PAGE_ENTRY((pTable->NamePageList),(Name.Length/sizeof(WCHAR)));
  187. if (pBuffer != NULL)
  188. {
  189. RtlZeroMemory(pBuffer,Name.Length);
  190. RtlCopyMemory(pBuffer,Name.Buffer,Name.Length);
  191. pEntry->PathSegment = Name;
  192. pEntry->PathSegment.Buffer = pBuffer;
  193. }
  194. else
  195. {
  196. status = STATUS_NO_MEMORY;
  197. break;
  198. }
  199. }
  200. else
  201. pEntry->PathSegment = Name;
  202. // thread the entry to point to the parent.
  203. pEntry->pParentEntry = pParentEntry;
  204. // Insert the entry in the bucket.
  205. INSERT_IN_BUCKET(pTable->Buckets[BucketNo],pEntry);
  206. // Insert the entry in the parent's children list.
  207. INSERT_IN_CHILD_LIST(pEntry, pParentEntry);
  208. }
  209. else
  210. {
  211. status = STATUS_NO_MEMORY;
  212. DfsDbgTrace(0, Dbg, "DfsInsertInPrefixTable Error -- %lx\n", ULongToPtr(status) );
  213. break;
  214. }
  215. }
  216. else
  217. {
  218. // Increment the no. of children associated with this entry
  219. pEntry->NoOfChildren++;
  220. }
  221. pParentEntry = pEntry;
  222. }
  223. else
  224. {
  225. status = STATUS_INVALID_PARAMETER;
  226. DfsDbgTrace(0, Dbg, "DfsInsertInPrefixTable Error -- %lx\n", ULongToPtr(status) );
  227. break;
  228. }
  229. }
  230. // If a new entry was not successfully inserted we need to walk up the chain
  231. // of parent entries to undo the increment to the reference count and
  232. // remove the entries from their parent links.
  233. if (NT_SUCCESS(status))
  234. {
  235. // The entry was successfully inserted in the prefix table. Update
  236. // the data (BLOB) associated with it.
  237. // We do it outside the loop to prevent redundant comparisons within
  238. // the loop.
  239. pEntry->pData = pData;
  240. }
  241. else
  242. {
  243. while (pParentEntry != NULL)
  244. {
  245. PDFS_PREFIX_TABLE_ENTRY pMaybeTempEntry;
  246. pMaybeTempEntry = pParentEntry;
  247. pParentEntry = pParentEntry->pParentEntry;
  248. if (--pMaybeTempEntry->NoOfChildren == 0) {
  249. //
  250. // If pParentEntry == NULL, pMaybeTempEntry is
  251. // pTable->RootEntry. Do not try to remove it.
  252. //
  253. if (pParentEntry != NULL) {
  254. REMOVE_FROM_CHILD_LIST(pMaybeTempEntry);
  255. REMOVE_FROM_BUCKET(pMaybeTempEntry);
  256. FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pMaybeTempEntry);
  257. }
  258. }
  259. }
  260. }
  261. if (NameBuffer != Buffer) {
  262. ExFreePool( NameBuffer );
  263. }
  264. DfsDbgTrace(-1, Dbg, "DfsInsertInPrefixTable -- Exit\n", 0);
  265. return status;
  266. }
  267. //+---------------------------------------------------------------------------
  268. //
  269. // Function: DfsLookupPrefixTable
  270. //
  271. // Synopsis: private fn. for looking up a name segment in a prefix table
  272. //
  273. // Arguments: [pTable] -- the DFS prefix table instance
  274. //
  275. // [pPath] -- the path to be looked up.
  276. //
  277. // [pSuffix] -- the suffix that could not be found.
  278. //
  279. // [ppData] -- placeholder for the BLOB for the prefix.
  280. //
  281. //
  282. // Returns: one of the following NTSTATUS codes
  283. // STATUS_SUCCESS -- call was successfull.
  284. // STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
  285. //
  286. // History: 04-18-94 SethuR Created
  287. //
  288. // Notes:
  289. //
  290. //----------------------------------------------------------------------------
  291. NTSTATUS DfsLookupPrefixTable(PDFS_PREFIX_TABLE pTable,
  292. PUNICODE_STRING pPath,
  293. PUNICODE_STRING pSuffix,
  294. PVOID *ppData)
  295. {
  296. NTSTATUS status = STATUS_SUCCESS;
  297. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  298. DfsDbgTrace(+1, Dbg, "DfsLookupInPrefixTable -- Entry\n", 0);
  299. if (pPath->Length == 0)
  300. {
  301. DfsDbgTrace(-1, Dbg, "DfsLookupInPrefixTable Exited - Null Path!\n", 0);
  302. return STATUS_SUCCESS;
  303. }
  304. else
  305. {
  306. status = _LookupPrefixTable(pTable,pPath,pSuffix,&pEntry);
  307. // Update the BLOB placeholder with the results of the lookup.
  308. if (NT_SUCCESS(status))
  309. {
  310. *ppData = pEntry->pData;
  311. }
  312. DfsDbgTrace(-1, Dbg, "DfsLookupInPrefixTable -- Exit\n", 0);
  313. return status;
  314. }
  315. }
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Function: DfsFindUnicodePrefix
  319. //
  320. // Synopsis: fn. for looking up a name segment in a prefix table
  321. //
  322. // Arguments: [pTable] -- the DFS prefix table instance
  323. //
  324. // [pPath] -- the path to be looked up.
  325. //
  326. // [pSuffix] -- the suffix that could not be found.
  327. //
  328. // Returns: a valid ptr if successfull, NULL otherwise
  329. //
  330. // History: 04-18-94 SethuR Created
  331. //
  332. // Notes:
  333. //
  334. //----------------------------------------------------------------------------
  335. PVOID DfsFindUnicodePrefix(PDFS_PREFIX_TABLE pTable,
  336. PUNICODE_STRING pPath,
  337. PUNICODE_STRING pSuffix)
  338. {
  339. NTSTATUS status = STATUS_SUCCESS;
  340. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  341. PVOID pData = NULL;
  342. DfsDbgTrace(+1, Dbg, "DfsFindUnicodePrefix -- Entry\n", 0);
  343. if (pPath->Length == 0)
  344. {
  345. DfsDbgTrace(-1, Dbg, "DfsFindUnicodePrefix Exited - Null Path!\n", 0);
  346. return NULL;
  347. }
  348. else
  349. {
  350. status = _LookupPrefixTable(pTable,pPath,pSuffix,&pEntry);
  351. // Update the BLOB placeholder with the results of the lookup.
  352. if (NT_SUCCESS(status))
  353. {
  354. pData = pEntry->pData;
  355. }
  356. DfsDbgTrace(-1, Dbg, "DfsFindUnicodePrefix -- Exit\n", 0);
  357. return pData;
  358. }
  359. }
  360. //+---------------------------------------------------------------------------
  361. //
  362. // Function: DfsRemoveFromPrefixTable
  363. //
  364. // Synopsis: private fn. for looking up a name segment in a prefix table
  365. //
  366. // Arguments: [pTable] -- the DFS prefix table instance
  367. //
  368. // [pPath] -- the path to be looked up.
  369. //
  370. // Returns: one of the following NTSTATUS codes
  371. // STATUS_SUCCESS -- call was successfull.
  372. // STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
  373. //
  374. // History: 04-18-94 SethuR Created
  375. //
  376. // Notes:
  377. //
  378. //----------------------------------------------------------------------------
  379. NTSTATUS DfsRemoveFromPrefixTable(PDFS_PREFIX_TABLE pTable,
  380. PUNICODE_STRING pPath)
  381. {
  382. NTSTATUS status = STATUS_SUCCESS;
  383. UNICODE_STRING Path,Suffix;
  384. ULONG BucketNo;
  385. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  386. DfsDbgTrace(+1, Dbg, "DfsRemoveFromPrefixTable -- Entry\n", 0);
  387. Suffix.Length = 0;
  388. Suffix.Buffer = NULL;
  389. if (pPath->Length == 0)
  390. {
  391. DfsDbgTrace(-1, Dbg, "DfsRemoveFromPrefixTable Exited -- Null Path!\n", 0);
  392. return STATUS_SUCCESS;
  393. }
  394. else if ((pPath->Length == sizeof(WCHAR)) &&
  395. (pPath->Buffer[0] == PATH_DELIMITER))
  396. {
  397. if (pTable->RootEntry.pData == NULL)
  398. {
  399. status = STATUS_OBJECT_PATH_NOT_FOUND;
  400. }
  401. else
  402. {
  403. pTable->RootEntry.pData = NULL;
  404. DfsDbgTrace(-1, Dbg, "DfsRemoveFromPrefixTable Exited.\n", 0);
  405. return STATUS_SUCCESS;
  406. }
  407. }
  408. else
  409. {
  410. Path.Length = pPath->Length - sizeof(WCHAR);
  411. Path.MaximumLength = pPath->MaximumLength;
  412. Path.Buffer = &pPath->Buffer[1];
  413. status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry);
  414. if (NT_SUCCESS(status) && (Suffix.Length == 0))
  415. {
  416. // Destroy the association between the data associated with
  417. // this prefix.
  418. pEntry->pData = NULL;
  419. // found an exact match for the given path name in the table.
  420. // traverse the list of parent pointers and delete them if
  421. // required.
  422. while (pEntry != NULL)
  423. {
  424. if ((--pEntry->NoOfChildren) == 0)
  425. {
  426. PDFS_PREFIX_TABLE_ENTRY pTempEntry = pEntry;
  427. pEntry = pEntry->pParentEntry;
  428. //
  429. // pEntry == NULL means pTempEntry is pTable->RootEntry.
  430. // Do not try to remove it.
  431. //
  432. if (pEntry != NULL) {
  433. REMOVE_FROM_CHILD_LIST(pTempEntry);
  434. REMOVE_FROM_BUCKET(pTempEntry);
  435. FREE_DFS_PREFIX_TABLE_ENTRY(pTable,pTempEntry);
  436. }
  437. }
  438. else
  439. break;
  440. }
  441. }
  442. }
  443. DfsDbgTrace(-1, Dbg, "DfsRemoveFromPrefixTable -- Exit\n", 0);
  444. return status;
  445. }
  446. //+---------------------------------------------------------------------------
  447. //
  448. // Function: DfsFreePrefixTable
  449. //
  450. // Synopsis: API for freeing a prefix table
  451. //
  452. // Arguments: [pTable] -- the DFS prefix table instance
  453. //
  454. // Returns: one of the following NTSTATUS codes
  455. // STATUS_SUCCESS -- call was successfull.
  456. //
  457. // History: 08-01-99 JHarper Created
  458. //
  459. // Notes:
  460. //
  461. //----------------------------------------------------------------------------
  462. NTSTATUS
  463. DfsFreePrefixTable(
  464. PDFS_PREFIX_TABLE pTable)
  465. {
  466. NTSTATUS status = STATUS_SUCCESS;
  467. PNAME_PAGE pNamePage = NULL;
  468. PNAME_PAGE pNextPage = NULL;
  469. PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
  470. PDFS_PREFIX_TABLE_ENTRY pSentinelEntry = NULL;
  471. ULONG i;
  472. if (pTable != NULL) {
  473. for (i = 0; i < NO_OF_HASH_BUCKETS; i++) {
  474. pSentinelEntry = &pTable->Buckets[i].SentinelEntry;
  475. while (pSentinelEntry->pNextEntry != pSentinelEntry) {
  476. pEntry = pSentinelEntry->pNextEntry;
  477. REMOVE_FROM_BUCKET(pEntry);
  478. if (pEntry->PathSegment.Buffer != NULL)
  479. ExFreePool(pEntry->PathSegment.Buffer);
  480. ExFreePool(pEntry);
  481. }
  482. pTable->Buckets[i].NoOfEntries = 0;
  483. }
  484. if (pTable->RootEntry.PathSegment.Buffer != NULL)
  485. ExFreePool(pTable->RootEntry.PathSegment.Buffer);
  486. for (pNamePage = pTable->NamePageList.pFirstPage;
  487. pNamePage;
  488. pNamePage = pNextPage
  489. ) {
  490. pNextPage = pNamePage->pNextPage;
  491. ExFreePool(pNamePage);
  492. }
  493. } else {
  494. status = STATUS_INVALID_PARAMETER;
  495. }
  496. return status;
  497. }