/*++ Copyright (c) 1991-2001 Microsoft Corporation Module Name: autofmt.cxx Abstract: This is the main program for the autofmt version of format. Author: Matthew Bradburn (mattbr) 13-Dec-94 --*/ #include "ulib.hxx" #include "wstring.hxx" #include "achkmsg.hxx" #include "spackmsg.hxx" #include "tmackmsg.hxx" #include "ifssys.hxx" #include "rtmsg.h" #include "ifsentry.hxx" #include "fatvol.hxx" #include "ntfsvol.hxx" #include "autoreg.hxx" #include "autoentr.hxx" #include "arg.hxx" extern "C" BOOLEAN InitializeUfat( PVOID DllHandle, ULONG Reason, PCONTEXT Context ); extern "C" BOOLEAN InitializeUhpfs( PVOID DllHandle, ULONG Reason, PCONTEXT Context ); extern "C" BOOLEAN InitializeUntfs( PVOID DllHandle, ULONG Reason, PCONTEXT Context ); extern "C" BOOLEAN InitializeIfsUtil( PVOID DllHandle, ULONG Reason, PCONTEXT Context ); BOOLEAN DeRegister( int argc, char** argv ); BOOLEAN SavemessageLog( IN OUT PMESSAGE message, IN PCWSTRING drive_name ); int __cdecl main( int argc, char** argv, char** envp, ULONG DebugParameter ) /*++ Routine Description: This routine is the main program for AutoFmt Arguments: argc, argv - Supplies the fully qualified NT path name of the the drive to check. The syntax of the autofmt command line is: AUTOFMT drive-name /FS:target-file-system [/V:label] [/Q] [/A:size] [/C] [/S] Return Value: 0 - Success. 1 - Failure. --*/ { if (!InitializeUlib( NULL, ! DLL_PROCESS_DETACH, NULL ) || !InitializeIfsUtil(NULL, ! DLL_PROCESS_DETACH, NULL) || !InitializeUfat(NULL, ! DLL_PROCESS_DETACH, NULL) || !InitializeUntfs(NULL, ! DLL_PROCESS_DETACH, NULL) ) { return 1; } PFAT_VOL fat_volume; PNTFS_VOL ntfs_volume; PDP_DRIVE dp_drive; PAUTOCHECK_MESSAGE message; DSTRING drive_name; DSTRING file_system_name; DSTRING label; DSTRING fat_name; DSTRING ntfs_name; DSTRING fat32_name; BOOLEAN quick = FALSE; BOOLEAN compress = FALSE; BOOLEAN error; FORMAT_ERROR_CODE success; BOOLEAN setup_output = FALSE; BOOLEAN textmode_output = FALSE; BIG_INT bigint; ULONG cluster_size = 0; int i; LARGE_INTEGER delay_interval; if (!file_system_name.Initialize()) { return 1; } if (!label.Initialize() || NULL == (dp_drive = NEW DP_DRIVE)) { return 1; } // // Parse the arguments. // if ( argc < 2 ) { return 1; } // // First argument is drive // if ( !drive_name.Initialize( argv[1] ) ) { return 1; } DebugPrintTrace(("drive name: %ws\n", drive_name.GetWSTR())); // // The rest of the arguments are flags. // for (i = 2; i < argc; i++) { if ((argv[i][0] == '/' || argv[i][0] == '-') && (argv[i][1] == 'f' || argv[i][1] == 'F') && (argv[i][2] == 's' || argv[i][2] == 'S') && (argv[i][3] == ':')) { if (!file_system_name.Initialize(&argv[i][4])) { return 1; } DebugPrintTrace(("fsname: %ws\n", file_system_name.GetWSTR())); continue; } if ((argv[i][0] == '/' || argv[i][0] == '-') && (argv[i][1] == 'v' || argv[i][1] == 'V') && (argv[i][2] == ':')) { if (!label.Initialize(&argv[i][3])) { return 1; } continue; } if ((argv[i][0] == '/' || argv[i][0] == '-') && (argv[i][1] == 'a' || argv[i][1] == 'A') && (argv[i][2] == ':')) { cluster_size = atoi(&argv[i][3]); continue; } if (0 == _stricmp(argv[i], "/Q") || 0 == _stricmp(argv[i], "-Q")) { quick = TRUE; continue; } if (0 == _stricmp(argv[i], "/C") || 0 == _stricmp(argv[i], "-C")) { compress = TRUE; continue; } if (0 == _stricmp(argv[i], "/S") || 0 == _stricmp(argv[i], "-S")) { setup_output = TRUE; } if (0 == _stricmp(argv[i], "/T") || 0 == _stricmp(argv[i], "-T")) { textmode_output = TRUE; } } if (textmode_output) { message = NEW TM_AUTOCHECK_MESSAGE; } else if (setup_output) { message = NEW SP_AUTOCHECK_MESSAGE; DebugPrintTrace(("Using setup output\n")); } else { DebugPrintTrace(("Not using setup output\n")); message = NEW AUTOCHECK_MESSAGE; } if (NULL == message || !message->Initialize()) { return 1; } #if 0 // Shouldn't limit the cluster size as long as it is reasonable. if (cluster_size != 0 && cluster_size != 512 && cluster_size != 1024 && cluster_size != 2048 && cluster_size != 4096) { message->Set(MSG_UNSUPPORTED_PARAMETER); message->Display(); DeRegister( argc, argv ); return 1; } #endif if (0 == file_system_name.QueryChCount()) { // attempt to get the current filesystem type from disk if (!IFS_SYSTEM::QueryFileSystemName(&drive_name, &file_system_name)) { message->Set( MSG_FS_NOT_DETERMINED ); message->Display( "%W", &drive_name ); DeRegister( argc, argv ); return 1; } file_system_name.Strupr(); } if (!fat_name.Initialize("FAT") || !ntfs_name.Initialize("NTFS") || !fat32_name.Initialize("FAT32")) { return 1; } file_system_name.Strupr(); // // If compression is requested, make sure it's available. // if (compress && file_system_name != ntfs_name) { message->Set(MSG_COMPRESSION_NOT_AVAILABLE); message->Display("%W", &file_system_name); DeRegister( argc, argv ); return 1; } // Since autoformat will often be put in place by Setup // to run after AutoSetp, delay for 3 seconds to give the // file system time to clean up detritus of deleted files. // delay_interval = RtlConvertLongToLargeInteger( -30000000 ); NtDelayExecution( TRUE, &delay_interval ); if (!dp_drive->Initialize(&drive_name, message)) { DeRegister( argc, argv ); return 1; } if (dp_drive->IsFloppy()) { // MJB: refuse to format DeRegister( argc, argv ); return 1; } switch (dp_drive->QueryDriveType()) { case UnknownDrive: message->Set(MSG_NONEXISTENT_DRIVE); message->Display(""); DeRegister( argc, argv ); return 1; case RemoteDrive: // it probably won't get that far message->Set(MSG_FORMAT_NO_NETWORK); message->Display(""); DeRegister( argc, argv ); return 1; case RamDiskDrive: // it probably won't get that far message->Set(MSG_FORMAT_NO_RAMDISK); message->Display(""); DeRegister( argc, argv ); return 1; default: break; } // // Print the "formatting " message. // if (quick) { message->Set(MSG_QUICKFORMATTING_MB); } else { message->Set(MSG_FORMATTING_MB); } bigint = dp_drive->QuerySectors() * dp_drive->QuerySectorSize() / 1048576; DebugAssert(bigint.GetHighPart() == 0); message->Display("%d", bigint.GetLowPart()); if (file_system_name == fat_name || file_system_name == fat32_name) { BOOLEAN old_fat_vol = TRUE; if( file_system_name == fat32_name ) { old_fat_vol = FALSE; } if( !(fat_volume = NEW FAT_VOL) || NoError != fat_volume->Initialize( &drive_name, message, FALSE, !quick, Unknown )) { DeRegister( argc, argv ); return 1; } success = fat_volume->Format(&label, message, old_fat_vol ? FORMAT_BACKWARD_COMPATIBLE : 0, cluster_size); DebugPrintTrace(("Format return code: %d\n", success)); DELETE( fat_volume ); } else if (file_system_name == ntfs_name) { if (dp_drive->QueryDriveType() == CdRomDrive) { message->Set(MSG_FMT_NO_NTFS_ALLOWED); message->Display(); DeRegister( argc, argv ); return 1; } if( !(ntfs_volume = NEW NTFS_VOL) || NoError != ntfs_volume->Initialize( &drive_name, message, FALSE, !quick, Unknown )) { DeRegister( argc, argv ); return 1; } success = ntfs_volume->Format(&label, message, 0, cluster_size); DebugPrintTrace(("Format return code: %d\n", success)); DELETE( ntfs_volume ); } else { message->Set( MSG_FS_NOT_SUPPORTED ); message->Display( "%s%W", "AUTOFMT", &file_system_name); DeRegister( argc, argv ); return 1; } // Truncate "fat32" back to "fat"...yuck.. if (file_system_name == fat32_name) { if (!file_system_name.Initialize("FAT")) { DeRegister( argc, argv ); return 1; } } // Make sure the file system is installed. if (!IFS_SYSTEM::IsFileSystemEnabled(&file_system_name)) { message->Set(MSG_FMT_INSTALL_FILE_SYSTEM); message->Display("%W", &file_system_name); if (!IFS_SYSTEM::EnableFileSystem(&file_system_name)) { message->Set(MSG_FMT_CANT_INSTALL_FILE_SYSTEM); message->Display(); return 1; } message->Set(MSG_FMT_FILE_SYSTEM_INSTALLED); message->Display(); } if (compress && !IFS_SYSTEM::EnableVolumeCompression(&drive_name)) { message->Set(MSG_CANNOT_ENABLE_COMPRESSION); message->Display(); DeRegister( argc, argv ); return 1; } DeRegister( argc, argv ); return (success != NoError); } BOOLEAN DeRegister( int argc, char** argv ) /*++ Routine Description: This function removes the registry entry which triggered autoconvert. Arguments: argc -- Supplies the number of arguments given to autoconv argv -- supplies the arguments given to autoconv Return Value: TRUE upon successful completion. --*/ { DSTRING CommandLineString1, CommandLineString2, CurrentArgString, OneSpace; int i; // Reconstruct the command line and remove it from // the registry. First, reconstruct the primary // string, which is "autoconv arg1 arg2...". // if( !CommandLineString1.Initialize( L"autofmt" ) || !OneSpace.Initialize( L" " ) ) { return FALSE; } for( i = 1; i < argc; i++ ) { if( !CurrentArgString.Initialize( argv[i] ) || !CommandLineString1.Strcat( &OneSpace ) || !CommandLineString1.Strcat( &CurrentArgString ) ) { return FALSE; } } // Now construct the secondary string, which is // "autocheck arg0 arg1 arg2..." // if( !CommandLineString2.Initialize( "autocheck " ) || !CommandLineString2.Strcat( &CommandLineString1 ) ) { return FALSE; } return( AUTOREG::DeleteEntry( &CommandLineString1 ) && AUTOREG::DeleteEntry( &CommandLineString2 ) ); }