NT4/private/utils/convert/convert.cxx
2020-09-30 17:12:29 +02:00

1308 lines
32 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 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"
#include "ulibcl.hxx"
#include "error.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 "convert.hxx"
extern "C" {
#include <stdio.h>
}
#include "fatofs.hxx"
ERRSTACK* perrstk;
#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
INT _CRTAPI1
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;
}
BOOLEAN IsRestartFatToOfs( WSTRING const & CurrentFsName,
WSTRING const & NtDriveName )
/*++
Routine Description:
Checks if a FAT->OFS convert is being restarted because of a failure
after the Phase1. So, the currrent file system will be OFS but it is not
fully converted/
Arguments:
CurrentFsName - Name of the current file system
NtDriveName - NtStyle name of the drive to check.
Return Value:
BOOLEAN - TRUE if it is a restart of FAT->OFS. FALSE o/w
History:
Created Srikants August 24, 1995 (WIN95 launch day!!)
Notes:
--*/
{
DSTRING libraryName;
DSTRING entryPoint;
HANDLE fsUtilityHandle;
DSTRING Ofs;
Ofs.Initialize("OFS");
if ( 0 != Ofs.Stricmp(&CurrentFsName) ) {
return FALSE;
}
libraryName.Initialize( FAT_TO_OFS_DLL_NAME );
entryPoint.Initialize( FAT_TO_OFS_RESTART_FUNCTION_NAME );
FAT_OFS_RESTART_FN IsRestartFatOfs;
IsRestartFatOfs = (FAT_OFS_RESTART_FN)SYSTEM::QueryLibraryEntryPoint(
&libraryName, &entryPoint, &fsUtilityHandle );
if ( NULL == IsRestartFatOfs )
{
return FALSE;
}
PWSTR pwszNtDriveName = NtDriveName.QueryWSTR();
BOOLEAN fResult= IsRestartFatOfs( pwszNtDriveName );
DELETE( pwszNtDriveName );
SYSTEM::FreeLibraryHandle( fsUtilityHandle );
return fResult;
}
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
FSTRING NameTableFnName; // Name of Name-Table construction fn
INT ExitCode = EXIT_SUCCESS; // CONVERT exit code
CONVERT_STATUS ConvertStatus; // Conversion status
NTSTATUS Status; // NT API status
HANDLE FsUtilityHandle; // Handle to DLL
HANDLE CuDbfsHandle; // Handle to cudbfs.dll
CONVERT_FN Convert; // Pointer to entry point in DLL
NAMETABLE_FN ConstructNameTable; // Pointer to entry point in DLL
CHECKSPACE_FN CheckSpace; // Pointer to entry point in DLL
BOOLEAN ConvertDblsHost = TRUE;
BOOLEAN Error = FALSE;
BOOLEAN Success;
BOOLEAN Result;
// 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", &_DosDrive );
}
return EXIT_ERROR;
}
// If the source and target file system are the same, there's
// nothing to do. But if we're uncompressing, that's not true.
//
if (_Restart) {
if ( IsRestartFatToOfs( CurrentFsName, _NtDrive ) ) {
CurrentFsName.Initialize("FAT");
}
else {
//XXX.mjb: assume that we're restarting from NTFS to OFS.
CurrentFsName.Initialize("NTFS");
}
}
if( CurrentFsName.Stricmp( &_FsName ) == 0) {
#ifdef DBLSPACE_ENABLED
if (!_Uncompress) {
#endif // DBLSPACE_ENABLED
DisplayMessage( MSG_CONV_ALREADY_CONVERTED, ERROR_MESSAGE, "%W%W",
&_DosDrive, &_FsName );
return EXIT_ERROR;
#ifdef DBLSPACE_ENABLED
}
//
// We're uncompressing, and we don't need to convert the
// host filesystem.
//
ConvertDblsHost = FALSE;
#endif // DBLSPACE_ENABLED
}
// Make sure that the target file system is enabled in the
// registry.
//
if( !IFS_SYSTEM::IsFileSystemEnabled( &_FsName ) ) {
DisplayMessage( MSG_FMT_INSTALL_FILE_SYSTEM, NORMAL_MESSAGE, "%W", &_FsName );
if( _Message.IsYesResponse(TRUE) ) {
if( IFS_SYSTEM::EnableFileSystem( &_FsName ) ) {
DisplayMessage( MSG_FMT_FILE_SYSTEM_INSTALLED );
} else {
DisplayMessage( MSG_FMT_CANT_INSTALL_FILE_SYSTEM, ERROR_MESSAGE );
return EXIT_ERROR;
}
} else {
return EXIT_ERROR;
}
}
#ifdef DBLSPACE_ENABLED
if (_Uncompress) {
//
// Make sure the indicated cvf exists before we try to do
// anything.
//
DSTRING CvfPath;
DSTRING backslash;
if (!backslash.Initialize("\\")) {
DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
return EXIT_ERROR;
}
if (!CvfPath.Initialize(&_DosDrive) ||
!CvfPath.Strcat(&backslash) ||
!CvfPath.Strcat(&_CvfName)) {
DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
return EXIT_ERROR;
}
if (0xffffffff == GetFileAttributes(CvfPath.GetWSTR())) {
if (ERROR_FILE_NOT_FOUND == GetLastError()) {
DisplayMessage(MSG_DBLSPACE_NO_SUCH_FILE, ERROR_MESSAGE,
"%W", &CvfPath);
return EXIT_ERROR;
}
}
}
#endif // DBLSPACE_ENABLED
//
// Display the current file system type. (Standard in all file system utilities)
//
DisplayMessage( MSG_FILE_SYSTEM_TYPE, NORMAL_MESSAGE, "%W", &CurrentFsName );
if (ConvertDblsHost) {
#ifdef DBLSPACE_ENABLED
if (_Uncompress) {
if (!LibraryName.Initialize("CNVDBFS") ||
!EntryPoint.Initialize("CheckFreeSpaceDBFS")) {
return EXIT_ERROR;
}
if (NULL == (CheckSpace = (CHECKSPACE_FN)SYSTEM::
QueryLibraryEntryPoint(&LibraryName, &EntryPoint,
&CuDbfsHandle))) {
return EXIT_ERROR;
}
Success = CheckSpace(&_NtDrive, &_CvfName, &_Message, _Verbose,
_Compress, /* HostIsCompressed */
TRUE /* WillConvertHost */
);
SYSTEM::FreeLibraryHandle( CuDbfsHandle );
if (!Success) {
return EXIT_ERROR;
}
}
#endif // DBLSPACE_ENABLED
//
// Depending on the current file system, form the name of the conversion
// DLL in charge of converting that file system. The name of the
// conversion library is the name of the file system prefixed with "CNV"
// eg FAT->CNVFAT, HPFS->CNVHPFS
//
// We also initialize the name of the conversion entry point in the DLL
// ("Convert")
//
if ( !LibraryName.Initialize( "CNV" ) ||
!LibraryName.Strcat( &CurrentFsName ) ||
!EntryPoint.Initialize( "Convert" ) ||
!EntryPoint.Strcat( &CurrentFsName )
) {
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 );
DisplayMessage( MSG_BLANK_LINE, ERROR_MESSAGE );
return EXIT_ERROR;
}
Result = Convert( &_NtDrive,
&_FsName,
&_Message,
_Verbose,
FALSE, /* Pause */
&ConvertStatus);
SYSTEM::FreeLibraryHandle( FsUtilityHandle );
if( Result ) {
#ifdef DBLSPACE_ENABLED
if (!_Uncompress) {
#endif // DBLSPACE_ENABLED
//
// We're done.
//
DisplayMessage( MSG_CONV_CONVERSION_COMPLETE, NORMAL_MESSAGE );
return EXIT_SUCCESS;
#ifdef DBLSPACE_ENABLED
}
#endif // DBLSPACE_ENABLED
} 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!
//
DebugPrintf( "CONVERT Error: Conversion failed, but status is success!\n" );
DebugAssert( FALSE );
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_CANNOT_LOCK_DRIVE:
//
// The drive cannot be locked. We must schedule ChkDsk and AutoConv
// to do the job during the next system boot.
//
if( _NameTable.QueryChCount() ) {
NameTableFnName.Initialize( L"ConstructNameTable" );
ConstructNameTable = (NAMETABLE_FN)
SYSTEM::QueryLibraryEntryPoint( &LibraryName,
&NameTableFnName,
&FsUtilityHandle );
if( ConstructNameTable == NULL ) {
DisplayMessage( MSG_CONV_NAME_TABLE_NOT_SUPPORTED,
ERROR_MESSAGE,
"%W",
&_FsName );
} else {
ConstructNameTable( &_NtDrive, &_NameTable, &_Message );
}
}
DisplayMessage( MSG_CONVERT_ON_REBOOT_PROMPT, NORMAL_MESSAGE, "%W",
&_DosDrive );
// Note that ScheduleAutoConv reports its success or
// failure, so no additional messages are required.
//
if( _Message.IsYesResponse( FALSE ) &&
ScheduleAutoConv() ) {
#ifdef DBLSPACE_ENABLED
if (_Uncompress) {
DisplayMessage(MSG_DBLCONV_AGAIN, NORMAL_MESSAGE);
}
#endif
ExitCode = EXIT_SCHEDULED;
} else {
ExitCode = EXIT_ERROR;
}
break;
case CONVERT_STATUS_ERROR:
//
// The conversion failed.
//
DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
"%W%W", &_DosDrive, &_FsName );
ExitCode = EXIT_ERROR;
break;
default:
//
// Invalid status code
//
DebugPrintf( "CONVERT Error: Convert status code %X invalid!\n",
ConvertStatus );
DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
"%W%W", &_DosDrive, &_FsName );
ExitCode = EXIT_ERROR;
break;
}
return ExitCode;
}
}
#ifdef DBLSPACE_ENABLED
//
// Uncompress the cvf named by _CvfName.
//
if (!LibraryName.Initialize("CNVDBFS") ||
!EntryPoint.Initialize("CheckFreeSpaceDBFS")) {
return EXIT_ERROR;
}
if (_Compress) {
//
// Indicate that the files we're about to create should
// be compressed.
//
if (!IFS_SYSTEM::EnableVolumeCompression(&_NtDrive)) {
return EXIT_ERROR;
}
}
if (!ConvertDblsHost) {
if (NULL == (CheckSpace = (CHECKSPACE_FN)SYSTEM::QueryLibraryEntryPoint(
&LibraryName, &EntryPoint, &CuDbfsHandle))) {
return EXIT_ERROR;
}
Success = CheckSpace(&_NtDrive, &_CvfName, &_Message, _Verbose,
FALSE, /* HostIsCompressed */
TRUE /* WillConvertHost */
);
SYSTEM::FreeLibraryHandle( CuDbfsHandle );
if (!Success) {
return EXIT_ERROR;
}
}
if (!EntryPoint.Initialize("ConvertDBFS")) {
return EXIT_ERROR;
}
if (NULL == (Convert = (CONVERT_FN)SYSTEM::QueryLibraryEntryPoint(
&LibraryName, &EntryPoint, &CuDbfsHandle))) {
return EXIT_ERROR;
}
DisplayMessage( MSG_DBLSPACE_UNCOMPRESSING, NORMAL_MESSAGE );
if (Convert(&_NtDrive, &_CvfName, &_Message, _Verbose,
&ConvertStatus)) {
ExitCode = EXIT_SUCCESS;
} else {
if (CONVERT_STATUS_INSUFFICIENT_SPACE == ConvertStatus) {
DisplayMessage( MSG_DBLCONV_SPACE_EXHAUSTED, ERROR_MESSAGE );
}
ExitCode = EXIT_ERROR;
}
SYSTEM::FreeLibraryHandle( CuDbfsHandle );
DisplayMessage( MSG_CONV_CONVERSION_COMPLETE, NORMAL_MESSAGE );
#endif // DBLSPACE_ENABLED
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
/uncompress uncompress a cvf after converting
/c Compress the resulting filesystem
/? Help
/NAMETABLE:filename Filename for name translation table.
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).
--*/
{
DSTRING Colon;
UCHAR SequenceNumber;
DebugPtrAssert( ExitCode );
//
// Parse command line
//
if ( !Colon.Initialize( (LPWSTR)L":" ) ||
!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 ( !_DosDrive.Strcat( &Colon ) ||
!_DosDrive.Strupr()) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
*ExitCode = EXIT_ERROR;
return FALSE;
}
} else {
if ( !SYSTEM::QueryCurrentDosDriveName( &_DosDrive ) ) {
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, ERROR_MESSAGE, "%W", &_DosDrive );
*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 (!_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
/NAMETABLE:filename Filename for name translation table
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 NameTableArgument; // Name Table file name
FLAG_ARGUMENT HelpArgument; // Help flag argument
FLAG_ARGUMENT VerboseArgument; // Verbose flag argument
FLAG_ARGUMENT RestartArgument; // Restart (/r) flag 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
DSTRING Colon; // Colon
//
// Initialize all the argument parsing machinery.
//
if( !Colon.Initialize( ":" ) ||
!ArgArray.Initialize( 7, 1 ) ||
!LexArray.Initialize( 7, 1 ) ||
!ArgLex.Initialize( &LexArray ) ||
!DriveArgument.Initialize( "*:" ) ||
!HelpArgument.Initialize( "/?" ) ||
!RestartArgument.Initialize( "/R" ) ||
!VerboseArgument.Initialize( "/V" ) ||
#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:*" ) ||
!NameTableArgument.Initialize( "/NAMETABLE:*" ) ) {
if ( Interactive ) {
DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
}
return FALSE;
}
//
// The conversion utility is case-insensitive
//
ArgLex.SetCaseSensitive( FALSE );
if( !ArgArray.Put( &DriveArgument ) ||
!ArgArray.Put( &HelpArgument ) ||
!ArgArray.Put( &VerboseArgument ) ||
!ArgArray.Put( &RestartArgument ) ||
#ifdef DBLSPACE_ENABLED
!ArgArray.Put( &CompressArgument ) ||
#endif // DBLSPACE_ENABLED
!ArgArray.Put( &ProgramNameArgument ) ||
#ifdef DBLSPACE_ENABLED
!ArgArray.Put( &UncompressArgument ) ||
!ArgArray.Put( &UncompressNumberArgument ) ||
#endif // DBLSPACE_ENABLED
!ArgArray.Put( &FsNameArgument ) ||
!ArgArray.Put( &NameTableArgument ) ) {
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();
_Restart = RestartArgument.QueryFlag();
#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( NameTableArgument.IsValueSet() ) {
if( !_NameTable.Initialize( NameTableArgument.GetString() ) ) {
return FALSE;
}
} else {
_NameTable.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 NameTableFlag;
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( _NameTable.QueryChCount() &&
( !CommandLine.Strcat( &Space ) ||
!NameTableFlag.Initialize( L"/NAMETABLE:" ) ||
!CommandLine.Strcat( &NameTableFlag ) ||
!CommandLine.Strcat( &_NameTable ) ) ) {
return FALSE;
}
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
--*/
{
ARRAY EntryArray;
PITERATOR Iterator = NULL;
BOOLEAN Ok = TRUE;
//
// Make sure that Autochk.exe and Autoconv.exe are in the
// right place.
//
if ( !(_Autochk = FindSystemFile( (LPWSTR)AUTOCHK_PROGRAM_NAME )) ||
!(_Autoconv = FindSystemFile( (LPWSTR)AUTOCONV_PROGRAM_NAME )) ) {
return FALSE;
}
// See if this conversion has already been scheduled:
//
if ( IsAutoConvScheduled( ) ) {
DisplayMessage( MSG_CONV_ALREADY_SCHEDULED, ERROR_MESSAGE, "%W", &_DosDrive );
return TRUE;
}
//
// schedule autoconvert
//
if ( Ok = Schedule( ) ) {
DisplayMessage( MSG_CONV_WILL_CONVERT_ON_REBOOT, NORMAL_MESSAGE, "%W", &_DosDrive );
} else {
DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
}
return Ok;
}
BOOLEAN
CONVERT::IsAutoConvScheduled(
)
/*++
Routine Description:
Determines if an AutoEntry contains a scheduled AUTOCONV for this
drive.
Arguments:
Entry - AutoEntry to be inspected
FileSystem - File system to be converted to,
Return Value:
BOOLEAN
--*/
{
DSTRING CommandLine;
DSTRING Space;
DSTRING FileSystem;
return (BOOLEAN)
( 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 ) &&
AUTOREG::IsEntryPresent( &CommandLine ) );
}