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.

503 lines
23 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: prefix.hxx
  7. //
  8. // Contents: PREFIX table definition
  9. //
  10. // History: SethuR -- Implemented
  11. //
  12. // Notes: The DFS prefix table data structure consists of three
  13. // entities and methods to manipulate them. They are the
  14. // DFS_PREFIX_TABLE_ENTRY,DFS_PREFIX_TABLE_BUCKET and the
  15. // DFS_PREFIX_TABLE.
  16. //
  17. // The DFS_PREFIX_TABLE is a hash table of DFS_PREFIX_TABLE_ENTRY's
  18. // wherein collisions are resolved through linear chaining. The
  19. // hash table is organized as an array of collision lists
  20. // (DFS_PREFIX_TABLE_BUCKET). A brief description with each of
  21. // these entities is attached to the declaration.
  22. //
  23. // There are certain characterstics that distinguish this
  24. // hash table from other hash tables. These are the extensions
  25. // provided to accomodate the special operations.
  26. //
  27. //--------------------------------------------------------------------------
  28. #ifndef __PREFIXP_H__
  29. #define __PREFIXP_H__
  30. #include <prefix.h>
  31. //--------------------------------------------------------------------------
  32. //
  33. // PREFIX TABLE UTILITIES
  34. //
  35. // A Path is a sequence of one or more name segments alternated with a
  36. // distinguished concatenation character ( typically \ in FAT,NTFS,HPFS and
  37. // / in UNIX file systems). These utilities are used to split a given path
  38. // into the first path segment followed by the remainder of the path.
  39. //
  40. // SPLIT_PATH("foo\bar\bar1",Name,RemainingPath) binds Name to foo and
  41. // RemainingPath to bar\bar1
  42. //
  43. // Similarly PROCESS_CASE_SENSITIVE_NAME and PROCESS_CASE_INSENSITIVE_NAME
  44. // compute the hash signatures ( bucket no. ) for a given string.
  45. //
  46. //--------------------------------------------------------------------------
  47. //
  48. // MAX_PATH_SEGMENT_SIZE is simply used as a good size buffer to do prefix
  49. // lookups and insertions. This should save us from having to allocate for
  50. // most cases.
  51. //
  52. #define MAX_PATH_SEGMENT_SIZE 256
  53. #define PATH_DELIMITER L'\\'
  54. //+---------------------------------------------------------------------------
  55. //
  56. // Function: SPLIT_CASE_INSENSITIVE_PATH
  57. //
  58. // Synopsis: Split the path name around deleimiters.
  59. //
  60. // Arguments: [pPath] -- path to be split(PUNICODE_STRING)
  61. //
  62. // [pName] -- the leftmost component of the path(PUNICODE_STRING)
  63. //
  64. // [BucketNo] -- Hash Bucket no. corresponding to the name(ULONG)
  65. //
  66. // SideEffects: the UNICODE_STRING pointed to by pName and BucketNo are
  67. // modified.
  68. //
  69. // PreRequisite: pName be associated with a valid buffer.
  70. //
  71. // History: 04-18-94 SethuR Created
  72. //
  73. // Notes: defined as a macro for inlining
  74. //
  75. //----------------------------------------------------------------------------
  76. #define SPLIT_CASE_INSENSITIVE_PATH(pPath,pName,BucketNo) \
  77. { \
  78. WCHAR *pPathBuffer = (pPath)->Buffer; \
  79. WCHAR *pNameBuffer = (pName)->Buffer; \
  80. WCHAR *pPathBufferEnd = &pPathBuffer[(pPath)->Length / sizeof(WCHAR)]; \
  81. \
  82. BucketNo = 0; \
  83. while ((pPathBufferEnd != pPathBuffer) && \
  84. ((*pNameBuffer = *pPathBuffer++) != PATH_DELIMITER)) \
  85. { \
  86. *pNameBuffer = (*pNameBuffer < L'a') \
  87. ? *pNameBuffer \
  88. : ((*pNameBuffer < L'z') \
  89. ? (*pNameBuffer - L'a' + L'A') \
  90. : RtlUpcaseUnicodeChar(*pNameBuffer)); \
  91. BucketNo *= 131; \
  92. BucketNo += *pNameBuffer; \
  93. pNameBuffer++; \
  94. } \
  95. \
  96. BucketNo = BucketNo % NO_OF_HASH_BUCKETS; \
  97. *pNameBuffer = L'\0'; \
  98. (pName)->Length = (USHORT)((CHAR *)pNameBuffer - (CHAR *)(pName)->Buffer);\
  99. \
  100. (pPath)->Length = (USHORT)((CHAR *)pPathBufferEnd - (CHAR *)pPathBuffer);\
  101. (pPath)->Buffer = pPathBuffer; \
  102. DebugTrace(0, Dbg, "SPLIT_PATH:Path (%wZ)",pPath); \
  103. DebugTrace(0, Dbg, " Name (%wZ)\n",pName); \
  104. } \
  105. //+---------------------------------------------------------------------------
  106. //
  107. // Function: SPLIT_CASE_SENSITIVE_PATH
  108. //
  109. // Synopsis: Split the patah name around deleimiters.
  110. //
  111. // Arguments: [pPath] -- path to be split(PUNICODE_STRING)
  112. //
  113. // [pName] -- the leftmost component of the path(PUNICODE_STRING)
  114. //
  115. // [BucketNo] -- Hash Bucket no. corresponding to the name(ULONG)
  116. //
  117. // SideEffects: the UNICODE_STRING pointed to by pName and BucketNo are modified.
  118. //
  119. // PreRequisite: pName be associated with a valid buffer.
  120. //
  121. // History: 04-18-94 SethuR Created
  122. //
  123. // Notes: defined as a macro for inlining
  124. //
  125. //----------------------------------------------------------------------------
  126. #define SPLIT_CASE_SENSITIVE_PATH(pPath,pName,BucketNo) \
  127. { \
  128. WCHAR *pPathBuffer = (pPath)->Buffer; \
  129. WCHAR *pNameBuffer = (pName)->Buffer; \
  130. WCHAR *pPathBufferEnd = &pPathBuffer[(pPath)->Length / sizeof(WCHAR)]; \
  131. \
  132. BucketNo = 0; \
  133. while ((pPathBufferEnd != pPathBuffer) && \
  134. ((*pNameBuffer = *pPathBuffer++) != PATH_DELIMITER)) \
  135. { \
  136. BucketNo *= 131; \
  137. BucketNo += *pNameBuffer; \
  138. pNameBuffer++; \
  139. } \
  140. \
  141. BucketNo = BucketNo % NO_OF_HASH_BUCKETS; \
  142. *pNameBuffer = L'\0'; \
  143. (pName)->Length = (USHORT)((CHAR *)pNameBuffer - (CHAR *)(pName)->Buffer);\
  144. \
  145. (pPath)->Length = (USHORT)((CHAR *)pPathBufferEnd - (CHAR *)pPathBuffer); \
  146. (pPath)->Buffer = pPathBuffer; \
  147. DebugTrace(0, Dbg, "SPLIT_PATH:Path (%wZ)",pPath); \
  148. DebugTrace(0, Dbg, " Name (%wZ)\n",pName); \
  149. } \
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Function: INITIALIZE_BUCKET
  153. //
  154. // Synopsis: Initializes a hash bucket.
  155. //
  156. // Arguments: [Bucket] -- the bucket to be initialized(DFS_PREFIX_TABLE_BUCKET)
  157. //
  158. // SideEffects: the bucket is intialized ( the collision list and count are
  159. // initialized
  160. //
  161. // History: 04-18-94 SethuR Created
  162. //
  163. // Notes: defined as a macro for inlining
  164. //
  165. //----------------------------------------------------------------------------
  166. #define INITIALIZE_BUCKET(Bucket) \
  167. { \
  168. (Bucket).SentinelEntry.pNextEntry = &(Bucket).SentinelEntry; \
  169. (Bucket).SentinelEntry.pPrevEntry = &(Bucket).SentinelEntry; \
  170. (Bucket).NoOfEntries = 0; \
  171. } \
  172. //+---------------------------------------------------------------------------
  173. //
  174. // Function: LOOKUP_BUCKET
  175. //
  176. // Synopsis: lookups the bucket for an entry.
  177. //
  178. // Arguments: [Bucket] -- the bucket to be used (DFS_PREFIX_TABLE_BUCKET)
  179. //
  180. // [Name] -- the name to be looked up (UNICODE_STRING)
  181. //
  182. // [pParentEntry] -- the parent entry of the entry we are
  183. // searching for.
  184. //
  185. // [pEntry] -- placeholder for the desired entry.
  186. //
  187. // [fNameFound] -- indicates if the name was found.
  188. //
  189. // SideEffects: Name,fNameFound and pEntry are modified
  190. //
  191. // History: 04-18-94 SethuR Created
  192. //
  193. // Notes: defined as a macro for inlining
  194. //
  195. // We only store one copy of a string irrespective of the no. of
  196. // places it appears in, e.g. foo\bar and foo1\bar will result
  197. // in only one copy of bar being stored. This implies that the
  198. // lookup routine will have to return sufficient info. to prevent
  199. // the allocation of memory space for a string. If on exit
  200. // fNameFound is set to TRUE then this indicates that a similar
  201. // string was located in the table and the Name.Buffer field is
  202. // modified to point to the first instance of the string in
  203. // the table.
  204. //
  205. //----------------------------------------------------------------------------
  206. #define LOOKUP_BUCKET(Bucket,Name,pParentEntry,pEntry,fNameFound) \
  207. { \
  208. PDFS_PREFIX_TABLE_ENTRY pCurEntry = Bucket.SentinelEntry.pNextEntry; \
  209. \
  210. DebugTrace(0, Dbg, "LOOKUP_BUCKET: Looking for (%wZ)\n", &Name); \
  211. fNameFound = FALSE; \
  212. pEntry = NULL; \
  213. \
  214. while (pCurEntry != &Bucket.SentinelEntry) \
  215. { \
  216. if (pCurEntry->PathSegment.Length == Name.Length) \
  217. { \
  218. DebugTrace(0, Dbg, "LOOKUP_BUCKET: Looking at Entry with Name (%wZ)\n",&pCurEntry->PathSegment); \
  219. if (fNameFound && \
  220. (pCurEntry->PathSegment.Buffer == Name.Buffer)) \
  221. { \
  222. if (pCurEntry->pParentEntry == pParentEntry) \
  223. { \
  224. pEntry = pCurEntry; \
  225. break; \
  226. } \
  227. } \
  228. else if (!COMPARE_MEMORY(pCurEntry->PathSegment.Buffer, \
  229. Name.Buffer, \
  230. Name.Length)) \
  231. { \
  232. fNameFound = TRUE; \
  233. Name.Buffer = pCurEntry->PathSegment.Buffer; \
  234. if (pCurEntry->pParentEntry == pParentEntry) \
  235. { \
  236. pEntry = pCurEntry; \
  237. break; \
  238. } \
  239. } \
  240. } \
  241. \
  242. pCurEntry = pCurEntry->pNextEntry; \
  243. } \
  244. } \
  245. //+---------------------------------------------------------------------------
  246. //
  247. // Function: INSERT_IN_BUCKET
  248. //
  249. // Synopsis: inserts the entry in the bucket
  250. //
  251. // Arguments: [Bucket] -- the bucket to be initialized(DFS_PREFIX_TABLE_BUCKET)
  252. //
  253. // [pEntry] -- the entry to be inserted
  254. //
  255. // SideEffects: Bucket is modified to include the entry
  256. //
  257. // History: 04-18-94 SethuR Created
  258. //
  259. // Notes: defined as a macro for inlining
  260. //
  261. //----------------------------------------------------------------------------
  262. #define INSERT_IN_BUCKET(Bucket,pEntry) \
  263. { \
  264. (Bucket).NoOfEntries++; \
  265. (pEntry)->pPrevEntry = (Bucket).SentinelEntry.pPrevEntry; \
  266. (pEntry)->pNextEntry = &((Bucket).SentinelEntry); \
  267. ((Bucket).SentinelEntry.pPrevEntry)->pNextEntry = (pEntry); \
  268. (Bucket).SentinelEntry.pPrevEntry = (pEntry); \
  269. } \
  270. //+---------------------------------------------------------------------------
  271. //
  272. // Function: REMOVE_FROM_BUCKET
  273. //
  274. // Synopsis: removes the entry from the bucket
  275. //
  276. // Arguments: [pEntry] -- the entry to be inserted
  277. //
  278. // SideEffects: Bucket is modified to exclude the entry
  279. //
  280. // History: 04-18-94 SethuR Created
  281. //
  282. // Notes: defined as a macro for inlining
  283. //
  284. //----------------------------------------------------------------------------
  285. #define REMOVE_FROM_BUCKET(pEntry) \
  286. { \
  287. PDFS_PREFIX_TABLE_ENTRY pPrevEntry = (pEntry)->pPrevEntry; \
  288. PDFS_PREFIX_TABLE_ENTRY pNextEntry = (pEntry)->pNextEntry; \
  289. \
  290. pPrevEntry->pNextEntry = pNextEntry; \
  291. pNextEntry->pPrevEntry = pPrevEntry; \
  292. } \
  293. //+---------------------------------------------------------------------------
  294. //
  295. // Function: INSERT_IN_CHILD_LIST
  296. //
  297. // Synopsis: Inserts this entry in the parent's list of children
  298. //
  299. // Arguments: [pEntry] -- the entry to be inserted
  300. //
  301. // [pParentEntry] -- the entry into whose list of children
  302. // pEntry has to be inserted.
  303. //
  304. // SideEffects: Parent's list of children is modified.
  305. //
  306. // History: 01-09-96 MilanS Created
  307. //
  308. // Notes: defined as a macro for inlining
  309. //
  310. //----------------------------------------------------------------------------
  311. #define INSERT_IN_CHILD_LIST(pEntry, pParentEntry) \
  312. { \
  313. PDFS_PREFIX_TABLE_ENTRY pLastChild; \
  314. \
  315. if (pParentEntry->pFirstChildEntry == NULL) { \
  316. pParentEntry->pFirstChildEntry = pEntry; \
  317. } else { \
  318. for (pLastChild = pParentEntry->pFirstChildEntry; \
  319. pLastChild->pSiblingEntry != NULL; \
  320. pLastChild = pLastChild->pSiblingEntry) { \
  321. NOTHING; \
  322. } \
  323. pLastChild->pSiblingEntry = pEntry; \
  324. } \
  325. }
  326. //+----------------------------------------------------------------------------
  327. //
  328. // Function: REMOVE_FROM_CHILD_LIST
  329. //
  330. // Synopsis: Removes an entry from its parent's list of children
  331. //
  332. // Arguments: [pEntry] -- the Entry to remove from children list.
  333. //
  334. // SideEffects: The children list of pParentEntry is modified.
  335. //
  336. // History: 01-09-96 MilanS Created
  337. //
  338. // Notes: Defined as a macro for inlining.
  339. //
  340. // This routine will ASSERT if pEntry is not in the parent's
  341. // list of children.
  342. //
  343. //-----------------------------------------------------------------------------
  344. #define REMOVE_FROM_CHILD_LIST(pEntry) \
  345. { \
  346. PDFS_PREFIX_TABLE_ENTRY pParentEntry = pEntry->pParentEntry; \
  347. PDFS_PREFIX_TABLE_ENTRY pPrevSibling; \
  348. \
  349. if (pParentEntry->pFirstChildEntry == pEntry) { \
  350. pParentEntry->pFirstChildEntry = pEntry->pSiblingEntry; \
  351. } else { \
  352. for (pPrevSibling = pParentEntry->pFirstChildEntry; \
  353. pPrevSibling->pSiblingEntry != pEntry; \
  354. pPrevSibling = pPrevSibling->pSiblingEntry) { \
  355. ASSERT(pPrevSibling->pSiblingEntry != NULL); \
  356. } \
  357. pPrevSibling->pSiblingEntry = pEntry->pSiblingEntry; \
  358. } \
  359. }
  360. //+---------------------------------------------------------------------------
  361. //
  362. // Function: INITIALIZE_NAME_PAGE
  363. //
  364. // Synopsis: initializes the name page
  365. //
  366. // Arguments: [pNamePage] -- the NAME_PAGE to be initialized
  367. //
  368. // SideEffects: the name page is initialized
  369. //
  370. // History: 04-18-94 SethuR Created
  371. //
  372. // Notes: defined as a macro for inlining
  373. //
  374. //----------------------------------------------------------------------------
  375. #define INITIALIZE_NAME_PAGE(pNamePage) \
  376. { \
  377. pNamePage->pNextPage = NULL; \
  378. pNamePage->cFreeSpace = FREESPACE_IN_NAME_PAGE - 1; \
  379. pNamePage->Names[FREESPACE_IN_NAME_PAGE - 1] = L'\0'; \
  380. } \
  381. //+---------------------------------------------------------------------------
  382. //
  383. // Function: INITIALIZE_PREFIX_TABLE_ENTRY
  384. //
  385. // Synopsis: initializes the prefix table entry
  386. //
  387. // Arguments: [pEntry] -- the entry to be initialized
  388. //
  389. // SideEffects: the prefix table entry is modified
  390. //
  391. // History: 04-18-94 SethuR Created
  392. //
  393. // Notes: defined as a macro for inlining
  394. //
  395. //----------------------------------------------------------------------------
  396. #define INITIALIZE_PREFIX_TABLE_ENTRY(pEntry) \
  397. { \
  398. RtlZeroMemory( pEntry, sizeof( DFS_PREFIX_TABLE_ENTRY ) ); \
  399. (pEntry)->NoOfChildren = 1; \
  400. } \
  401. //+---------------------------------------------------------------------------
  402. //
  403. // Function: private fns. extern declarations
  404. //
  405. //----------------------------------------------------------------------------
  406. extern
  407. NTSTATUS _LookupPrefixTable(PDFS_PREFIX_TABLE pTable,
  408. UNICODE_STRING *pPath,
  409. UNICODE_STRING *pSuffix,
  410. PDFS_PREFIX_TABLE_ENTRY *ppEntry);
  411. //+---------------------------------------------------------------------------
  412. //
  413. // Function: ALLOCATION ROUTINES
  414. //
  415. // Synopsis: all the allocation routines are defined to be used in the KERNEL as
  416. // well as user mode. The KERNEL mode is turned on by defining KERNEL
  417. //
  418. // History: 04-18-94 SethuR Created
  419. //
  420. // Notes: defined as a macro for inlining
  421. //
  422. //----------------------------------------------------------------------------
  423. extern
  424. NTSTATUS
  425. _InitializePrefixTableEntryAllocation(PDFS_PREFIX_TABLE pTable);
  426. extern
  427. PWSTR _AllocateNamePageEntry(PNAME_PAGE_LIST pPageList,ULONG cLength);
  428. #ifdef KERNEL_MODE
  429. #define ALLOCATE_NAME_PAGE() (PNAME_PAGE)ExAllocatePoolWithTag(PagedPool,sizeof(NAME_PAGE), ' sfD')
  430. #define FREE_NAME_PAGE(pPage) ExFreePool(pPage)
  431. #define ALLOCATE_NAME_PAGE_ENTRY(PageList,cLength) \
  432. ExAllocatePoolWithTag(PagedPool, cLength * sizeof(WCHAR), ' sfD'); \
  433. #define FREE_NAME_PAGE_ENTRY(PageList,pName)
  434. #define ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable) \
  435. (PDFS_PREFIX_TABLE_ENTRY) ExAllocatePoolWithTag(PagedPool,sizeof(DFS_PREFIX_TABLE_ENTRY), ' sfD')
  436. #define FREE_DFS_PREFIX_TABLE_ENTRY(pTable,pEntry) \
  437. if ((pEntry)->PathSegment.Buffer != NULL) { \
  438. ExFreePool((pEntry)->PathSegment.Buffer); \
  439. } \
  440. ExFreePool((pEntry));
  441. #define COMPARE_MEMORY(s,d,l) (!RtlEqualMemory(s,d,l))
  442. #else
  443. #define ALLOCATE_NAME_PAGE() (PNAME_PAGE)malloc(sizeof(NAME_PAGE))
  444. #define FREE_NAME_PAGE(pPage) free(pPage)
  445. #define ALLOCATE_NAME_PAGE_ENTRY(PageList,cLength) malloc(cLength * sizeof(WCHAR))
  446. #define FREE_NAME_PAGE_ENTRY(PageList,pName)
  447. #define ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable) \
  448. (PDFS_PREFIX_TABLE_ENTRY)malloc(sizeof(DFS_PREFIX_TABLE_ENTRY))
  449. #define FREE_DFS_PREFIX_TABLE_ENTRY(pTable,pEntry) free((pEntry))
  450. #define COMPARE_MEMORY(s,d,l) memcmp(s,d,l)
  451. #endif
  452. #endif // __PREFIXP_H__