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.

348 lines
10 KiB

  1. /*
  2. * subcycle.c - Subtree cycle detection routines module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "stub.h"
  9. #include "subcycle.h"
  10. /* Constants
  11. ************/
  12. /* pointer array allocation constants */
  13. #define NUM_CYCLE_PTRS_TO_ADD (16)
  14. /***************************** Private Functions *****************************/
  15. /* Module Prototypes
  16. ********************/
  17. PRIVATE_CODE TWINRESULT CheckHalfForSubtreeCycle(HPTRARRAY, HPATH, HPATH, LPCTSTR);
  18. /*
  19. ** CheckHalfForSubtreeCycle()
  20. **
  21. ** Checks to see if half of a proposed new folder subtree twin would create one
  22. ** or more cycles of folder subtree twins.
  23. **
  24. ** Arguments: hpaFolderPairs - handle to PTRARRAY containing pointers to
  25. ** folder pairs
  26. ** hpathStartFolder - root folder of initial half of proposed
  27. ** new folder pair
  28. ** hpathEndFolder - root folder of other half of proposed new
  29. ** folder pair
  30. ** pcszName - name specification of matching objects to be
  31. ** included in proposed new folder subtree pair
  32. **
  33. ** Returns: TWINRESULT
  34. **
  35. ** Side Effects: none
  36. **
  37. ** N.b., this function should be called twice for each proposed new folder
  38. ** subtree pair.
  39. */
  40. PRIVATE_CODE TWINRESULT CheckHalfForSubtreeCycle(HPTRARRAY hpaFolderPairs,
  41. HPATH hpathStartFolder,
  42. HPATH hpathEndFolder,
  43. LPCTSTR pcszName)
  44. {
  45. TWINRESULT tr;
  46. ARRAYINDEX aicFolderPairs;
  47. NEWPTRARRAY npa;
  48. HPTRARRAY hpaFolders;
  49. ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY));
  50. ASSERT(IS_VALID_HANDLE(hpathStartFolder, PATH));
  51. ASSERT(IS_VALID_HANDLE(hpathEndFolder, PATH));
  52. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  53. aicFolderPairs = GetPtrCount(hpaFolderPairs);
  54. /*
  55. * Try to create an unsorted pointer array to be used in checking for
  56. * cycles.
  57. */
  58. npa.aicInitialPtrs = aicFolderPairs;
  59. npa.aicAllocGranularity = NUM_CYCLE_PTRS_TO_ADD;
  60. npa.dwFlags = 0;
  61. if (CreatePtrArray(&npa, &hpaFolders))
  62. {
  63. ARRAYINDEX aicFolders;
  64. ARRAYINDEX aiCurFolder;
  65. HPATH hpathCurFolderRoot;
  66. /* Search all folder pairs connected to the first new folder twin. */
  67. /*
  68. * Mark all folder twins unused. A "used" folder twin is one that has
  69. * already been visited while searching for subtree cycles. I.e., a
  70. * used folder subtree pair half intersected the first folder of the
  71. * proposed new folder twin, and its other half was added to the list for
  72. * later comparison.
  73. */
  74. ClearFlagInArrayOfStubs(hpaFolderPairs, STUB_FL_USED);
  75. /*
  76. * Loop to process entire graph of folder subtree twins connected to the
  77. * first new folder twin. Folder twins are only added to the hpaFolders
  78. * array if they don't already intersect the second of the two proposed
  79. * new folder subtree twins.
  80. */
  81. tr = TR_SUCCESS;
  82. aicFolders = 0;
  83. aiCurFolder = 0;
  84. /* Begin with start folder. */
  85. hpathCurFolderRoot = hpathStartFolder;
  86. FOREVER
  87. {
  88. ARRAYINDEX aiCheckFolderRoot;
  89. /*
  90. * Loop to find all subtree folder pairs that intersect
  91. * hpaFolders[aiCurFolder]'s subtree.
  92. */
  93. for (aiCheckFolderRoot = 0;
  94. aiCheckFolderRoot < aicFolderPairs;
  95. aiCheckFolderRoot++)
  96. {
  97. PFOLDERPAIR pfpCheck;
  98. /* Get this subtree folder pair's root folder. */
  99. pfpCheck = GetPtr(hpaFolderPairs, aiCheckFolderRoot);
  100. ASSERT(IS_VALID_STRUCT_PTR(pfpCheck, CFOLDERPAIR));
  101. /* Have we already visited this folder pair? */
  102. if (IsStubFlagSet(&(pfpCheck->stub), STUB_FL_SUBTREE) &&
  103. IsStubFlagClear(&(pfpCheck->stub), STUB_FL_BEING_TRANSLATED) &&
  104. IsStubFlagClear(&(pfpCheck->stub), STUB_FL_USED) &&
  105. IsStubFlagClear(&(pfpCheck->pfpOther->stub), STUB_FL_USED))
  106. {
  107. /*
  108. * No. Does this subtree folder pair intersect the current
  109. * folder pair node's subtree, and the objects named in the
  110. * proposed new folder subtree twin?
  111. */
  112. ASSERT(IsStubFlagSet(&(pfpCheck->pfpOther->stub), STUB_FL_SUBTREE));
  113. ASSERT(IsStubFlagClear(&(pfpCheck->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
  114. if (SubtreesIntersect(hpathCurFolderRoot, pfpCheck->hpath) &&
  115. NamesIntersect(GetString(pfpCheck->pfpd->hsName), pcszName))
  116. {
  117. HPATH hpathOtherCheckFolderRoot;
  118. /* Yes. Get the other side of the folder subtree pair. */
  119. hpathOtherCheckFolderRoot = pfpCheck->pfpOther->hpath;
  120. /*
  121. * Does this pair connect back to the other side of the
  122. * proposed new folder pair?
  123. */
  124. if (SubtreesIntersect(hpathOtherCheckFolderRoot,
  125. hpathEndFolder))
  126. {
  127. /*
  128. * Yes. Are the roots different parts of the common
  129. * subtree?
  130. */
  131. if (ComparePaths(hpathEndFolder,
  132. hpathOtherCheckFolderRoot)
  133. != CR_EQUAL)
  134. {
  135. /* Yes. Found a cycle. Bail out. */
  136. WARNING_OUT((TEXT("CheckHalfForSubtreeCycle(): Subtree cycle found connecting folders %s and %s."),
  137. DebugGetPathString(hpathStartFolder),
  138. DebugGetPathString(hpathEndFolder)));
  139. tr = TR_SUBTREE_CYCLE_FOUND;
  140. break;
  141. }
  142. /*
  143. * We don't need to include this root in the search if it
  144. * is the same as the other side of the proposed new
  145. * folder pair since it will be covered during the other
  146. * call to CheckHalfForSubtreeCycle().
  147. */
  148. }
  149. else
  150. {
  151. /* Add this subtree as another node to be examined. */
  152. if (! InsertPtr(hpaFolders, NULL, aicFolders++,
  153. (PCVOID)(pfpCheck->pfpOther)))
  154. tr = TR_OUT_OF_MEMORY;
  155. }
  156. /* Mark this folder twin as already visited. */
  157. if (tr == TR_SUCCESS)
  158. SetStubFlag(&(pfpCheck->stub), STUB_FL_USED);
  159. else
  160. break;
  161. }
  162. }
  163. }
  164. /* Any folder subtree twins left to investigate? */
  165. if (aiCurFolder < aicFolders)
  166. {
  167. PFOLDERPAIR pfpCur;
  168. /* Yes. */
  169. pfpCur = GetPtr(hpaFolders, aiCurFolder++);
  170. hpathCurFolderRoot = pfpCur->hpath;
  171. }
  172. else
  173. /* No. */
  174. break;
  175. }
  176. DestroyPtrArray(hpaFolders);
  177. }
  178. else
  179. tr = TR_OUT_OF_MEMORY;
  180. return(tr);
  181. }
  182. /****************************** Public Functions *****************************/
  183. /*
  184. ** BeginTranslateFolder()
  185. **
  186. **
  187. **
  188. ** Arguments:
  189. **
  190. ** Returns:
  191. **
  192. ** Side Effects: none
  193. */
  194. PUBLIC_CODE void BeginTranslateFolder(PFOLDERPAIR pfp)
  195. {
  196. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  197. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_BEING_TRANSLATED));
  198. ASSERT(IsStubFlagClear(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
  199. SetStubFlag(&(pfp->stub), STUB_FL_BEING_TRANSLATED);
  200. SetStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED);
  201. return;
  202. }
  203. /*
  204. ** EndTranslateFolder()
  205. **
  206. **
  207. **
  208. ** Arguments:
  209. **
  210. ** Returns:
  211. **
  212. ** Side Effects: none
  213. */
  214. PUBLIC_CODE void EndTranslateFolder(PFOLDERPAIR pfp)
  215. {
  216. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  217. ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_BEING_TRANSLATED));
  218. ASSERT(IsStubFlagSet(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
  219. ClearStubFlag(&(pfp->stub), STUB_FL_BEING_TRANSLATED);
  220. ClearStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED);
  221. return;
  222. }
  223. /*
  224. ** CheckForSubtreeCycles()
  225. **
  226. ** Checks to see if a proposed new folder subtree twin would create one or more
  227. ** cycles of folder subtree twins.
  228. **
  229. ** Arguments:
  230. **
  231. ** Returns: TWINRESULT
  232. **
  233. ** Side Effects: none
  234. **
  235. ** N.b., TR_SUBTREE_CYCLE_FOUND is returned if the folder subtree roots of the
  236. ** proposed new folder subtree twin are the same.
  237. */
  238. PUBLIC_CODE TWINRESULT CheckForSubtreeCycles(HPTRARRAY hpaFolderPairs,
  239. HPATH hpathFirstFolder,
  240. HPATH hpathSecondFolder,
  241. HSTRING hsName)
  242. {
  243. TWINRESULT tr;
  244. ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY));
  245. ASSERT(IS_VALID_HANDLE(hpathFirstFolder, PATH));
  246. ASSERT(IS_VALID_HANDLE(hpathSecondFolder, PATH));
  247. ASSERT(IS_VALID_HANDLE(hsName, STRING));
  248. /* Are the folder twins cyclical on their own? */
  249. if (SubtreesIntersect(hpathFirstFolder, hpathSecondFolder))
  250. {
  251. /* Yes. */
  252. tr = TR_SUBTREE_CYCLE_FOUND;
  253. WARNING_OUT((TEXT("CheckForSubtreeCycles(): Subtree cycle found connecting folders %s and %s."),
  254. DebugGetPathString(hpathFirstFolder),
  255. DebugGetPathString(hpathSecondFolder)));
  256. }
  257. else
  258. {
  259. LPCTSTR pcszName;
  260. /* No. Check for any indirect subtree cycle. */
  261. pcszName = GetString(hsName);
  262. tr = CheckHalfForSubtreeCycle(hpaFolderPairs, hpathFirstFolder,
  263. hpathSecondFolder, pcszName);
  264. if (tr == TR_SUCCESS)
  265. tr = CheckHalfForSubtreeCycle(hpaFolderPairs, hpathSecondFolder,
  266. hpathFirstFolder, pcszName);
  267. }
  268. return(tr);
  269. }