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.

260 lines
8.1 KiB

  1. //
  2. // copied from fusion\util\io.cpp with minor changes
  3. //
  4. // xiaoyuw@ 09/05/2001
  5. //
  6. #include "stdinc.h"
  7. #include "macros.h"
  8. #include "fusionbuffer.h"
  9. #include "fusionhandle.h"
  10. #include "fuseio.h"
  11. static BOOL
  12. FusionpIsDotOrDotDot(
  13. PCWSTR str
  14. )
  15. {
  16. return ((str[0] == L'.') && ((str[1] == L'\0') || ((str[1] == L'.') && (str[2] == L'\0'))));
  17. }
  18. static BOOL
  19. IsStarOrStarDotStar(
  20. PCWSTR str
  21. )
  22. {
  23. return (str[0] == '*'
  24. && (str[1] == 0 || (str[1] == '.' && str[2] == '*' && str[3] == 0)));
  25. }
  26. CDirWalk::ECallbackResult
  27. CDirWalk::WalkHelper(
  28. )
  29. {
  30. const PCWSTR* fileFilter = NULL;
  31. BOOL fGotAll = FALSE;
  32. BOOL fThisIsAll = FALSE;
  33. CFindFile hFind;
  34. SIZE_T directoryLength = m_strParent.Cch();
  35. ECallbackResult result = eKeepWalking;
  36. ::ZeroMemory(&m_fileData, sizeof(m_fileData));
  37. result |= m_callback(eBeginDirectory, this);
  38. if (result & (eError | eSuccess))
  39. {
  40. goto Exit;
  41. }
  42. if ((result & eStopWalkingFiles) == 0)
  43. {
  44. for (fileFilter = m_fileFiltersBegin ; fileFilter != m_fileFiltersEnd ; ++fileFilter)
  45. {
  46. //
  47. // FindFirstFile equates *.* with *, so we do too.
  48. //
  49. fThisIsAll = ::IsStarOrStarDotStar(*fileFilter);
  50. fGotAll = fGotAll || fThisIsAll;
  51. if (!m_strParent.Win32EnsureTrailingPathSeparator())
  52. goto Error;
  53. if (!m_strParent.Win32Append(*fileFilter, (*fileFilter != NULL) ? ::wcslen(*fileFilter) : 0))
  54. goto Error;
  55. hFind = ::FindFirstFileW(m_strParent, &m_fileData);
  56. m_strParent.Left(directoryLength);
  57. if (hFind != INVALID_HANDLE_VALUE)
  58. {
  59. do
  60. {
  61. if (::FusionpIsDotOrDotDot(m_fileData.cFileName))
  62. continue;
  63. if (!m_strLastObjectFound.Win32Assign(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  64. {
  65. goto Error;
  66. }
  67. //
  68. // we recurse on directories only if we are getting all of them
  69. // otherwise we do them afterward
  70. //
  71. // the order directories are visited is therefore inconsistent, but
  72. // most applications should be happy enough with the eEndDirectory
  73. // notification (to implement rd /q/s)
  74. //
  75. if (m_fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  76. {
  77. if (fThisIsAll && (result & eStopWalkingDirectories) == 0)
  78. {
  79. if (!m_strParent.Win32Append("\\", 1))
  80. {
  81. goto Error;
  82. }
  83. if (!m_strParent.Win32Append(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  84. {
  85. goto Error;
  86. }
  87. result |= WalkHelper();
  88. }
  89. }
  90. else
  91. {
  92. if ((result & eStopWalkingFiles) == 0)
  93. {
  94. result |= m_callback(eFile, this);
  95. }
  96. }
  97. m_strParent.Left(directoryLength);
  98. if (result & (eError | eSuccess))
  99. {
  100. goto Exit;
  101. }
  102. if (fThisIsAll)
  103. {
  104. if ((result & eStopWalkingDirectories) &&
  105. (result & eStopWalkingFiles))
  106. {
  107. if (!hFind.Win32Close())
  108. {
  109. goto Error;
  110. }
  111. goto StopWalking;
  112. }
  113. }
  114. else
  115. {
  116. if (result & eStopWalkingFiles)
  117. {
  118. if (!hFind.Win32Close())
  119. {
  120. goto Error;
  121. }
  122. goto StopWalking;
  123. }
  124. }
  125. } while(::FindNextFileW(hFind, &m_fileData));
  126. if (::GetLastError() != ERROR_NO_MORE_FILES)
  127. {
  128. goto Error;
  129. }
  130. if (!hFind.Win32Close())
  131. {
  132. goto Error;
  133. }
  134. }
  135. }
  136. }
  137. StopWalking:;
  138. //
  139. // make another pass with * to get all directories, if we haven't already
  140. //
  141. if (!fGotAll && (result & eStopWalkingDirectories) == 0)
  142. {
  143. if (!m_strParent.Win32Append("\\*", 2))
  144. {
  145. goto Error;
  146. }
  147. hFind = ::FindFirstFileW(m_strParent, &m_fileData);
  148. m_strParent.Left(directoryLength);
  149. if (hFind != INVALID_HANDLE_VALUE)
  150. {
  151. do
  152. {
  153. if (::FusionpIsDotOrDotDot(m_fileData.cFileName))
  154. continue;
  155. if ((m_fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  156. {
  157. continue;
  158. }
  159. if (!m_strLastObjectFound.Win32Assign(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  160. {
  161. goto Error;
  162. }
  163. if (!m_strParent.Win32Append("\\", 1))
  164. {
  165. goto Error;
  166. }
  167. if (!m_strParent.Win32Append(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  168. {
  169. goto Error;
  170. }
  171. result |= WalkHelper();
  172. m_strParent.Left(directoryLength);
  173. if (result & (eError | eSuccess))
  174. {
  175. goto Exit;
  176. }
  177. if (result & eStopWalkingDirectories)
  178. {
  179. goto StopWalkingDirs;
  180. }
  181. } while(::FindNextFileW(hFind, &m_fileData));
  182. if (::GetLastError() != ERROR_NO_MORE_FILES)
  183. {
  184. goto Error;
  185. }
  186. StopWalkingDirs:
  187. if (!hFind.Win32Close())
  188. {
  189. goto Error;
  190. }
  191. }
  192. }
  193. ::ZeroMemory(&m_fileData, sizeof(m_fileData));
  194. result |= m_callback(eEndDirectory, this);
  195. if (result & (eError | eSuccess))
  196. {
  197. goto Exit;
  198. }
  199. result = eKeepWalking;
  200. Exit:
  201. if ((result & eStopWalkingDeep) == 0)
  202. {
  203. result &= ~(eStopWalkingFiles | eStopWalkingDirectories);
  204. }
  205. if (result & eError)
  206. {
  207. result |= (eStopWalkingFiles | eStopWalkingDirectories | eStopWalkingDeep);
  208. }
  209. return result;
  210. Error:
  211. result |= eError;
  212. goto Exit;
  213. }
  214. CDirWalk::CDirWalk()
  215. {
  216. const static PCWSTR defaultFileFilter[] = { L"*" };
  217. m_fileFiltersBegin = defaultFileFilter;
  218. m_fileFiltersEnd = defaultFileFilter + NUMBER_OF(defaultFileFilter);
  219. }
  220. BOOL
  221. CDirWalk::Walk()
  222. {
  223. BOOL fSuccess = FALSE;
  224. //
  225. // Save off the original path length before we go twiddling m_strParent
  226. //
  227. m_cchOriginalPath = m_strParent.Cch();
  228. ECallbackResult result = WalkHelper();
  229. if (result & eError)
  230. {
  231. if (::GetLastError() == ERROR_SUCCESS) // forget to set lasterror ?
  232. ::SetLastError(ERROR_INSTALL_FAILURE);
  233. goto Exit;
  234. }
  235. fSuccess = TRUE;
  236. Exit:
  237. return fSuccess;
  238. }