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.

512 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. PrefxSup.c
  5. Abstract:
  6. This module implements the Fat Name lookup Suport routines
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. David Goebel [DavidGoe] 31-Jan-1994
  10. Revision History:
  11. // @@END_DDKSPLIT
  12. --*/
  13. #include "FatProcs.h"
  14. //
  15. // The Bug check file id for this module
  16. //
  17. #define BugCheckFileId (FAT_BUG_CHECK_SPLAYSUP)
  18. //
  19. // The debug trace level for this module
  20. //
  21. #define Dbg (DEBUG_TRACE_SPLAYSUP)
  22. //
  23. // Local procedures and types used only in this package
  24. //
  25. typedef enum _COMPARISON {
  26. IsLessThan,
  27. IsGreaterThan,
  28. IsEqual
  29. } COMPARISON;
  30. COMPARISON
  31. FatCompareNames (
  32. IN PSTRING NameA,
  33. IN PSTRING NameB
  34. );
  35. //
  36. // Do a macro here to check for a common case.
  37. //
  38. #define CompareNames(NAMEA,NAMEB) ( \
  39. *(PUCHAR)(NAMEA)->Buffer != *(PUCHAR)(NAMEB)->Buffer ? \
  40. *(PUCHAR)(NAMEA)->Buffer < *(PUCHAR)(NAMEB)->Buffer ? \
  41. IsLessThan : IsGreaterThan : \
  42. FatCompareNames((PSTRING)(NAMEA), (PSTRING)(NAMEB)) \
  43. )
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(PAGE, FatInsertName)
  46. #pragma alloc_text(PAGE, FatRemoveNames)
  47. #pragma alloc_text(PAGE, FatFindFcb)
  48. #pragma alloc_text(PAGE, FatCompareNames)
  49. #endif
  50. VOID
  51. FatInsertName (
  52. IN PIRP_CONTEXT IrpContext,
  53. IN PRTL_SPLAY_LINKS *RootNode,
  54. IN PFILE_NAME_NODE Name
  55. )
  56. /*++
  57. Routine Description:
  58. This routine will insert a name in the splay tree pointed to
  59. by RootNode.
  60. The name must not already exist in the splay tree.
  61. Arguments:
  62. RootNode - Supplies a pointer to the table.
  63. Name - Contains the New name to enter.
  64. Return Value:
  65. None.
  66. --*/
  67. {
  68. COMPARISON Comparison;
  69. PFILE_NAME_NODE Node;
  70. RtlInitializeSplayLinks(&Name->Links);
  71. //
  72. // If we are the first entry in the tree, just become the root.
  73. //
  74. if (*RootNode == NULL) {
  75. *RootNode = &Name->Links;
  76. return;
  77. }
  78. Restart:
  79. Node = CONTAINING_RECORD( *RootNode, FILE_NAME_NODE, Links );
  80. while (TRUE) {
  81. //
  82. // Compare the prefix in the tree with the prefix we want
  83. // to insert. Note that Oem here doesn't mean anything.
  84. //
  85. Comparison = CompareNames(&Node->Name.Oem, &Name->Name.Oem);
  86. //
  87. // We should never find the name in the table already.
  88. //
  89. if (Comparison == IsEqual) {
  90. //
  91. // Almost. If the removable media was taken to another machine and
  92. // back, and we have something like:
  93. //
  94. // Old: foobar~1 / foobarbaz
  95. // New: foobar~1 / foobarbazbaz
  96. //
  97. // but a handle was kept open to foobarbaz so we couldn't purge
  98. // away the Fcb in the verify path ... opening foobarbazbaz will
  99. // try to insert a duplicate shortname. Bang!
  100. //
  101. // Invalidate it and the horse it came in on. This new one wins.
  102. // The old one is gone. Only if the old one is in normal state
  103. // do we really have a problem.
  104. //
  105. if (Node->Fcb->FcbState == FcbGood) {
  106. FatBugCheck( (ULONG_PTR)*RootNode, (ULONG_PTR)Name, (ULONG_PTR)Node );
  107. }
  108. //
  109. // Note, once we zap the prefix links we need to restart our walk
  110. // of the tree.
  111. //
  112. FatMarkFcbCondition( IrpContext, Node->Fcb, FcbBad, TRUE );
  113. FatRemoveNames( IrpContext, Node->Fcb );
  114. goto Restart;
  115. }
  116. //
  117. // If the tree prefix is greater than the new prefix then
  118. // we go down the left subtree
  119. //
  120. if (Comparison == IsGreaterThan) {
  121. //
  122. // We want to go down the left subtree, first check to see
  123. // if we have a left subtree
  124. //
  125. if (RtlLeftChild(&Node->Links) == NULL) {
  126. //
  127. // there isn't a left child so we insert ourselves as the
  128. // new left child
  129. //
  130. RtlInsertAsLeftChild(&Node->Links, &Name->Links);
  131. //
  132. // and exit the while loop
  133. //
  134. break;
  135. } else {
  136. //
  137. // there is a left child so simply go down that path, and
  138. // go back to the top of the loop
  139. //
  140. Node = CONTAINING_RECORD( RtlLeftChild(&Node->Links),
  141. FILE_NAME_NODE,
  142. Links );
  143. }
  144. } else {
  145. //
  146. // The tree prefix is either less than or a proper prefix
  147. // of the new string. We treat both cases a less than when
  148. // we do insert. So we want to go down the right subtree,
  149. // first check to see if we have a right subtree
  150. //
  151. if (RtlRightChild(&Node->Links) == NULL) {
  152. //
  153. // These isn't a right child so we insert ourselves as the
  154. // new right child
  155. //
  156. RtlInsertAsRightChild(&Node->Links, &Name->Links);
  157. //
  158. // and exit the while loop
  159. //
  160. break;
  161. } else {
  162. //
  163. // there is a right child so simply go down that path, and
  164. // go back to the top of the loop
  165. //
  166. Node = CONTAINING_RECORD( RtlRightChild(&Node->Links),
  167. FILE_NAME_NODE,
  168. Links );
  169. }
  170. }
  171. }
  172. return;
  173. }
  174. VOID
  175. FatRemoveNames (
  176. IN PIRP_CONTEXT IrpContext,
  177. IN PFCB Fcb
  178. )
  179. /*++
  180. Routine Description:
  181. This routine will remove the short name and any long names associated
  182. with the files from their repsective splay tree.
  183. Arguments:
  184. Name - Supplies the Fcb to process.
  185. Return Value:
  186. None.
  187. --*/
  188. {
  189. PDCB Parent;
  190. PRTL_SPLAY_LINKS NewRoot;
  191. Parent = Fcb->ParentDcb;
  192. //
  193. // We used to assert this condition, but it really isn't good. If
  194. // someone rapidly renames a directory multiple times and we can't
  195. // flush the lower fcbs fast enough (that didn't go away synch.)
  196. // well, well hit some of them again.
  197. //
  198. // ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE ));
  199. //
  200. if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) {
  201. //
  202. // Delete the node short name.
  203. //
  204. NewRoot = RtlDelete(&Fcb->ShortName.Links);
  205. Parent->Specific.Dcb.RootOemNode = NewRoot;
  206. //
  207. // Now check for the presence of long name and delete it.
  208. //
  209. if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME )) {
  210. NewRoot = RtlDelete(&Fcb->LongName.Oem.Links);
  211. Parent->Specific.Dcb.RootOemNode = NewRoot;
  212. RtlFreeOemString( &Fcb->LongName.Oem.Name.Oem );
  213. ClearFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
  214. }
  215. if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME )) {
  216. NewRoot = RtlDelete(&Fcb->LongName.Unicode.Links);
  217. Parent->Specific.Dcb.RootUnicodeNode = NewRoot;
  218. RtlFreeUnicodeString( &Fcb->LongName.Unicode.Name.Unicode );
  219. ClearFlag( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME );
  220. }
  221. ClearFlag( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE );
  222. }
  223. return;
  224. }
  225. PFCB
  226. FatFindFcb (
  227. IN PIRP_CONTEXT IrpContext,
  228. IN OUT PRTL_SPLAY_LINKS *RootNode,
  229. IN PSTRING Name,
  230. OUT PBOOLEAN FileNameDos OPTIONAL
  231. )
  232. /*++
  233. Routine Description:
  234. This routine searches either the Oem or Unicode splay tree looking
  235. for an Fcb with the specified name. In the case the Fcb is found,
  236. rebalance the tree.
  237. Arguments:
  238. RootNode - Supplies the parent to search.
  239. Name - If present, search the Oem tree.
  240. UnicodeName - If present, search the Unicode tree.
  241. Return Value:
  242. PFCB - The Fcb, or NULL if none was found.
  243. --*/
  244. {
  245. COMPARISON Comparison;
  246. PFILE_NAME_NODE Node;
  247. PRTL_SPLAY_LINKS Links;
  248. Links = *RootNode;
  249. while (Links != NULL) {
  250. Node = CONTAINING_RECORD(Links, FILE_NAME_NODE, Links);
  251. //
  252. // Compare the prefix in the tree with the full name
  253. //
  254. Comparison = CompareNames(&Node->Name.Oem, Name);
  255. //
  256. // See if they don't match
  257. //
  258. if (Comparison == IsGreaterThan) {
  259. //
  260. // The prefix is greater than the full name
  261. // so we go down the left child
  262. //
  263. Links = RtlLeftChild(Links);
  264. //
  265. // And continue searching down this tree
  266. //
  267. } else if (Comparison == IsLessThan) {
  268. //
  269. // The prefix is less than the full name
  270. // so we go down the right child
  271. //
  272. Links = RtlRightChild(Links);
  273. //
  274. // And continue searching down this tree
  275. //
  276. } else {
  277. //
  278. // We found it.
  279. //
  280. // Splay the tree and save the new root.
  281. //
  282. *RootNode = RtlSplay(Links);
  283. //
  284. // Tell the caller what kind of name we hit
  285. //
  286. if (FileNameDos) {
  287. *FileNameDos = Node->FileNameDos;
  288. }
  289. return Node->Fcb;
  290. }
  291. }
  292. //
  293. // We didn't find the Fcb.
  294. //
  295. return NULL;
  296. }
  297. //
  298. // Local support routine
  299. //
  300. COMPARISON
  301. FatCompareNames (
  302. IN PSTRING NameA,
  303. IN PSTRING NameB
  304. )
  305. /*++
  306. Routine Description:
  307. This function compares two names as fast as possible. Note that since
  308. this comparison is case sensitive, I neither know nor case if the names
  309. are UNICODE or OEM. All that is important is that the result is
  310. deterministic.
  311. Arguments:
  312. NameA & NameB - The names to compare.
  313. Return Value:
  314. COMPARISON - returns
  315. IsLessThan if NameA < NameB lexicalgraphically,
  316. IsGreaterThan if NameA > NameB lexicalgraphically,
  317. IsEqual if NameA is equal to NameB
  318. --*/
  319. {
  320. ULONG i;
  321. ULONG MinLength;
  322. PAGED_CODE();
  323. //
  324. // Figure out the minimum of the two lengths
  325. //
  326. MinLength = NameA->Length < NameB->Length ? NameA->Length :
  327. NameB->Length;
  328. //
  329. // Loop through looking at all of the characters in both strings
  330. // testing for equalilty, less than, and greater than
  331. //
  332. i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinLength );
  333. if (i < MinLength) {
  334. return NameA->Buffer[i] < NameB->Buffer[i] ? IsLessThan :
  335. IsGreaterThan;
  336. }
  337. if (NameA->Length < NameB->Length) {
  338. return IsLessThan;
  339. }
  340. if (NameA->Length > NameB->Length) {
  341. return IsGreaterThan;
  342. }
  343. return IsEqual;
  344. }