1308 lines
32 KiB
C++
1308 lines
32 KiB
C++
/*++
|
||
|
||
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 ) );
|
||
|
||
}
|