432 lines
13 KiB
C++
432 lines
13 KiB
C++
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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<UINT>( 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()
|