#include "precomp.h" #pragma hdrstop #if SCAN_DEBUG BOOL dprinton = FALSE; #endif // // This flag indicates whether empty directories should be deleted. // BOOL DeleteEmptyDirectories = FALSE; BOOL ContinueOnError = FALSE; BOOL Quiet = FALSE; BOOL ShowWriteableFiles = FALSE; DWORD NewFile ( IN PVOID Context, IN PWCH Path, IN PSMALL_WIN32_FIND_DATAW ExistingFileData OPTIONAL, IN PWIN32_FIND_DATAW NewFileData, IN PVOID *FileUserData, IN PVOID *ParentDirectoryUserData ) /*++ Routine Description: Called when ScanDirectory finds a file. Arguments: Context - User-supplied context. Not used by emptydirs. Path - Directory containing this file. ExistingFileData - Pointer to data describing previous found file with same name, if any. NewFileData - Pointer to data for this file. FileUserData - Pointer to user-controlled data field for the file. ParentDirectoryUserData - Pointer to user-controlled data field for the parent directory. Return Value: DWORD - Indicates whether an error occurred. --*/ { // // Increment the directory/file count for the parent. Set the file's // user data pointer to NULL, indicating that we don't need the // scan library to remember this file. // (*(DWORD *)ParentDirectoryUserData)++; *FileUserData = NULL; dprintf(( " NF: File %ws\\%ws: parent count %d, file count %d\n", Path, NewFileData->cFileName, *(DWORD *)ParentDirectoryUserData, *FileUserData )); // // If we're supposed to show writeable files, check for that now. // if ( ShowWriteableFiles && ((NewFileData->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) ) { printf( "FILE: %ws\\%ws\n", Path, NewFileData->cFileName ); } return 0; } // NewFile DWORD NewDirectory ( IN PVOID Context, IN PWCH Path, IN PSMALL_WIN32_FIND_DATAW ExistingDirectoryData OPTIONAL, IN PWIN32_FIND_DATAW NewDirectoryData, IN PVOID *DirectoryUserData, IN PVOID *ParentDirectoryUserData ) /*++ Routine Description: Called when ScanDirectory finds a directory. Arguments: Context - User-supplied context. Not used by emptydirs. Path - Directory containing this directory. ExistingDirectoryData - Pointer to data describing previous found directory with same name, if any. NewDirectoryData - Pointer to data for this directory. DirectoryUserData - Pointer to user-controlled data field for the directory. ParentDirectoryUserData - Pointer to user-controlled data field for the parent directory. Return Value: DWORD - Indicates whether an error occurred. --*/ { // // Increment the directory/file count for the parent. Set the directory's // user data pointer to 1, indicating that the scan library should // remember this directory and scan it. // (*(DWORD *)ParentDirectoryUserData)++; *(DWORD *)DirectoryUserData = 1; dprintf(( " ND: Dir %ws\\%ws: parent count %d, dir count %d\n", Path, NewDirectoryData->cFileName, *(DWORD *)ParentDirectoryUserData, *DirectoryUserData )); return 0; } // NewDirectory DWORD CheckDirectory ( IN PVOID Context, IN PWCH Path, IN PSMALL_WIN32_FIND_DATAW DirectoryData, IN PVOID *DirectoryUserData, IN PVOID *ParentDirectoryUserData ) /*++ Routine Description: Called when ScanDirectory has completed the recursive scan for a directory. Arguments: Context - User-supplied context. Not used by emptydirs. Path - Path to this directory. (Not to containing directory.) DirectoryData - Pointer to data for this directory. DirectoryUserData - Pointer to user-controlled data field for the directory. ParentDirectoryUserData - Pointer to user-controlled data field for the parent directory. Return Value: DWORD - Indicates whether an error occurred. --*/ { BOOL ok; DWORD error; // // If the directory's directory/file count is 1, then the directory // contains no files or directories (the count is biased by 1), and // is empty. // if ( *(DWORD *)DirectoryUserData == 1 ) { if ( !Quiet ) { if ( ShowWriteableFiles ) { printf( "DIR: " ); } printf( "%ws", Path ); } // // If requested, delete this empty directory. // if ( DeleteEmptyDirectories ) { ok = RemoveDirectory( Path ); if ( !ok ) { error = GetLastError( ); if ( !Quiet ) printf( " - error %d\n", error ); fprintf( stderr, "Error %d deleting %ws\n", error, Path ); if ( !ContinueOnError ) { return error; } } else { if ( !Quiet ) printf( " - deleted\n" ); } } else { if ( !Quiet ) printf( "\n" ); } // // Decrement the parent directory's directory/file count. // (*(DWORD *)ParentDirectoryUserData)--; } dprintf(( " CD: Dir %ws: parent count %d, dir count %d\n", Path, *(DWORD *)ParentDirectoryUserData, *DirectoryUserData )); return 0; } // CheckDirectory int __cdecl wmain ( int argc, WCHAR *argv[] ) { BOOL ok; DWORD error; WCHAR directory[MAX_PATH]; PVOID scanHandle = NULL; // // Parse switches. // argc--; argv++; while ( (argc != 0) && ((argv[0][0] == '-') || (argv[0][0] == '/')) ) { argv[0]++; switch ( towlower(argv[0][0]) ) { case 'c': ContinueOnError = TRUE; break; case 'd': DeleteEmptyDirectories = TRUE; break; case 'q': Quiet = TRUE; break; case 'w': ShowWriteableFiles = TRUE; break; default: fprintf( stderr, "usage: emptydirs [-cdqw]\n" ); return 1; } argc--; argv++; } // // If a directory was specified, CD to it and get its path. // if ( argc != 0 ) { ok = SetCurrentDirectory( argv[0] ); if ( !ok ) { error = GetLastError( ); fprintf( stderr, "error: Unable to change to specified directory %ws: %d\n", argv[0], error ); goto cleanup; } } argc--; argv++; GetCurrentDirectory( MAX_PATH, directory ); // // Initialize the scan library. // error = ScanInitialize( &scanHandle, TRUE, // recurse FALSE, // don't skip root NULL ); if (error != 0) { fprintf( stderr, "ScanInitialize(%ws) failed %d\n", directory, error ); error = 1; goto cleanup; } // // Scan the specified directory. // error = ScanDirectory( scanHandle, directory, NULL, NewDirectory, CheckDirectory, NULL, NewFile, NULL ); if (error != 0) { fprintf( stderr, "ScanDirectory(%ws) failed %d\n", directory, error ); error = 1; goto cleanup; } cleanup: // // Close down the scan library. // if ( scanHandle != NULL ) { ScanTerminate( scanHandle ); } return error; } // wmain