windows-nt/Source/XPSP1/NT/sdktools/emptydirs/exe/emptydirs.c
2020-09-26 16:20:57 +08:00

337 lines
7.4 KiB
C

#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