///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2001 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. UINT m_uiDirNameLen; // Length of string currently in buffer (does not include '\0') UINT m_uiDirNameMax; // Max length of string in buffer (does not include '\0') signed int m_iMaxDepth; // Maximum recursion depth. }; ////////////////////////////////////////////////////////////////////////////// // Forward Declarations. ////////////////////////////////////////////////////////////////////////////// DWORD DwRecursiveEmptyDirectory( SDirRemoveParams * pdrpParamsInOut ); ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // HrCreateDirectoryPath( // LPWSTR pszDirectoryPathInOut // ) // // Descriptions: // Creates the directory tree as required. // // Arguments: // pszDirectoryPathOut // Must be MAX_PATH big. It will contain the trace log file path to // create. // // Return Values: // S_OK - Success // other HRESULTs for failures // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT HrCreateDirectoryPath( LPWSTR pszDirectoryPath ) { LPTSTR psz; BOOL fReturn; DWORD dwAttr; HRESULT hr = S_OK; // // Find the \ that indicates the root directory. There should be at least // one \, but if there isn't, we just fall through. // // skip X:\ part psz = wcschr( pszDirectoryPath, L'\\' ); Assert( psz != NULL ); if ( psz != NULL ) { // // Find the \ that indicates the end of the first level directory. It's // probable that there won't be another \, in which case we just fall // through to creating the entire path. // psz = wcschr( psz + 1, L'\\' ); while ( psz != NULL ) { // Terminate the directory path at the current level. *psz = 0; // // Create a directory at the current level. // dwAttr = GetFileAttributes( pszDirectoryPath ); if ( 0xFFFFffff == dwAttr ) { DebugMsg( TEXT("DEBUG: Creating %s"), pszDirectoryPath ); fReturn = CreateDirectory( pszDirectoryPath, NULL ); if ( ! fReturn ) { hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) ); goto Error; } // if: creation failed } // if: directory not found else if ( ( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) { hr = THR( E_FAIL ); goto Error; } // else: file found // // Restore the \ and find the next one. // *psz = L'\\'; psz = wcschr( psz + 1, L'\\' ); } // while: found slash } // if: found slash // // Create the target directory. // dwAttr = GetFileAttributes( pszDirectoryPath ); if ( 0xFFFFffff == dwAttr ) { fReturn = CreateDirectory( pszDirectoryPath, NULL ); if ( ! fReturn ) { hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) ); } // if: creation failed } // if: path not found Error: return hr; } //*** HrCreateDirectoryPath() ////////////////////////////////////////////////////////////////////////////// //++ // // 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; UINT uiCurDirNameLen = pdrpParamsInOut->m_uiDirNameLen; 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 ( uiCurDirNameLen > ( pdrpParamsInOut->m_uiDirNameMax - 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[ uiCurDirNameLen ] = '\\'; pdrpParamsInOut->m_pszDirName[ uiCurDirNameLen + 1 ] = '*'; pdrpParamsInOut->m_pszDirName[ uiCurDirNameLen + 2 ] = '\0'; ++uiCurDirNameLen; SmartFindFileHandle sffhFindFileHandle( FindFirstFile( pdrpParamsInOut->m_pszDirName, &wfdCurFile ) ); if ( sffhFindFileHandle.FIsInvalid() ) { dwError = TW32( GetLastError() ); break; } do { size_t stFileNameLen; // 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 ) ) { stFileNameLen = wcslen( wfdCurFile.cFileName ); // Append the subdirectory name past the last '\\' character. wcsncpy( pdrpParamsInOut->m_pszDirName + uiCurDirNameLen , wfdCurFile.cFileName , pdrpParamsInOut->m_uiDirNameMax - uiCurDirNameLen + 1 ); // Update the parameter object. --pdrpParamsInOut->m_iMaxDepth; pdrpParamsInOut->m_uiDirNameLen = uiCurDirNameLen + static_cast( stFileNameLen ); // 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_uiDirNameLen // 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. // stFileNameLen = wcslen( wfdCurFile.cFileName ); if ( stFileNameLen > ( pdrpParamsInOut->m_uiDirNameMax - uiCurDirNameLen ) ) { dwError = TW32( ERROR_BUFFER_OVERFLOW ); break; } // Append the file name to the directory name. wcsncpy( pdrpParamsInOut->m_pszDirName + uiCurDirNameLen , wfdCurFile.cFileName , pdrpParamsInOut->m_uiDirNameMax - uiCurDirNameLen + 1 ); 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[ uiCurDirNameLen - 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. wcsncpy( szDirBuffer, pcszTargetDirIn, MAX_PATH ); szDirBuffer[ MAX_PATH - 1 ] = L'\0'; // Initialize the object that holds the parameters for the recursive call. drpParams.m_pszDirName = szDirBuffer; drpParams.m_uiDirNameLen = static_cast< UINT >( wcslen( szDirBuffer ) ); drpParams.m_uiDirNameMax = ( sizeof( szDirBuffer ) / sizeof( szDirBuffer[0] ) ) - 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()