Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1473 lines
38 KiB

/*++
Copyright (c) 1991-2001 Microsoft Corporation
Module Name:
convert.cxx
Abstract:
This module contains the definition of the CONVERT class, which
implements the File System Conversion Utility.
Author:
Ramon J. San Andres (ramonsa) sep-23-1991
Environment:
ULIB, User Mode
--*/
#define _NTAPI_ULIB_
#include "ulib.hxx"
#if defined(FE_SB) && defined(_X86_)
#include "machine.hxx"
#endif
#include "ulibcl.hxx"
#include "arg.hxx"
#include "file.hxx"
#include "smsg.hxx"
#include "rtmsg.h"
#include "wstring.hxx"
#include "system.hxx"
#include "autoreg.hxx"
#include "ifssys.hxx"
#include "ifsentry.hxx"
#include "hmem.hxx"
#include "convert.hxx"
#include "supera.hxx"
extern "C" {
#include <stdio.h>
#include "undo.h"
}
#include "fatofs.hxx"
#define AUTOCHK_PROGRAM_NAME L"AUTOCHK.EXE"
#define AUTOCONV_PROGRAM_NAME L"AUTOCONV.EXE"
#define AUTOCHK_NAME L"AUTOCHK"
#define AUTOCONV_NAME L"AUTOCONV"
#define VALUE_NAME_PATH L"PATH"
#define VALUE_NAME_ARGS L"ARGUMENTS"
#define VALUE_NAME_FS L"TARGET FILESYSTEM"
//
// Scheduling status codes
//
#define CONV_STATUS_NONE 0
#define CONV_STATUS_SCHEDULED 1
static WCHAR NameBuffer[16]; // holds cvf name
DWORD
WINAPI
SceConfigureConvertedFileSecurity(
IN PWSTR pszDriveName,
IN DWORD dwConvertDisposition
);
INT __cdecl
main (
)
/*++
Routine Description:
Entry point for the conversion utility.
Arguments:
None.
Return Value:
One of the CONVERT exit codes.
Notes:
--*/
{
INT ExitCode = EXIT_ERROR; // Let's be pessimistic
DEFINE_CLASS_DESCRIPTOR( CONVERT );
{
CONVERT Convert;
//
// Initialize the CONVERT object.
//
if ( Convert.Initialize( &ExitCode ) ) {
//
// Do the conversion
//
ExitCode = Convert.Convert();
}
}
return ExitCode;
}
DEFINE_CONSTRUCTOR( CONVERT, PROGRAM );
NONVIRTUAL
VOID
CONVERT::Construct (
)
/*++
Routine Description:
converts a CONVERT object
Arguments:
None.
Return Value:
None.
Notes:
--*/
{
_Autochk = NULL;
_Autoconv = NULL;
}
NONVIRTUAL
VOID
CONVERT::Destroy (
)
/*++
Routine Description:
Destroys a CONVERT object
Arguments:
None.
Return Value:
None.
Notes:
--*/
{
DELETE( _Autochk );
DELETE( _Autoconv );
}
CONVERT::~CONVERT (
)
/*++
Routine Description:
Destructs a CONVERT object
Arguments:
None.
Return Value:
None.
Notes:
--*/
{
Destroy();
}
BOOLEAN
CONVERT::Initialize (
OUT PINT ExitCode
)
/*++
Routine Description:
Initializes the CONVERT object. Initialization consist of allocating memory
for certain object members and argument parsing.
Arguments:
ExitCode - Supplies pointer to CONVERT exit code.
Return Value:
BOOLEAN - TRUE if initialization succeeded, FALSE otherwise.
Notes:
--*/
{
Destroy();
//
// Initialize program object
//
if ( PROGRAM::Initialize( MSG_CONV_USAGE ) ) {
//
// Parse the arguments
//
return ParseArguments( ExitCode );
}
//
// Could not initialize the program object.
//
*ExitCode = EXIT_ERROR;
return FALSE;
}
INT
CONVERT::Convert (
)
/*++
Routine Description:
Converts the file system in a volume.
Depending on the current file system, it loads the appropriate
conversion library and calls its conversion entry point.
Arguments:
None
Return Value:
INT - One of the CONVERT return codes
Notes:
--*/
{
DSTRING CurrentFsName; // Name of current FS in volume
DSTRING LibraryName; // Name of library to load
DSTRING EntryPoint; // Name of entry point in DLL
DSTRING fat_name;
DSTRING fat32_name;
DSTRING driveletter;
DSTRING user_old_label;
DSTRING null_string;
PWSTRING old_volume_label = NULL;
PATH dos_drive_path;
INT ExitCode = EXIT_SUCCESS; // CONVERT exit code
CONVERT_STATUS ConvertStatus; // Conversion status
NTSTATUS Status; // NT API status
HANDLE FsUtilityHandle; // Handle to DLL
CONVERT_FN Convert; // Pointer to entry point in DLL
IS_CONVERSION_AVAIL_FN IsConversionAvailable;
DWORD OldErrorMode;
DRIVE_TYPE drive_type;
VOL_SERIAL_NUMBER old_serial;
BOOLEAN Error = FALSE;
BOOLEAN Success;
BOOLEAN Result;
ULONG flags;
#if defined(FE_SB) && defined(_X86_)
if(IsPC98_N()){
CONVERT Convert2;
Convert2.ChangeBPB1(&_NtDrive);
}
#endif
// Check to see if this is an ARC System Partition--if it
// is, don't convert it.
//
if( IFS_SYSTEM::IsArcSystemPartition( &_NtDrive, &Error ) ) {
DisplayMessage( MSG_CONV_ARC_SYSTEM_PARTITION, ERROR_MESSAGE );
return EXIT_ERROR;
}
//
// Ask the volume what file system it has, and use that name to
// figure out what DLL to load.
//
if ( !IFS_SYSTEM::QueryFileSystemName( &_NtDrive,
&CurrentFsName,
&Status )) {
if ( Status == STATUS_ACCESS_DENIED ) {
DisplayMessage( MSG_DASD_ACCESS_DENIED, ERROR_MESSAGE );
} else {
DisplayMessage( MSG_FS_NOT_DETERMINED, ERROR_MESSAGE, "%W", &_DisplayDrive );
}
return EXIT_ERROR;
}
CurrentFsName.Strupr();
_FsName.Strupr();
if( CurrentFsName == _FsName ) {
DisplayMessage( MSG_CONV_ALREADY_CONVERTED, ERROR_MESSAGE, "%W%W",
&_DisplayDrive, &_FsName );
return EXIT_ERROR;
}
if (!fat_name.Initialize("FAT") ||
!fat32_name.Initialize("FAT32")) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
return EXIT_ERROR;
}
if (CurrentFsName == fat_name || CurrentFsName == fat32_name) {
if ( !LibraryName.Initialize( "CNVFAT" ) ||
!EntryPoint.Initialize( "IsConversionAvailable" ) ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
return( EXIT_ERROR );
}
//
// Get pointer to the conversion entry point and convert the volume.
//
if (NULL == (IsConversionAvailable =
(IS_CONVERSION_AVAIL_FN)SYSTEM::QueryLibraryEntryPoint(
&LibraryName, &EntryPoint, &FsUtilityHandle ))) {
//
// There is no conversion DLL for the file system in the volume.
//
DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
"CONVERT", &CurrentFsName );
return EXIT_ERROR;
}
if (IsConversionAvailable(&_FsName) == -1) {
DisplayMessage ( MSG_CONV_CONVERSION_NOT_AVAILABLE, ERROR_MESSAGE,
"%W%W", &CurrentFsName, &_FsName );
return EXIT_ERROR;
}
} else {
DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
"CONVERT", &CurrentFsName );
return EXIT_ERROR;
}
//
// Display the current file system type. (Standard in all file system utilities)
//
DisplayMessage( MSG_FILE_SYSTEM_TYPE, NORMAL_MESSAGE, "%W", &CurrentFsName );
//
// We also initialize the name of the conversion entry point in the DLL
// ("Convert")
//
if ( !EntryPoint.Initialize( "ConvertFAT" )) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
return( EXIT_ERROR );
}
//
// Get pointer to the conversion entry point and convert the volume.
//
if (NULL == (Convert = (CONVERT_FN)SYSTEM::QueryLibraryEntryPoint(
&LibraryName, &EntryPoint, &FsUtilityHandle ))) {
//
// There is no conversion DLL for the file system in the volume.
//
DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
"CONVERT", &CurrentFsName );
return EXIT_ERROR;
}
// If the volume has a label, prompt the user for it.
// Note that if it has no label we do nothing.
OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
drive_type = SYSTEM::QueryDriveType(&_DosDrive);
if (null_string.Initialize( "" ) &&
(drive_type != RemovableDrive) &&
dos_drive_path.Initialize( &_DosDrive) &&
(old_volume_label =
SYSTEM::QueryVolumeLabel( &dos_drive_path,
&old_serial )) != NULL &&
old_volume_label->Stricmp( &null_string ) != 0 ) {
// This drive has a label. To give the user
// a bit more protection, prompt for the old label:
DisplayMessage( MSG_ENTER_CURRENT_LABEL, NORMAL_MESSAGE, "%W",
&_DisplayDrive );
_Message.QueryStringInput( &user_old_label );
if( old_volume_label->Stricmp( &user_old_label ) != 0 ) {
// Re-enable hard error popups.
SetErrorMode( OldErrorMode );
DisplayMessage( MSG_WRONG_CURRENT_LABEL, ERROR_MESSAGE );
DELETE( old_volume_label );
return EXIT_ERROR;
}
}
// Re-enable hard error popups
SetErrorMode( OldErrorMode );
DELETE( old_volume_label );
BOOLEAN delete_uninstall_backup = FALSE;
OSVERSIONINFOEX os_version_info;
if (Uninstall_Valid == IsUninstallImageValid(Uninstall_FatToNtfsConversion, &os_version_info)) {
DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP, NORMAL_MESSAGE );
if (!_Message.IsYesResponse(FALSE)) {
return EXIT_ERROR;
}
delete_uninstall_backup = TRUE;
}
flags = _Verbose ? CONVERT_VERBOSE_FLAG : 0;
flags |= _NoChkdsk ? CONVERT_NOCHKDSK_FLAG : 0;
flags |= _ForceDismount ? CONVERT_FORCE_DISMOUNT_FLAG : 0;
flags |= _NoSecurity ? CONVERT_NOSECURITY_FLAG : 0;
//
// no pause flag needed since we don't want to pause
//
Result = Convert( &_NtDrive,
&_FsName,
&_CvtZoneFileName,
&_Message,
flags,
&ConvertStatus);
SYSTEM::FreeLibraryHandle( FsUtilityHandle );
if ( Result ) {
DWORD sce_result = NO_ERROR;
ExitCode = EXIT_SUCCESS;
if (!_NoSecurity && _DosDrive.QueryChCount() == 2 && _DosDrive.QueryChAt(1) == ':') {
DSTRING msg;
sce_result = SceConfigureConvertedFileSecurity( (PWSTR)_DosDrive.GetWSTR(), 0 );
if ( sce_result != NO_ERROR ) {
if ( SYSTEM::QueryWindowsErrorMessage( sce_result, &msg ) ) {
DisplayMessage( MSG_CONV_SCE_FAILURE_WITH_MESSAGE, ERROR_MESSAGE, "%W", &msg );
} else {
DisplayMessage( MSG_CONV_SCE_SET_FAILURE, ERROR_MESSAGE, "%d", sce_result );
}
}
}
if (!NT_SUCCESS(SUPERAREA::GenerateLabelNotification(&_NtDrive))) {
DisplayMessage( MSG_CONV_UNABLE_TO_NOTIFY, ERROR_MESSAGE );
ExitCode = EXIT_ERROR;
}
if (delete_uninstall_backup && !RemoveUninstallImage()) {
DWORD last_error = GetLastError();
DSTRING errmsg;
if (SYSTEM::QueryWindowsErrorMessage( last_error, &errmsg )) {
DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%W", &errmsg );
} else {
DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%d", last_error );
}
ExitCode = EXIT_ERROR;
}
//
// We're done.
//
if ( sce_result == NO_ERROR && ExitCode == EXIT_SUCCESS ) {
DisplayMessage( MSG_CONV_CONVERSION_COMPLETE, NORMAL_MESSAGE );
return EXIT_SUCCESS;
} else {
return EXIT_ERROR;
}
} else {
//
// The conversion was not successful. Determine what the problem
// was and return the appropriate CONVERT exit code.
//
switch ( ConvertStatus ) {
case CONVERT_STATUS_CONVERTED:
//
// This is an inconsistent state, Convert should return
// TRUE if the conversion was successful!
//
DebugPrintTrace(( "CONVERT Error: Conversion failed, but status is success!\n" ));
DebugAssert( FALSE );
DisplayMessage( MSG_CONV_CONVERSION_MAYHAVE_FAILED, ERROR_MESSAGE,
"%W%W", &_DisplayDrive, &_FsName );
ExitCode = EXIT_ERROR;
break;
case CONVERT_STATUS_INVALID_FILESYSTEM:
//
// The conversion DLL does not recognize the target file system.
//
DisplayMessage( MSG_CONV_INVALID_FILESYSTEM, ERROR_MESSAGE, "%W", &_FsName );
ExitCode = EXIT_UNKNOWN;
break;
case CONVERT_STATUS_CONVERSION_NOT_AVAILABLE:
//
// The target file system is valid, but the conversion is not
// available.
//
DisplayMessage( MSG_CONV_CONVERSION_NOT_AVAILABLE, ERROR_MESSAGE,
"%W%W", &CurrentFsName, &_FsName );
ExitCode = EXIT_NOCANDO;
break;
case CONVERT_STATUS_NTFS_RESERVED_NAMES:
DisplayMessage( MSG_CONV_NTFS_RESERVED_NAMES, ERROR_MESSAGE, "%W", &_DisplayDrive );
ExitCode = EXIT_ERROR;
break;
case CONVERT_STATUS_WRITE_PROTECTED:
DisplayMessage( MSG_CONV_WRITE_PROTECTED, ERROR_MESSAGE, "%W", &_DisplayDrive );
ExitCode = EXIT_ERROR;
break;
case CONVERT_STATUS_CANNOT_LOCK_DRIVE:
//
// The drive cannot be locked. We must schedule ChkDsk and AutoConv
// to do the job during the next system boot.
//
DisplayMessage( MSG_CONVERT_ON_REBOOT_PROMPT, NORMAL_MESSAGE, "%W",
&_DisplayDrive );
// Note that ScheduleAutoConv reports its success or
// failure, so no additional messages are required.
//
if ( _Message.IsYesResponse( FALSE ) &&
ScheduleAutoConv() ) {
if (!_NoSecurity && _DosDrive.QueryChCount() == 2 && _DosDrive.QueryChAt(1) == ':') {
DSTRING msg;
DWORD sce_result;
sce_result = SceConfigureConvertedFileSecurity( (PWSTR)_DosDrive.GetWSTR(), 1 );
if ( sce_result != NO_ERROR ) {
if ( SYSTEM::QueryWindowsErrorMessage( sce_result, &msg ) ) {
DisplayMessage( MSG_CONV_SCE_FAILURE_WITH_MESSAGE, ERROR_MESSAGE, "%W", &msg );
} else {
DisplayMessage( MSG_CONV_SCE_SCHEDULE_FAILURE, ERROR_MESSAGE, "%d", sce_result );
}
//
// error in setting up security for files
//
ExitCode = EXIT_ERROR;
} else {
ExitCode = EXIT_SCHEDULED;
}
} else {
//
// no need to worry about security and so return success
//
ExitCode = EXIT_SCHEDULED;
}
if (delete_uninstall_backup && !RemoveUninstallImage()) {
DWORD last_error = GetLastError();
DSTRING errmsg;
if (SYSTEM::QueryWindowsErrorMessage( last_error, &errmsg )) {
DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%W", &errmsg );
} else {
DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%d", last_error );
}
ExitCode = EXIT_ERROR;
}
} else {
//
// Don't want to schedule a convert or scheduling failed
//
ExitCode = EXIT_ERROR;
}
break;
case CONVERT_STATUS_INSUFFICIENT_FREE_SPACE:
case CONVERT_STATUS_DRIVE_IS_DIRTY:
case CONVERT_STATUS_ERROR:
//
// The conversion failed.
//
DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
"%W%W", &_DisplayDrive, &_FsName );
if(ConvertStatus == CONVERT_STATUS_INSUFFICIENT_FREE_SPACE) {
ExitCode = EXIT_NOFREESPACE;
} else {
ExitCode = EXIT_ERROR;
}
break;
default:
//
// Invalid status code
//
DebugPrintTrace(( "CONVERT Error: Convert status code %X invalid!\n",
ConvertStatus ));
DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
"%W%W", &_DisplayDrive, &_FsName );
ExitCode = EXIT_ERROR;
break;
}
return ExitCode;
}
}
PPATH
CONVERT::FindSystemFile(
IN PWSTR FileName
)
/*++
Routine Description:
Makes sure that the given file is in the system directory.
Arguments:
FileName - Supplies the name of the file to look for.
Return Value:
PPATH - Path to the file found
--*/
{
DSTRING Name;
PPATH Path = NULL;
PFSN_FILE File = NULL;
if ( !(Path = SYSTEM::QuerySystemDirectory() ) ) {
DisplayMessage( MSG_CONV_CANNOT_FIND_SYSTEM_DIR, ERROR_MESSAGE );
return FALSE;
}
if ( !Name.Initialize( FileName ) ||
!Path->AppendBase( &Name ) ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
DELETE( Path );
return FALSE;
}
if ( !(File = SYSTEM::QueryFile( Path )) ) {
DisplayMessage( MSG_CONV_CANNOT_FIND_FILE, ERROR_MESSAGE, "%W", Path->GetPathString() );
DELETE( Path );
return FALSE;
}
DELETE( File );
return Path;
}
BOOLEAN
CONVERT::ParseArguments(
OUT PINT ExitCode
)
/*++
Routine Description:
Parses the command line and sets the parameters used by the conversion
utility.
The arguments accepted are:
drive: Drive to convert
/fs:fsname File system to convert to
/v Verbose mode
/? Help
/CVTAREA:filename Filename for convert zone as place holder
for the $MFT, $Logfile, and Volume bitmap
/NoSecurity Allow everyone access
/NoChkdsk Skip chkdsk
/x Force a dismount on the volume if necessary
Arguments:
ExitCode - Supplies pointer to CONVERT exit code
Return Value:
BOOLEAN - TRUE if arguments were parsed correctly and program can
continue.
FALSE if the program should exit. ExitCode contains the
value with which the program should exit. Note that this
does not necessarily means an error (e.g. user requested
help).
--*/
{
UCHAR SequenceNumber;
PATH path;
DSTRING drive_path_string;
PATH_ANALYZE_CODE rst;
DebugPtrAssert( ExitCode );
//
// Parse command line
//
if ( !ParseCommandLine( NULL, TRUE ) ) {
*ExitCode = EXIT_ERROR;
return FALSE;
}
//
// If the user requested help, give it.
//
if ( _Help ) {
DisplayMessage( MSG_CONV_USAGE );
*ExitCode = EXIT_SUCCESS;
return FALSE;
}
#ifdef DBLSPACE_ENABLED
if (_Compress && !_Uncompress) {
//
// We don't allow you to specify /c (compress resulting
// filesystem) unless the source filesystem has dblspace.
//
DisplayMessage(MSG_CONV_SLASH_C_INVALID, ERROR_MESSAGE);
*ExitCode = EXIT_ERROR;
return FALSE;
}
#endif // DBLSPACE_ENABLED
//
// If the command line did not specify a drive, we use the
// current drive.
//
if ( _DosDrive.QueryChCount() == 0 ) {
if ( !SYSTEM::QueryCurrentDosDriveName( &_DosDrive ) ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
}
if ( !path.Initialize( &_DosDrive ) ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
rst = path.AnalyzePath( &_GuidDrive,
&_FullPath,
&drive_path_string );
switch (rst) {
case PATH_OK:
case PATH_COULD_BE_FLOPPY:
if (drive_path_string.QueryChCount() != 0) {
DisplayMessage( MSG_CONV_INVALID_DRIVE_SPEC, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
if (path.IsGuidVolName()) {
if (!_DisplayDrive.Initialize(&_GuidDrive)) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
} else {
if (!_DisplayDrive.Initialize(_FullPath.GetPathString())) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
}
if (_FullPath.GetPathString()->QueryChCount() == 2 &&
_FullPath.GetPathString()->QueryChAt(1) == (WCHAR)':') {
// if there is a drive letter for this drive, use it
// instead of the guid volume name
if (!_DosDrive.Initialize(_FullPath.GetPathString())) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
} else {
if (!_DosDrive.Initialize(&_GuidDrive)) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
}
break;
case PATH_OUT_OF_MEMORY:
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
case PATH_NO_MOUNT_POINT_FOR_VOLUME_NAME_PATH:
DisplayMessage( MSG_CONV_NO_MOUNT_POINT_FOR_GUID_VOLNAME_PATH, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
default:
DisplayMessage( MSG_CONV_INVALID_DRIVE_SPEC, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
if (!_DosDrive.Strupr()) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
//
// Make sure that drive is valid and is not remote.
//
switch ( SYSTEM::QueryDriveType( &_DosDrive ) ) {
case UnknownDrive:
DisplayMessage( MSG_CONV_INVALID_DRIVE_SPEC, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
case CdRomDrive:
DisplayMessage( MSG_CONV_CANT_CDROM, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
case RemoteDrive:
DisplayMessage( MSG_CONV_CANT_NETWORK, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
default:
break;
}
//
// Make sure a target file system was specified. Note that we do not
// validate the file system, we accept any string.
//
if ( _FsName.QueryChCount() == 0 ) {
DisplayMessage( MSG_CONV_NO_FILESYSTEM_SPECIFIED, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
//
// Set other object members.
//
if ( !IFS_SYSTEM::DosDriveNameToNtDriveName( &_DosDrive, &_NtDrive )) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
#ifdef DBLSPACE_ENABLED
//
// If we're to uncompress a dblspace volume, generate the cvf name.
//
if (_Uncompress) {
swprintf(NameBuffer, L"DBLSPACE.%03d", SequenceNumber);
if ( _FullPath.GetPathString()->QueryChCount() == 0 ) {
DisplayMessage( MSG_CONV_NO_MOUNT_POINT_FOR_GUID_VOLNAME_PATH, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
if (!_CvfName.Initialize(NameBuffer)) {
DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
*ExitCode = EXIT_ERROR;
return FALSE;
}
}
#endif // DBLSPACE_ENABLED
*ExitCode = EXIT_SUCCESS;
return TRUE;
}
BOOLEAN
CONVERT::ParseCommandLine (
IN PCWSTRING CommandLine,
IN BOOLEAN Interactive
)
/*++
Routine Description:
Parses the CONVERT (AUTOCONV) command line.
The arguments accepted are:
drive: Drive to convert
/fs:fsname File system to convert to
/v Verbose mode
/uncompress[:sss] Convert from dblspace
/c Compress resulting filesystem
/? Help
/CVTAREA:filename Filename for convert zone as place holder
for the $MFT, $Logfile, and Volume bitmap
Arguments:
CommandLine - Supplies command line to parse
Interactive - Supplies Interactive flag
Return Value:
BOOLEAN - TRUE if arguments were parsed correctly.
--*/
{
ARRAY ArgArray; // Array of arguments
ARRAY LexArray; // Array of lexemes
ARGUMENT_LEXEMIZER ArgLex; // Argument Lexemizer
STRING_ARGUMENT DriveArgument; // Drive argument
STRING_ARGUMENT ProgramNameArgument; // Program name argument
STRING_ARGUMENT FsNameArgument; // Target FS name argument
STRING_ARGUMENT ConvertZoneArgument; // Convert Zone file name
FLAG_ARGUMENT HelpArgument; // Help flag argument
FLAG_ARGUMENT VerboseArgument; // Verbose flag argument
FLAG_ARGUMENT NoSecurityArgument; // Skip setting of security argument
FLAG_ARGUMENT NoChkdskArgument; // Skip chkdsk argument
FLAG_ARGUMENT ForceDismountArgument; // Force a dismount argument
#ifdef DBLSPACE_ENABLED
FLAG_ARGUMENT UncompressArgument; // Uncompress flag argument
FLAG_ARGUMENT CompressArgument; // Compress flag argument
LONG_ARGUMENT UncompressNumberArgument;// Sequence number argument
#endif // DBLSPACE_ENABLED
PWSTRING InvalidArg; // Invalid argument catcher
//
// Initialize all the argument parsing machinery.
//
if( !ArgArray.Initialize( 7, 1 ) ||
!LexArray.Initialize( 7, 1 ) ||
!ArgLex.Initialize( &LexArray ) ||
!DriveArgument.Initialize( "*" ) ||
!HelpArgument.Initialize( "/?" ) ||
!VerboseArgument.Initialize( "/V" ) ||
!NoSecurityArgument.Initialize( "/NoSecurity" ) ||
!NoChkdskArgument.Initialize( "/NoChkdsk" ) ||
!ForceDismountArgument.Initialize( "/X" ) ||
#ifdef DBLSPACE_ENABLED
!CompressArgument.Initialize( "/C" ) ||
#endif // DBLSPACE_ENABLED
!ProgramNameArgument.Initialize( "*" ) ||
#ifdef DBLSPACE_ENABLED
!UncompressArgument.Initialize( "/UNCOMPRESS" ) ||
!UncompressNumberArgument.Initialize( "/UNCOMPRESS:*" ) ||
#endif // DBLSPACE_ENABLED
!FsNameArgument.Initialize( "/FS:*" ) ||
!ConvertZoneArgument.Initialize( "/CVTAREA:*" ) ) {
if ( Interactive ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
}
return FALSE;
}
//
// The conversion utility is case-insensitive
//
ArgLex.SetCaseSensitive( FALSE );
if( !ArgArray.Put( &ProgramNameArgument ) ||
!ArgArray.Put( &HelpArgument ) ||
!ArgArray.Put( &DriveArgument ) ||
!ArgArray.Put( &VerboseArgument ) ||
!ArgArray.Put( &NoSecurityArgument ) ||
!ArgArray.Put( &NoChkdskArgument ) ||
!ArgArray.Put( &ForceDismountArgument ) ||
#ifdef DBLSPACE_ENABLED
!ArgArray.Put( &CompressArgument ) ||
#endif // DBLSPACE_ENABLED
#ifdef DBLSPACE_ENABLED
!ArgArray.Put( &UncompressArgument ) ||
!ArgArray.Put( &UncompressNumberArgument ) ||
#endif // DBLSPACE_ENABLED
!ArgArray.Put( &FsNameArgument ) ||
!ArgArray.Put( &ConvertZoneArgument ) ) {
if ( Interactive ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
}
return FALSE;
}
//
// Lexemize the command line.
//
if ( !ArgLex.PrepareToParse( (PWSTRING)CommandLine ) ) {
if ( Interactive ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
}
return FALSE;
}
//
// Parse the arguments.
//
if( !ArgLex.DoParsing( &ArgArray ) ) {
if ( Interactive ) {
DisplayMessage( MSG_CONV_INVALID_PARAMETER, ERROR_MESSAGE, "%W",
InvalidArg = ArgLex.QueryInvalidArgument() );
DELETE( InvalidArg );
}
return FALSE;
}
_Help = HelpArgument.QueryFlag();
_Verbose = VerboseArgument.QueryFlag();
_NoSecurity = NoSecurityArgument.QueryFlag();
_NoChkdsk = NoChkdskArgument.QueryFlag();
_ForceDismount = ForceDismountArgument.QueryFlag();
_Restart = FALSE; // obsolete argument
#ifdef DBLSPACE_ENABLED
_Compress = CompressArgument.QueryFlag();
#endif // DBLSPACE_ENABLED
if ( DriveArgument.IsValueSet() ) {
if ( !_DosDrive.Initialize( DriveArgument.GetString() ) ) {
return FALSE;
}
} else {
if ( !_DosDrive.Initialize( L"" ) ) {
return FALSE;
}
}
if ( FsNameArgument.IsValueSet() ) {
if ( !_FsName.Initialize( FsNameArgument.GetString() ) ) {
return FALSE;
}
} else {
if ( !_FsName.Initialize( L"" ) ) {
return FALSE;
}
}
if( ConvertZoneArgument.IsValueSet() ) {
if( !_CvtZoneFileName.Initialize( ConvertZoneArgument.GetString() ) ) {
return FALSE;
}
} else {
_CvtZoneFileName.Initialize( L"" );
}
#ifdef DBLSPACE_ENABLED
_SequenceNumber = 0;
_Uncompress = FALSE;
if (UncompressArgument.IsValueSet()) {
_Uncompress = TRUE;
}
if (UncompressNumberArgument.IsValueSet()) {
_SequenceNumber = (UCHAR)UncompressNumberArgument.QueryLong();
_Uncompress = TRUE;
}
#endif // DBLSPACE_ENABLED
return TRUE;
}
BOOLEAN
CONVERT::Schedule (
)
/*++
Routine Description:
Schedules AutoConv
Arguments:
None.
Return Value:
BOOLEAN - TRUE if AutoConv successfully scheduled.
FALSE otherwise
--*/
{
DSTRING CommandLine;
DSTRING Space;
DSTRING FileSystem;
DSTRING ConvertZoneFlag;
DSTRING NoChkdskFlag;
DSTRING VerboseFlag;
DSTRING NoSecurityFlag;
if( !CommandLine.Initialize( (LPWSTR)L"autocheck autoconv " ) ||
!Space.Initialize( (LPWSTR)L" " ) ||
!FileSystem.Initialize( (LPWSTR)L"/FS:" ) ||
!CommandLine.Strcat( &_NtDrive ) ||
!CommandLine.Strcat( &Space ) ||
!CommandLine.Strcat( &FileSystem ) ||
!CommandLine.Strcat( &_FsName ) ) {
return FALSE;
}
if( _CvtZoneFileName.QueryChCount() &&
( !CommandLine.Strcat( &Space ) ||
!ConvertZoneFlag.Initialize( L"/CVTAREA:" ) ||
!CommandLine.Strcat( &ConvertZoneFlag ) ||
!CommandLine.Strcat( &_CvtZoneFileName ) ) ) {
return FALSE;
}
if( _NoChkdsk &&
( !CommandLine.Strcat( &Space ) ||
!NoChkdskFlag.Initialize( L"/NoChkdsk" ) ||
!CommandLine.Strcat( &NoChkdskFlag ) ) ) {
return FALSE;
}
if( _Verbose &&
( !CommandLine.Strcat( &Space ) ||
!VerboseFlag.Initialize( L"/V" ) ||
!CommandLine.Strcat( &VerboseFlag ) ) ) {
return FALSE;
}
if( _NoSecurity &&
( !CommandLine.Strcat( &Space ) ||
!NoSecurityFlag.Initialize( L"/NoSecurity" ) ||
!CommandLine.Strcat( &NoSecurityFlag ) ) ) {
return FALSE;
}
//
// There is no need to add options that are only for convert.exe
// like /x.
//
return( AUTOREG::AddEntry( &CommandLine ) );
}
BOOLEAN
CONVERT::ScheduleAutoConv(
)
/*++
Routine Description:
Schedules AutoConv to be invoked during boot the next time
that the machine reboots.
Arguments:
None
Return Value:
BOOLEAN - TRUE if AutoConv successfully scheduled.
FALSE otherwise
--*/
{
BOOLEAN Ok;
//
// Make sure that Autoconv.exe is in the right place.
//
if ( !(_Autoconv = FindSystemFile( (LPWSTR)AUTOCONV_PROGRAM_NAME )) ) {
DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
return FALSE;
}
// Remove any previously scheduled conversion
//
if ( !RemoveScheduledAutoConv( ) ) {
DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
return FALSE;
}
//
// schedule autoconvert
//
if ( Ok = Schedule( ) ) {
DisplayMessage( MSG_CONV_WILL_CONVERT_ON_REBOOT, NORMAL_MESSAGE, "%W", &_DisplayDrive );
} else {
DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
}
return Ok;
}
BOOLEAN
CONVERT::RemoveScheduledAutoConv(
)
/*++
Routine Description:
Remove possibly old entry of autoconv for the specified volume.
Arguments:
N/A
Return Value:
TRUE if no error.
--*/
{
DSTRING CommandLine;
DSTRING NtDrive;
if (!CommandLine.Initialize( (LPWSTR)L"autocheck autoconv " )) {
return FALSE;
}
if (!AUTOREG::DeleteEntry(&CommandLine, &_NtDrive)) {
return FALSE;
}
if (_DosDrive.Stricmp(&_GuidDrive) == 0)
return FALSE;
DebugAssert(_DosDrive.QueryChCount() == 2);
if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&_GuidDrive, &NtDrive)) {
return FALSE;
}
if (!AUTOREG::DeleteEntry(&CommandLine, &NtDrive)) {
return FALSE;
}
return TRUE;
}
#if defined(FE_SB) && defined(_X86_)
BOOLEAN
CONVERT::ChangeBPB1(
IN PCWSTRING NtDrive
)
/*++
Routine Description:
Change Bpb parameters Logical to Physical
Arguments:
none
Return Value:
BOOLEAN - TRUE Change OK
FALSE otherwise
--*/
{
USHORT work,work2;
ULONG work3;
BIG_INT start_sec;
ULONG sector_len;
PUCHAR Bpb_Buff;
HMEM hmem;
_NtDrive.Initialize(NtDrive);
start_sec=0;
sector_len=1;
LOG_IO_DP_DRIVE dpdrive;
//*** open
if (!dpdrive.Initialize( &_NtDrive, &_Message )) {
return FALSE;
}
if (!hmem.Acquire(2048, dpdrive.QueryAlignmentMask())) {
return(FALSE);
}
Bpb_Buff = (PUCHAR)hmem.GetBuf();
//*** read
if(!dpdrive.Read( start_sec, sector_len, Bpb_Buff)){
return FALSE;
}
work=(USHORT)dpdrive.QueryPhysicalSectorSize(); // get physical sector size
//*** change to physical from logical ***
_BytePerSec = Bpb_Buff[11]+Bpb_Buff[12]*256;
_SecPerClus = Bpb_Buff[13];
_Reserved = Bpb_Buff[14]+Bpb_Buff[15]*256;
_SectorNum = Bpb_Buff[19]+Bpb_Buff[20]*256;
_SecPerFat = Bpb_Buff[22]+Bpb_Buff[23]*256;
_LargeSector = Bpb_Buff[32]+Bpb_Buff[33]*256+Bpb_Buff[34]*256*256+Bpb_Buff[35]*256*256*256;
if (work != _BytePerSec){
Bpb_Buff[11] = (UCHAR)(work%256);
Bpb_Buff[12] = (UCHAR)(work/256);
Bpb_Buff[13]*= (UCHAR)(_BytePerSec/work);
work2 = _Reserved*_BytePerSec/work;
Bpb_Buff[14] = (UCHAR)(work2%256);
Bpb_Buff[15] = (UCHAR)(work2/256);
work2 = _SecPerFat*_BytePerSec/work;
Bpb_Buff[22] = (UCHAR)(work2%256);
Bpb_Buff[23] = (UCHAR)(work2/256);
if (_SectorNum*(_BytePerSec/work)>0xffff){
Bpb_Buff[19] = 0;
Bpb_Buff[20] = 0;
work3 = ((long)_SectorNum*(long)(_BytePerSec/work));
Bpb_Buff[32] = (UCHAR)(work3%256L);
Bpb_Buff[35] = (UCHAR)(work3/(256L*256L*256L));
Bpb_Buff[34] = (UCHAR)(work3/(256L*256L)-(ULONG)Bpb_Buff[31]*256L);
Bpb_Buff[33] = (UCHAR)(work3/256L-(ULONG)Bpb_Buff[31]*256L*256L-(ULONG)Bpb_Buff[30]*256L);
} else {
work2 = _SectorNum*(_BytePerSec/work);
Bpb_Buff[19] = (UCHAR)(work2%256);
Bpb_Buff[20] = (UCHAR)(work2/256);
work3 = _LargeSector;
Bpb_Buff[32] = (UCHAR)(work3%256L);
Bpb_Buff[35] = (UCHAR)(work3/(256L*256L*256L));
Bpb_Buff[34] = (UCHAR)(work3/(256L*256L)-(ULONG)Bpb_Buff[31]*256L);
Bpb_Buff[33] = (UCHAR)(work3/256L-(ULONG)Bpb_Buff[31]*256L*256L-(ULONG)Bpb_Buff[30]*256L);
}
start_sec=0;
sector_len=1;
//*** write
if (!dpdrive.Write(start_sec,sector_len,Bpb_Buff)){
//*** close
return FALSE;
}
} else {
//*** close
return FALSE;
}
return TRUE;
}
#endif