You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
488 lines
12 KiB
488 lines
12 KiB
/*++
|
|
|
|
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 <size>" 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 ) );
|
|
}
|