///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2002 Microsoft Corporation // // Module Name: // DirectoryUtils.cpp // // Description: // Useful functions for manipulating directies. // // Maintained By: // Galen Barbee (GalenB) 05-DEC-2000 // // Revision History: // // Notes: // ///////////////////////////////////////////////////////////////////////////// #include "Pch.h" #include "SmartClasses.h" ////////////////////////////////////////////////////////////////////////////// // Type Definitions ////////////////////////////////////////////////////////////////////////////// // // Structure used to pass parameters between recursive calls to the // gs_RecursiveEmptyDirectory() function. // struct SDirRemoveParams { WCHAR * m_pszDirName; // Pointer to the directory name buffer. size_t m_cchDirNameLen; // Length of string currently in buffer (does not include '\0') size_t m_cchDirNameMax; // Max length of string in buffer (does not include '\0') signed int m_iMaxDepth; // Maximum recursion depth. }; ////////////////////////////////////////////////////////////////////////////// // Forward Declarations. ////////////////////////////////////////////////////////////////////////////// DWORD DwRecursiveEmptyDirectory( SDirRemoveParams * pdrpParamsInOut ); ////////////////////////////////////////////////////////////////////////////// //++ // // DWORD // DwRecursiveEmptyDirectory // // Description: // Recursively removes the target directory and everything underneath it. // This is a recursive function. // // Arguments: // pdrpParamsInout // Pointer to the object that contains the parameters for this recursive call. // // Return Value: // ERROR_SUCCESS // The directory was deleted // // Other Win32 error codes // If something went wrong // //-- ////////////////////////////////////////////////////////////////////////////// DWORD DwRecursiveEmptyDirectory( SDirRemoveParams * pdrpParamsInout ) { DWORD dwError = ERROR_SUCCESS; do { typedef CSmartResource< CHandleTrait< HANDLE , BOOL , FindClose , INVALID_HANDLE_VALUE > > SmartFindFileHandle; WIN32_FIND_DATA wfdCurFile; size_t cchCurDirNameLen = pdrpParamsInout->m_cchDirNameLen; ZeroMemory( &wfdCurFile, sizeof( wfdCurFile ) ); if ( pdrpParamsInout->m_iMaxDepth < 0 ) { dwError = TW32( ERROR_DIR_NOT_EMPTY ); break; } // if: the recursion is too deep. // // Check if the target directory name is too long. The two extra characters // being checked for are '\\' and '*'. // if ( cchCurDirNameLen > ( pdrpParamsInout->m_cchDirNameMax - 2 ) ) { dwError = TW32( ERROR_BUFFER_OVERFLOW ); break; } // if: the target directory name is too long. // Append "\*" to the end of the directory name pdrpParamsInout->m_pszDirName[ cchCurDirNameLen ] = L'\\'; pdrpParamsInout->m_pszDirName[ cchCurDirNameLen + 1 ] = L'*'; pdrpParamsInout->m_pszDirName[ cchCurDirNameLen + 2 ] = L'\0'; ++cchCurDirNameLen; SmartFindFileHandle sffhFindFileHandle( FindFirstFile( pdrpParamsInout->m_pszDirName, &wfdCurFile ) ); if ( sffhFindFileHandle.FIsInvalid() ) { dwError = TW32( GetLastError() ); break; } do { size_t cchFileNameLen; // If the current file is a directory, make a recursive call to delete it. if ( ( wfdCurFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 ) { if ( ( wcscmp( wfdCurFile.cFileName, L"." ) != 0 ) && ( wcscmp( wfdCurFile.cFileName, L".." ) != 0 ) ) { cchFileNameLen = wcslen( wfdCurFile.cFileName ); // Append the subdirectory name past the last '\\' character. THR( StringCchCopyW( pdrpParamsInout->m_pszDirName + cchCurDirNameLen , pdrpParamsInout->m_cchDirNameMax - cchCurDirNameLen , wfdCurFile.cFileName ) ); // Update the parameter object. --pdrpParamsInout->m_iMaxDepth; pdrpParamsInout->m_cchDirNameLen = cchCurDirNameLen + cchFileNameLen; // Delete the subdirectory. dwError = TW32( DwRecursiveEmptyDirectory( pdrpParamsInout ) ); if ( dwError != ERROR_SUCCESS ) { break; } // if: an error occurred trying to empty this directory. // Restore the parameter object. There is no need to restore m_cchDirNameLen // since it is never used again in the RHS in this function. ++pdrpParamsInout->m_iMaxDepth; if ( RemoveDirectory( pdrpParamsInout->m_pszDirName ) == FALSE ) { dwError = TW32( GetLastError() ); break; } // if: the current directory could not be removed. } // if: the current directory is not "." or ".." } // if: current file is a directory. else { // // This file is not a directory. Delete it. // cchFileNameLen = wcslen( wfdCurFile.cFileName ); if ( cchFileNameLen > ( pdrpParamsInout->m_cchDirNameMax - cchCurDirNameLen ) ) { dwError = TW32( ERROR_BUFFER_OVERFLOW ); break; } // Append the file name to the directory name. THR( StringCchCopyW( pdrpParamsInout->m_pszDirName + cchCurDirNameLen , pdrpParamsInout->m_cchDirNameMax - cchCurDirNameLen , wfdCurFile.cFileName ) ); if ( DeleteFile( pdrpParamsInout->m_pszDirName ) == FALSE ) { dwError = TW32( GetLastError() ); break; } // if: DeleteFile failed. } // else: current file is not a directory. if ( FindNextFile( sffhFindFileHandle.HHandle(), &wfdCurFile ) == FALSE ) { dwError = GetLastError(); if ( dwError == ERROR_NO_MORE_FILES ) { // We have deleted all the files in this directory. dwError = ERROR_SUCCESS; } else { TW32( dwError ); } // If FindNextFile has failed, we are done. break; } // if: FindNextFile fails. } while( true ); // loop infinitely. if ( dwError != ERROR_SUCCESS ) { break; } // if: something went wrong. // // If we are here, then all the files in this directory have been deleted. // // Truncate the directory name at the last '\' pdrpParamsInout->m_pszDirName[ cchCurDirNameLen - 1 ] = L'\0'; } while( false ); // dummy do while loop to avoid gotos. return dwError; } //*** DwRecursiveEmptyDirectory ////////////////////////////////////////////////////////////////////////////// //++ // // DWORD // DwRemoveDirectory // // Description: // Remove the target directory and everything underneath it. // Calls DwRecursiveEmptyDirectory to do the actual work. // // Arguments: // pcszTargetDirIn // The directory to be removed. Note, this name cannot have trailing // backslash '\' characters. // // iMaxDepthIn // The maximum depth of the subdirectories that will be removed. // Default value is 32. If this depth is exceeded, an exception // is thrown. // // Return Value: // ERROR_SUCCESS // The directory was deleted // // Other Win32 error codes // If something went wrong // // Remarks: // If the length of the name of any of the files under pcszTargetDirIn // exceeds MAX_PATH - 1, an error is returned. // //-- ////////////////////////////////////////////////////////////////////////////// DWORD DwRemoveDirectory( const WCHAR * pcszTargetDirIn, signed int iMaxDepthIn ) { WCHAR szDirBuffer[ MAX_PATH ]; SDirRemoveParams drpParams; DWORD dwError = ERROR_SUCCESS; WIN32_FILE_ATTRIBUTE_DATA wfadDirAttributes; if ( pcszTargetDirIn == NULL ) { goto Cleanup; } // if: the directory name is NULL ZeroMemory( &wfadDirAttributes, sizeof( wfadDirAttributes ) ); // // Check if the directory exists. // if ( GetFileAttributesEx( pcszTargetDirIn, GetFileExInfoStandard, &wfadDirAttributes ) == FALSE ) { dwError = GetLastError(); if ( dwError == ERROR_FILE_NOT_FOUND ) { dwError = ERROR_SUCCESS; } // if: the directory does not exist, this is not an error else { TW32( dwError ); } goto Cleanup; } // if: we could not get the file attributes if ( ( wfadDirAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) { // We are not going to delete files goto Cleanup; } // if: the path does not point to a directory // Copy the input string to our buffer. THR( StringCchCopyW( szDirBuffer, RTL_NUMBER_OF( szDirBuffer ), pcszTargetDirIn ) ); // Initialize the object that holds the parameters for the recursive call. drpParams.m_pszDirName = szDirBuffer; drpParams.m_cchDirNameLen = static_cast< UINT >( wcslen( szDirBuffer ) ); drpParams.m_cchDirNameMax = RTL_NUMBER_OF( szDirBuffer ) - 1; drpParams.m_iMaxDepth = iMaxDepthIn; // Call the actual recursive function to empty the directory. dwError = TW32( DwRecursiveEmptyDirectory( &drpParams ) ); // If the directory was emptied, delete it. if ( ( dwError == ERROR_SUCCESS ) && ( RemoveDirectory( pcszTargetDirIn ) == FALSE ) ) { dwError = TW32( GetLastError() ); goto Cleanup; } // if: the current directory could not be removed. Cleanup: return dwError; } //*** DwRemoveDirectory