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.

431 lines
13 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2001 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. UINT m_uiDirNameLen; // Length of string currently in buffer (does not include '\0')
  32. UINT m_uiDirNameMax; // 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. // HRESULT
  44. // HrCreateDirectoryPath(
  45. // LPWSTR pszDirectoryPathInOut
  46. // )
  47. //
  48. // Descriptions:
  49. // Creates the directory tree as required.
  50. //
  51. // Arguments:
  52. // pszDirectoryPathOut
  53. // Must be MAX_PATH big. It will contain the trace log file path to
  54. // create.
  55. //
  56. // Return Values:
  57. // S_OK - Success
  58. // other HRESULTs for failures
  59. //
  60. //--
  61. //////////////////////////////////////////////////////////////////////////////
  62. HRESULT
  63. HrCreateDirectoryPath( LPWSTR pszDirectoryPath )
  64. {
  65. LPTSTR psz;
  66. BOOL fReturn;
  67. DWORD dwAttr;
  68. HRESULT hr = S_OK;
  69. //
  70. // Find the \ that indicates the root directory. There should be at least
  71. // one \, but if there isn't, we just fall through.
  72. //
  73. // skip X:\ part
  74. psz = wcschr( pszDirectoryPath, L'\\' );
  75. Assert( psz != NULL );
  76. if ( psz != NULL )
  77. {
  78. //
  79. // Find the \ that indicates the end of the first level directory. It's
  80. // probable that there won't be another \, in which case we just fall
  81. // through to creating the entire path.
  82. //
  83. psz = wcschr( psz + 1, L'\\' );
  84. while ( psz != NULL )
  85. {
  86. // Terminate the directory path at the current level.
  87. *psz = 0;
  88. //
  89. // Create a directory at the current level.
  90. //
  91. dwAttr = GetFileAttributes( pszDirectoryPath );
  92. if ( 0xFFFFffff == dwAttr )
  93. {
  94. DebugMsg( TEXT("DEBUG: Creating %s"), pszDirectoryPath );
  95. fReturn = CreateDirectory( pszDirectoryPath, NULL );
  96. if ( ! fReturn )
  97. {
  98. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  99. goto Error;
  100. } // if: creation failed
  101. } // if: directory not found
  102. else if ( ( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
  103. {
  104. hr = THR( E_FAIL );
  105. goto Error;
  106. } // else: file found
  107. //
  108. // Restore the \ and find the next one.
  109. //
  110. *psz = L'\\';
  111. psz = wcschr( psz + 1, L'\\' );
  112. } // while: found slash
  113. } // if: found slash
  114. //
  115. // Create the target directory.
  116. //
  117. dwAttr = GetFileAttributes( pszDirectoryPath );
  118. if ( 0xFFFFffff == dwAttr )
  119. {
  120. fReturn = CreateDirectory( pszDirectoryPath, NULL );
  121. if ( ! fReturn )
  122. {
  123. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  124. } // if: creation failed
  125. } // if: path not found
  126. Error:
  127. return hr;
  128. } //*** HrCreateDirectoryPath()
  129. //////////////////////////////////////////////////////////////////////////////
  130. //++
  131. //
  132. // DWORD
  133. // DwRecursiveEmptyDirectory
  134. //
  135. // Description:
  136. // Recursively removes the target directory and everything underneath it.
  137. // This is a recursive function.
  138. //
  139. // Arguments:
  140. // pdrpParamsInOut
  141. // Pointer to the object that contains the parameters for this recursive call.
  142. //
  143. // Return Value:
  144. // ERROR_SUCCESS
  145. // The directory was deleted
  146. //
  147. // Other Win32 error codes
  148. // If something went wrong
  149. //
  150. //--
  151. //////////////////////////////////////////////////////////////////////////////
  152. DWORD
  153. DwRecursiveEmptyDirectory( SDirRemoveParams * pdrpParamsInOut )
  154. {
  155. DWORD dwError = ERROR_SUCCESS;
  156. do
  157. {
  158. typedef CSmartResource<
  159. CHandleTrait<
  160. HANDLE
  161. , BOOL
  162. , FindClose
  163. , INVALID_HANDLE_VALUE
  164. >
  165. > SmartFindFileHandle;
  166. WIN32_FIND_DATA wfdCurFile;
  167. UINT uiCurDirNameLen = pdrpParamsInOut->m_uiDirNameLen;
  168. ZeroMemory( &wfdCurFile, sizeof( wfdCurFile ) );
  169. if ( pdrpParamsInOut->m_iMaxDepth < 0 )
  170. {
  171. dwError = TW32( ERROR_DIR_NOT_EMPTY );
  172. break;
  173. } // if: the recursion is too deep.
  174. //
  175. // Check if the target directory name is too long. The two extra characters
  176. // being checked for are '\\' and '*'.
  177. //
  178. if ( uiCurDirNameLen > ( pdrpParamsInOut->m_uiDirNameMax - 2 ) )
  179. {
  180. dwError = TW32( ERROR_BUFFER_OVERFLOW );
  181. break;
  182. } // if: the target directory name is too long.
  183. // Append "\*" to the end of the directory name
  184. pdrpParamsInOut->m_pszDirName[ uiCurDirNameLen ] = '\\';
  185. pdrpParamsInOut->m_pszDirName[ uiCurDirNameLen + 1 ] = '*';
  186. pdrpParamsInOut->m_pszDirName[ uiCurDirNameLen + 2 ] = '\0';
  187. ++uiCurDirNameLen;
  188. SmartFindFileHandle sffhFindFileHandle( FindFirstFile( pdrpParamsInOut->m_pszDirName, &wfdCurFile ) );
  189. if ( sffhFindFileHandle.FIsInvalid() )
  190. {
  191. dwError = TW32( GetLastError() );
  192. break;
  193. }
  194. do
  195. {
  196. size_t stFileNameLen;
  197. // If the current file is a directory, make a recursive call to delete it.
  198. if ( ( wfdCurFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 )
  199. {
  200. if ( ( wcscmp( wfdCurFile.cFileName, L"." ) != 0 )
  201. && ( wcscmp( wfdCurFile.cFileName, L".." ) != 0 )
  202. )
  203. {
  204. stFileNameLen = wcslen( wfdCurFile.cFileName );
  205. // Append the subdirectory name past the last '\\' character.
  206. wcsncpy(
  207. pdrpParamsInOut->m_pszDirName + uiCurDirNameLen
  208. , wfdCurFile.cFileName
  209. , pdrpParamsInOut->m_uiDirNameMax - uiCurDirNameLen + 1
  210. );
  211. // Update the parameter object.
  212. --pdrpParamsInOut->m_iMaxDepth;
  213. pdrpParamsInOut->m_uiDirNameLen = uiCurDirNameLen + static_cast<UINT>( stFileNameLen );
  214. // Delete the subdirectory.
  215. dwError = TW32( DwRecursiveEmptyDirectory( pdrpParamsInOut ) );
  216. if ( dwError != ERROR_SUCCESS )
  217. {
  218. break;
  219. } // if: an error occurred trying to empty this directory.
  220. // Restore the parameter object. There is no need to restore m_uiDirNameLen
  221. // since it is never used again in the RHS in this function.
  222. ++pdrpParamsInOut->m_iMaxDepth;
  223. if ( RemoveDirectory( pdrpParamsInOut->m_pszDirName ) == FALSE )
  224. {
  225. dwError = TW32( GetLastError() );
  226. break;
  227. } // if: the current directory could not be removed.
  228. } // if: the current directory is not "." or ".."
  229. } // if: current file is a directory.
  230. else
  231. {
  232. //
  233. // This file is not a directory. Delete it.
  234. //
  235. stFileNameLen = wcslen( wfdCurFile.cFileName );
  236. if ( stFileNameLen > ( pdrpParamsInOut->m_uiDirNameMax - uiCurDirNameLen ) )
  237. {
  238. dwError = TW32( ERROR_BUFFER_OVERFLOW );
  239. break;
  240. }
  241. // Append the file name to the directory name.
  242. wcsncpy(
  243. pdrpParamsInOut->m_pszDirName + uiCurDirNameLen
  244. , wfdCurFile.cFileName
  245. , pdrpParamsInOut->m_uiDirNameMax - uiCurDirNameLen + 1
  246. );
  247. if ( DeleteFile( pdrpParamsInOut->m_pszDirName ) == FALSE )
  248. {
  249. dwError = TW32( GetLastError() );
  250. break;
  251. } // if: DeleteFile failed.
  252. } // else: current file is not a directory.
  253. if ( FindNextFile( sffhFindFileHandle.HHandle(), &wfdCurFile ) == FALSE )
  254. {
  255. dwError = GetLastError();
  256. if ( dwError == ERROR_NO_MORE_FILES )
  257. {
  258. // We have deleted all the files in this directory.
  259. dwError = ERROR_SUCCESS;
  260. }
  261. else
  262. {
  263. TW32( dwError );
  264. }
  265. // If FindNextFile has failed, we are done.
  266. break;
  267. } // if: FindNextFile fails.
  268. }
  269. while( true ); // loop infinitely.
  270. if ( dwError != ERROR_SUCCESS )
  271. {
  272. break;
  273. } // if: something went wrong.
  274. //
  275. // If we are here, then all the files in this directory have been deleted.
  276. //
  277. // Truncate the directory name at the last '\'
  278. pdrpParamsInOut->m_pszDirName[ uiCurDirNameLen - 1 ] = L'\0';
  279. }
  280. while( false ); // dummy do while loop to avoid gotos.
  281. return dwError;
  282. } //*** DwRecursiveEmptyDirectory()
  283. //////////////////////////////////////////////////////////////////////////////
  284. //++
  285. //
  286. // DWORD
  287. // DwRemoveDirectory
  288. //
  289. // Description:
  290. // Remove the target directory and everything underneath it.
  291. // Calls DwRecursiveEmptyDirectory to do the actual work.
  292. //
  293. // Arguments:
  294. // pcszTargetDirIn
  295. // The directory to be removed. Note, this name cannot have trailing
  296. // backslash '\' characters.
  297. //
  298. // iMaxDepthIn
  299. // The maximum depth of the subdirectories that will be removed.
  300. // Default value is 32. If this depth is exceeded, an exception
  301. // is thrown.
  302. //
  303. // Return Value:
  304. // ERROR_SUCCESS
  305. // The directory was deleted
  306. //
  307. // Other Win32 error codes
  308. // If something went wrong
  309. //
  310. // Remarks:
  311. // If the length of the name of any of the files under pcszTargetDirIn
  312. // exceeds MAX_PATH - 1, an error is returned.
  313. //
  314. //--
  315. //////////////////////////////////////////////////////////////////////////////
  316. DWORD
  317. DwRemoveDirectory( const WCHAR * pcszTargetDirIn, signed int iMaxDepthIn )
  318. {
  319. WCHAR szDirBuffer[ MAX_PATH ];
  320. SDirRemoveParams drpParams;
  321. DWORD dwError = ERROR_SUCCESS;
  322. WIN32_FILE_ATTRIBUTE_DATA wfadDirAttributes;
  323. if ( pcszTargetDirIn == NULL )
  324. {
  325. goto Cleanup;
  326. } // if: the directory name is NULL
  327. ZeroMemory( &wfadDirAttributes, sizeof( wfadDirAttributes ) );
  328. //
  329. // Check if the directory exists.
  330. //
  331. if ( GetFileAttributesEx( pcszTargetDirIn, GetFileExInfoStandard, &wfadDirAttributes ) == FALSE )
  332. {
  333. dwError = GetLastError();
  334. if ( dwError == ERROR_FILE_NOT_FOUND )
  335. {
  336. dwError = ERROR_SUCCESS;
  337. } // if: the directory does not exist, this is not an error
  338. else
  339. {
  340. TW32( dwError );
  341. }
  342. goto Cleanup;
  343. } // if: we could not get the file attributes
  344. if ( ( wfadDirAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
  345. {
  346. // We are not going to delete files
  347. goto Cleanup;
  348. } // if: the path does not point to a directory
  349. // Copy the input string to our buffer.
  350. wcsncpy( szDirBuffer, pcszTargetDirIn, MAX_PATH );
  351. szDirBuffer[ MAX_PATH - 1 ] = L'\0';
  352. // Initialize the object that holds the parameters for the recursive call.
  353. drpParams.m_pszDirName = szDirBuffer;
  354. drpParams.m_uiDirNameLen = static_cast< UINT >( wcslen( szDirBuffer ) );
  355. drpParams.m_uiDirNameMax = ( sizeof( szDirBuffer ) / sizeof( szDirBuffer[0] ) ) - 1;
  356. drpParams.m_iMaxDepth = iMaxDepthIn;
  357. // Call the actual recursive function to empty the directory.
  358. dwError = TW32( DwRecursiveEmptyDirectory( &drpParams ) );
  359. // If the directory was emptied, delete it.
  360. if ( ( dwError == ERROR_SUCCESS ) && ( RemoveDirectory( pcszTargetDirIn ) == FALSE ) )
  361. {
  362. dwError = TW32( GetLastError() );
  363. goto Cleanup;
  364. } // if: the current directory could not be removed.
  365. Cleanup:
  366. return dwError;
  367. } //*** DwRemoveDirectory()