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.

327 lines
11 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // DirectoryUtils.cpp
  7. //
  8. // Description:
  9. // Useful functions for manipulating directies.
  10. //
  11. // Maintained By:
  12. // Galen Barbee (GalenB) 05-DEC-2000
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "Pch.h"
  20. #include "SmartClasses.h"
  21. //////////////////////////////////////////////////////////////////////////////
  22. // Type Definitions
  23. //////////////////////////////////////////////////////////////////////////////
  24. //
  25. // Structure used to pass parameters between recursive calls to the
  26. // gs_RecursiveEmptyDirectory() function.
  27. //
  28. struct SDirRemoveParams
  29. {
  30. WCHAR * m_pszDirName; // Pointer to the directory name buffer.
  31. size_t m_cchDirNameLen; // Length of string currently in buffer (does not include '\0')
  32. size_t m_cchDirNameMax; // Max length of string in buffer (does not include '\0')
  33. signed int m_iMaxDepth; // Maximum recursion depth.
  34. };
  35. //////////////////////////////////////////////////////////////////////////////
  36. // Forward Declarations.
  37. //////////////////////////////////////////////////////////////////////////////
  38. DWORD
  39. DwRecursiveEmptyDirectory( SDirRemoveParams * pdrpParamsInOut );
  40. //////////////////////////////////////////////////////////////////////////////
  41. //++
  42. //
  43. // DWORD
  44. // DwRecursiveEmptyDirectory
  45. //
  46. // Description:
  47. // Recursively removes the target directory and everything underneath it.
  48. // This is a recursive function.
  49. //
  50. // Arguments:
  51. // pdrpParamsInout
  52. // Pointer to the object that contains the parameters for this recursive call.
  53. //
  54. // Return Value:
  55. // ERROR_SUCCESS
  56. // The directory was deleted
  57. //
  58. // Other Win32 error codes
  59. // If something went wrong
  60. //
  61. //--
  62. //////////////////////////////////////////////////////////////////////////////
  63. DWORD
  64. DwRecursiveEmptyDirectory( SDirRemoveParams * pdrpParamsInout )
  65. {
  66. DWORD dwError = ERROR_SUCCESS;
  67. do
  68. {
  69. typedef CSmartResource<
  70. CHandleTrait<
  71. HANDLE
  72. , BOOL
  73. , FindClose
  74. , INVALID_HANDLE_VALUE
  75. >
  76. > SmartFindFileHandle;
  77. WIN32_FIND_DATA wfdCurFile;
  78. size_t cchCurDirNameLen = pdrpParamsInout->m_cchDirNameLen;
  79. ZeroMemory( &wfdCurFile, sizeof( wfdCurFile ) );
  80. if ( pdrpParamsInout->m_iMaxDepth < 0 )
  81. {
  82. dwError = TW32( ERROR_DIR_NOT_EMPTY );
  83. break;
  84. } // if: the recursion is too deep.
  85. //
  86. // Check if the target directory name is too long. The two extra characters
  87. // being checked for are '\\' and '*'.
  88. //
  89. if ( cchCurDirNameLen > ( pdrpParamsInout->m_cchDirNameMax - 2 ) )
  90. {
  91. dwError = TW32( ERROR_BUFFER_OVERFLOW );
  92. break;
  93. } // if: the target directory name is too long.
  94. // Append "\*" to the end of the directory name
  95. pdrpParamsInout->m_pszDirName[ cchCurDirNameLen ] = L'\\';
  96. pdrpParamsInout->m_pszDirName[ cchCurDirNameLen + 1 ] = L'*';
  97. pdrpParamsInout->m_pszDirName[ cchCurDirNameLen + 2 ] = L'\0';
  98. ++cchCurDirNameLen;
  99. SmartFindFileHandle sffhFindFileHandle( FindFirstFile( pdrpParamsInout->m_pszDirName, &wfdCurFile ) );
  100. if ( sffhFindFileHandle.FIsInvalid() )
  101. {
  102. dwError = TW32( GetLastError() );
  103. break;
  104. }
  105. do
  106. {
  107. size_t cchFileNameLen;
  108. // If the current file is a directory, make a recursive call to delete it.
  109. if ( ( wfdCurFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 )
  110. {
  111. if ( ( wcscmp( wfdCurFile.cFileName, L"." ) != 0 )
  112. && ( wcscmp( wfdCurFile.cFileName, L".." ) != 0 )
  113. )
  114. {
  115. cchFileNameLen = wcslen( wfdCurFile.cFileName );
  116. // Append the subdirectory name past the last '\\' character.
  117. THR( StringCchCopyW(
  118. pdrpParamsInout->m_pszDirName + cchCurDirNameLen
  119. , pdrpParamsInout->m_cchDirNameMax - cchCurDirNameLen
  120. , wfdCurFile.cFileName
  121. ) );
  122. // Update the parameter object.
  123. --pdrpParamsInout->m_iMaxDepth;
  124. pdrpParamsInout->m_cchDirNameLen = cchCurDirNameLen + cchFileNameLen;
  125. // Delete the subdirectory.
  126. dwError = TW32( DwRecursiveEmptyDirectory( pdrpParamsInout ) );
  127. if ( dwError != ERROR_SUCCESS )
  128. {
  129. break;
  130. } // if: an error occurred trying to empty this directory.
  131. // Restore the parameter object. There is no need to restore m_cchDirNameLen
  132. // since it is never used again in the RHS in this function.
  133. ++pdrpParamsInout->m_iMaxDepth;
  134. if ( RemoveDirectory( pdrpParamsInout->m_pszDirName ) == FALSE )
  135. {
  136. dwError = TW32( GetLastError() );
  137. break;
  138. } // if: the current directory could not be removed.
  139. } // if: the current directory is not "." or ".."
  140. } // if: current file is a directory.
  141. else
  142. {
  143. //
  144. // This file is not a directory. Delete it.
  145. //
  146. cchFileNameLen = wcslen( wfdCurFile.cFileName );
  147. if ( cchFileNameLen > ( pdrpParamsInout->m_cchDirNameMax - cchCurDirNameLen ) )
  148. {
  149. dwError = TW32( ERROR_BUFFER_OVERFLOW );
  150. break;
  151. }
  152. // Append the file name to the directory name.
  153. THR( StringCchCopyW(
  154. pdrpParamsInout->m_pszDirName + cchCurDirNameLen
  155. , pdrpParamsInout->m_cchDirNameMax - cchCurDirNameLen
  156. , wfdCurFile.cFileName
  157. ) );
  158. if ( DeleteFile( pdrpParamsInout->m_pszDirName ) == FALSE )
  159. {
  160. dwError = TW32( GetLastError() );
  161. break;
  162. } // if: DeleteFile failed.
  163. } // else: current file is not a directory.
  164. if ( FindNextFile( sffhFindFileHandle.HHandle(), &wfdCurFile ) == FALSE )
  165. {
  166. dwError = GetLastError();
  167. if ( dwError == ERROR_NO_MORE_FILES )
  168. {
  169. // We have deleted all the files in this directory.
  170. dwError = ERROR_SUCCESS;
  171. }
  172. else
  173. {
  174. TW32( dwError );
  175. }
  176. // If FindNextFile has failed, we are done.
  177. break;
  178. } // if: FindNextFile fails.
  179. }
  180. while( true ); // loop infinitely.
  181. if ( dwError != ERROR_SUCCESS )
  182. {
  183. break;
  184. } // if: something went wrong.
  185. //
  186. // If we are here, then all the files in this directory have been deleted.
  187. //
  188. // Truncate the directory name at the last '\'
  189. pdrpParamsInout->m_pszDirName[ cchCurDirNameLen - 1 ] = L'\0';
  190. }
  191. while( false ); // dummy do while loop to avoid gotos.
  192. return dwError;
  193. } //*** DwRecursiveEmptyDirectory
  194. //////////////////////////////////////////////////////////////////////////////
  195. //++
  196. //
  197. // DWORD
  198. // DwRemoveDirectory
  199. //
  200. // Description:
  201. // Remove the target directory and everything underneath it.
  202. // Calls DwRecursiveEmptyDirectory to do the actual work.
  203. //
  204. // Arguments:
  205. // pcszTargetDirIn
  206. // The directory to be removed. Note, this name cannot have trailing
  207. // backslash '\' characters.
  208. //
  209. // iMaxDepthIn
  210. // The maximum depth of the subdirectories that will be removed.
  211. // Default value is 32. If this depth is exceeded, an exception
  212. // is thrown.
  213. //
  214. // Return Value:
  215. // ERROR_SUCCESS
  216. // The directory was deleted
  217. //
  218. // Other Win32 error codes
  219. // If something went wrong
  220. //
  221. // Remarks:
  222. // If the length of the name of any of the files under pcszTargetDirIn
  223. // exceeds MAX_PATH - 1, an error is returned.
  224. //
  225. //--
  226. //////////////////////////////////////////////////////////////////////////////
  227. DWORD
  228. DwRemoveDirectory( const WCHAR * pcszTargetDirIn, signed int iMaxDepthIn )
  229. {
  230. WCHAR szDirBuffer[ MAX_PATH ];
  231. SDirRemoveParams drpParams;
  232. DWORD dwError = ERROR_SUCCESS;
  233. WIN32_FILE_ATTRIBUTE_DATA wfadDirAttributes;
  234. if ( pcszTargetDirIn == NULL )
  235. {
  236. goto Cleanup;
  237. } // if: the directory name is NULL
  238. ZeroMemory( &wfadDirAttributes, sizeof( wfadDirAttributes ) );
  239. //
  240. // Check if the directory exists.
  241. //
  242. if ( GetFileAttributesEx( pcszTargetDirIn, GetFileExInfoStandard, &wfadDirAttributes ) == FALSE )
  243. {
  244. dwError = GetLastError();
  245. if ( dwError == ERROR_FILE_NOT_FOUND )
  246. {
  247. dwError = ERROR_SUCCESS;
  248. } // if: the directory does not exist, this is not an error
  249. else
  250. {
  251. TW32( dwError );
  252. }
  253. goto Cleanup;
  254. } // if: we could not get the file attributes
  255. if ( ( wfadDirAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
  256. {
  257. // We are not going to delete files
  258. goto Cleanup;
  259. } // if: the path does not point to a directory
  260. // Copy the input string to our buffer.
  261. THR( StringCchCopyW( szDirBuffer, RTL_NUMBER_OF( szDirBuffer ), pcszTargetDirIn ) );
  262. // Initialize the object that holds the parameters for the recursive call.
  263. drpParams.m_pszDirName = szDirBuffer;
  264. drpParams.m_cchDirNameLen = static_cast< UINT >( wcslen( szDirBuffer ) );
  265. drpParams.m_cchDirNameMax = RTL_NUMBER_OF( szDirBuffer ) - 1;
  266. drpParams.m_iMaxDepth = iMaxDepthIn;
  267. // Call the actual recursive function to empty the directory.
  268. dwError = TW32( DwRecursiveEmptyDirectory( &drpParams ) );
  269. // If the directory was emptied, delete it.
  270. if ( ( dwError == ERROR_SUCCESS ) && ( RemoveDirectory( pcszTargetDirIn ) == FALSE ) )
  271. {
  272. dwError = TW32( GetLastError() );
  273. goto Cleanup;
  274. } // if: the current directory could not be removed.
  275. Cleanup:
  276. return dwError;
  277. } //*** DwRemoveDirectory