windows-nt/Source/XPSP1/NT/base/fs/utils/autoconv/autoconv.cxx

943 lines
26 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991-2001 Microsoft Corporation
Module Name:
autoconv.cxx
Abstract:
This is the main program for the autoconv version of convert.
Author:
Ramon J. San Andres (ramonsa) 04-Dec-91
--*/
#include "ulib.hxx"
#include "wstring.hxx"
#include "achkmsg.hxx"
#include "spackmsg.hxx"
#include "ifssys.hxx"
#include "rtmsg.h"
#if defined(FE_SB) && defined(_X86_)
#include "machine.hxx"
#endif
#include "ifsentry.hxx"
#include "convfat.hxx"
#include "fatvol.hxx"
#include "autoreg.hxx"
#include "autoentr.hxx"
#include "arg.hxx"
#include "rcache.hxx"
#if INCLUDE_OFS==1
#include "fatofs.hxx"
//#include "initexcp.hxx"
#endif // INCLUDE_OFS
extern "C" BOOLEAN
InitializeUfat(
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 DriveName
);
BOOLEAN
FileDelete(
IN PCWSTRING DriveName,
IN PCWSTRING FileName
);
#if INCLUDE_OFS==1
BOOLEAN
IsRestartFatToOfs( WSTRING const & DriveName,
WSTRING const & CurrentFsName,
WSTRING const & TargetFileSystem )
{
DSTRING OfsName;
DSTRING FatName;
if ( !OfsName.Initialize( L"OFS" ) )
return FALSE;
if ( CurrentFsName != OfsName || TargetFileSystem != OfsName )
return FALSE;
PWSTR pwszDriveName = DriveName.QueryWSTR();
BOOLEAN fIsRestart = IsFatToOfsRestart( pwszDriveName );
DELETE( pwszDriveName );
return fIsRestart;
}
BOOLEAN
IsFatToOfs( WSTRING const & CurrentFsName, WSTRING const & TargetFsName )
{
DSTRING FatName;
DSTRING OfsName;
if ( !FatName.Initialize( L"FAT" ) )
return FALSE;
if ( !OfsName.Initialize( L"OFS" ) )
return FALSE;
return 0 == CurrentFsName.Stricmp(&FatName) &&
0 == TargetFsName.Stricmp(&OfsName);
}
BOOLEAN
FatToOfs(
IN PCWSTRING NtDriveName,
IN OUT PMESSAGE Message,
IN BOOLEAN Verbose,
IN BOOLEAN fInSetup,
OUT PCONVERT_STATUS Status )
{
PWSTR pwszNtDriveName = NtDriveName->QueryWSTR();
FAT_OFS_CONVERT_STATUS cnvStatus;
BOOLEAN fResult= ConvertFatToOfs(
pwszNtDriveName,
Message,
Verbose,
fInSetup,
&cnvStatus );
DELETE( pwszNtDriveName );
if ( FAT_OFS_CONVERT_SUCCESS == cnvStatus )
{
*Status = CONVERT_STATUS_CONVERTED;
}
else
{
*Status = CONVERT_STATUS_ERROR;
}
return fResult;
}
#else
BOOLEAN
IsRestartFatToOfs( WSTRING const & DriveName, WSTRING const & CurrentFsName,
WSTRING const & TargetFileSystem )
{
return FALSE;
}
BOOLEAN
IsFatToOfs( WSTRING const & CurrentFsName, WSTRING const & TargetFsName )
{
return FALSE;
}
BOOLEAN
FatToOfs(
IN PCWSTRING NtDriveName,
IN OUT PMESSAGE Message,
IN BOOLEAN Verbose,
IN BOOLEAN fInSetup,
OUT PCONVERT_STATUS Status )
{
*Status = CONVERT_STATUS_CONVERSION_NOT_AVAILABLE;
return FALSE;
}
#endif // INCLUDE_OFS
int __cdecl
main(
int argc,
char** argv,
char** envp,
ULONG DebugParameter
)
/*++
Routine Description:
This routine is the main program for AutoConv
Arguments:
argc, argv - Supplies the fully qualified NT path name of the
the drive to check. The syntax of the autoconv
command line is:
AUTOCONV drive-name /FS:target-file-system [/v] [/s] [/o] [/cvtarea:filename]
/v -- verbose output
/s -- run from setup
/o -- pause before the final reboot (oem setup)
/cvtarea:filename
-- convert zone file name
/nochkdsk
-- skips chkdsk and go straight to conversion
Return Value:
0 - Success.
1 - Failure.
--*/
{
#if INCLUDE_OFS==1
InitExceptionSystem();
#endif // INCLUDE_OFS==1
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)
) {
DebugPrintTrace(( "Failed to initialize U* Dlls" ));
return 1;
}
#if defined(FE_SB) && defined(_X86_)
InitializeMachineId();
#endif
PAUTOCHECK_MESSAGE message;
DSTRING DriveName;
DSTRING FileSystemName;
DSTRING CvtZoneFileName;
DSTRING CurrentFsName;
DSTRING FatName;
DSTRING Fat32Name;
DSTRING QualifiedName;
FSTRING Backslash;
BOOLEAN Converted;
BOOLEAN Verbose = FALSE;
BOOLEAN NoChkdsk = FALSE;
BOOLEAN NoSecurity = FALSE;
BOOLEAN Error;
CONVERT_STATUS Status;
int i;
BOOLEAN fInSetup = FALSE;
BOOLEAN Pause = FALSE;
LARGE_INTEGER DelayInterval;
DSTRING StrippedDriveName;
BOOLEAN enabled;
NTSTATUS status;
UNICODE_STRING driverName;
ULONG flags;
status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, TRUE, FALSE, &enabled);
RtlInitUnicodeString( &driverName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Ntfs" );
status = NtLoadDriver( &driverName );
status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, enabled, FALSE, &enabled);
DebugPrintTrace(( "Entering autoconv argc=%ld\n", argc ));
for ( i = 0; i < argc; i++ )
{
DebugPrintTrace((" argv[%d] = %s\n", i, argv[i] ));
}
//
// Parse the arguments. The accepted arguments are:
//
// autoconv NtDrive /fs:<filesystem> [/v]
//
if ( argc < 3 ) {
return 1;
}
//
// First argument is drive
//
if ( !DriveName.Initialize( argv[1] ) ||
!StrippedDriveName.Initialize( argv[1] ) ) {
DebugPrintTrace(( "Failed to intialize DriveName \n" ));
return 1;
}
if (!IFS_SYSTEM::NtDriveNameToDosDriveName(&DriveName, &StrippedDriveName)) {
if (!StrippedDriveName.Initialize(&DriveName)) {
DebugPrint( "Out of memory.\n" );
return 1;
}
}
DebugPrintTrace(("drive name: %ws\n", StrippedDriveName.GetWSTR()));
//
// The rest of the arguments are flags.
//
for ( i = 2; i < argc; i++ ) {
if ( (strlen(argv[i]) >= 5) &&
(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 ( 0 != FileSystemName.QueryChCount() ||
!FileSystemName.Initialize( &(argv[i][4]) ) )
{
DebugPrintTrace(( "Failed to initialize FileSystemName \n" ));
return 1;
}
}
if (0 == _stricmp( argv[i], "/V" ) || 0 == _stricmp( argv[i], "-V" )) {
Verbose = TRUE;
}
if (0 == _stricmp(argv[i], "/S") || 0 == _stricmp(argv[i], "-S")) {
DebugPrintTrace(("Found /s option\n"));
fInSetup = TRUE;
}
if (0 == _stricmp(argv[i], "/O") || 0 == _stricmp(argv[i], "-O")) {
DebugPrintTrace(("Found /o option\n"));
Pause = TRUE;
}
if ( (strlen(argv[i]) >= 10) &&
(argv[i][0] == '/' || argv[i][0] == '-') &&
(argv[i][1] == 'c' || argv[i][1] == 'C') &&
(argv[i][2] == 'v' || argv[i][2] == 'V') &&
(argv[i][3] == 't' || argv[i][3] == 'T') &&
(argv[i][4] == 'a' || argv[i][4] == 'A') &&
(argv[i][5] == 'r' || argv[i][5] == 'R') &&
(argv[i][6] == 'e' || argv[i][6] == 'E') &&
(argv[i][7] == 'a' || argv[i][7] == 'A') &&
(argv[i][8] == ':') ) {
if ( 0 != CvtZoneFileName.QueryChCount() ||
!CvtZoneFileName.Initialize( &(argv[i][9]) ) )
{
DebugPrintTrace(( "Failed to initialize CvtZoneFileName \n" ));
return 1;
}
}
if ( (strlen(argv[i]) >= 9) &&
(argv[i][0] == '/' || argv[i][0] == '-') &&
(argv[i][1] == 'n' || argv[i][1] == 'N') &&
(argv[i][2] == 'o' || argv[i][2] == 'O') &&
(argv[i][3] == 'c' || argv[i][3] == 'C') &&
(argv[i][4] == 'h' || argv[i][4] == 'H') &&
(argv[i][5] == 'k' || argv[i][5] == 'K') &&
(argv[i][6] == 'd' || argv[i][6] == 'D') &&
(argv[i][7] == 's' || argv[i][7] == 'S') &&
(argv[i][8] == 'k' || argv[i][8] == 'K')
) {
NoChkdsk = TRUE;
}
if ( (strlen(argv[i]) >= 11) &&
(argv[i][0] == '/' || argv[i][0] == '-') &&
(argv[i][1] == 'n' || argv[i][1] == 'N') &&
(argv[i][2] == 'o' || argv[i][2] == 'O') &&
(argv[i][3] == 's' || argv[i][3] == 'S') &&
(argv[i][4] == 'e' || argv[i][4] == 'E') &&
(argv[i][5] == 'c' || argv[i][5] == 'C') &&
(argv[i][6] == 'u' || argv[i][6] == 'U') &&
(argv[i][7] == 'r' || argv[i][7] == 'R') &&
(argv[i][8] == 'i' || argv[i][8] == 'I') &&
(argv[i][9] == 't' || argv[i][9] == 'T') &&
(argv[i][10] == 'y' || argv[i][10] == 'Y')
) {
NoSecurity = TRUE;
}
}
if ( 0 == FileSystemName.QueryChCount() )
{
DebugPrintTrace(( "No FileSystem name specified\n" ));
return 1;
}
DebugPrintTrace(("AUTOCONV: TargetFileSystem=%ws\n", FileSystemName.GetWSTR() ));
if (fInSetup) {
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()) {
DebugPrintTrace(( "Failed to intitialize message structure\n" ));
return 1;
}
message->SetLoggingEnabled(TRUE);
if (!FatName.Initialize("FAT") ||
!Fat32Name.Initialize("FAT32")) {
message->Set(MSG_CONV_NO_MEMORY);
message->Display();
SaveMessageLog( message, &DriveName );
return 1;
}
// If this is the System Partition of an ARC machine, don't
// convert it.
//
if( IFS_SYSTEM::IsArcSystemPartition( &DriveName, &Error ) ) {
message->Set( MSG_CONV_ARC_SYSTEM_PARTITION );
message->Display( );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
if (!IFS_SYSTEM::QueryFileSystemName( &DriveName, &CurrentFsName )) {
message->Set( MSG_FS_NOT_DETERMINED );
message->Display( "%W", &StrippedDriveName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
#if defined(FE_SB) && defined(_X86_)
if( IsPC98_N() ) {
DP_DRIVE dpdrive2;
if( !dpdrive2.Initialize(&DriveName, message) ) {
message->Set( MSG_CONV_CANNOT_AUTOCHK );
message->Display( "%W%W", &DriveName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
if( CurrentFsName == FatName ) { //***FAT***
if((dpdrive2.QuerySectorSize() != dpdrive2.QueryPhysicalSectorSize())||
(dpdrive2.QueryPhysicalSectorSize() == 2048)) {
message->Set( MSG_CONV_CONVERSION_FAILED );
message->Display( "%W%W", &DriveName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
} else { //***HPFS/NTFS**
if( dpdrive2.QueryPhysicalSectorSize() == 2048 ) {
message->Set( MSG_CONV_CONVERSION_FAILED );
message->Display( "%W%W", &DriveName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
}
}
#endif
CurrentFsName.Strupr();
FileSystemName.Strupr();
if ( CurrentFsName == FileSystemName ) {
int iReturn = 0;
if ( IsRestartFatToOfs( DriveName, CurrentFsName, FileSystemName ) ) {
if ( !FatToOfs( &DriveName, message, Verbose, fInSetup, &Status ) ) {
iReturn = 1;
}
}
else {
//
// The drive is already in the desired file system, our
// job is done. Delete the name conversion table (if
// specified) and take ourselves out of the registry.
// Do not save the message log--there's nothing interesting
// in it.
//
// If we're doing oem pre-install (Pause is TRUE) we don't
// want to print this "already converted" message.
//
message->SetLoggingEnabled(FALSE);
}
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return iReturn;
}
message->Set( MSG_FILE_SYSTEM_TYPE );
message->Display( "%W", &CurrentFsName );
// Determine whether the target file-system is enabled
// in the registry. If it is not, refuse to convert
// the drive.
//
if( !IFS_SYSTEM::IsFileSystemEnabled( &FileSystemName ) ) {
message->Set( MSG_CONVERT_FILE_SYSTEM_NOT_ENABLED );
message->Display( "%W", &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
// Since autoconvert 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.
//
DelayInterval = RtlConvertLongToLargeInteger( -30000000 );
NtDelayExecution( TRUE, &DelayInterval );
// Open a volume of the appropriate type. The volume is
// opened for exclusive write access.
//
if( CurrentFsName == FatName || CurrentFsName == Fat32Name) {
if (IsConversionAvailable(&FileSystemName)) {
message->Set( MSG_CONV_CONVERSION_NOT_AVAILABLE );
message->Display( "%W%W", &CurrentFsName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
{
DP_DRIVE dpdrive;
if( !dpdrive.Initialize(&DriveName, message) ) {
message->Set( MSG_CONV_CONVERSION_FAILED );
message->Display( "%W%W", &DriveName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
switch (dpdrive.QueryDriveType()) {
case UnknownDrive: // it probably won't get this far
message->Set( MSG_CONV_INVALID_DRIVE_SPEC );
message->Display();
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
case CdRomDrive:
message->Set( MSG_CONV_CANT_CDROM );
message->Display();
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
case RemoteDrive: // it probably won't get this far
message->Set( MSG_CONV_CANT_NETWORK );
message->Display();
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
default:
break;
}
}
if (!NoChkdsk) {
PFAT_VOL FatVolume;
if( !(FatVolume = NEW FAT_VOL) ||
!FatVolume->Initialize( message, &DriveName) ||
!FatVolume->ChkDsk( TotalFix, message, 0, 0 ) ) {
DELETE (FatVolume);
message->Set( MSG_CONV_CANNOT_AUTOCHK );
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
DELETE (FatVolume);
}
message->Set( MSG_BLANK_LINE );
message->Display();
if ( IsFatToOfs( CurrentFsName, FileSystemName ) ) {
message->Set( MSG_CONV_CONVERTING );
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
Converted = FatToOfs( &DriveName,
message,
Verbose,
fInSetup,
&Status );
} else {
PLOG_IO_DP_DRIVE pDrive;
pDrive = NEW LOG_IO_DP_DRIVE;
if (pDrive == NULL) {
message->Set(MSG_CONV_NO_MEMORY);
message->Display();
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
if ( !pDrive->Initialize(&DriveName, message) ) {
message->Set( MSG_CONV_CONVERSION_FAILED );
message->Display( "%W%W", &DriveName, &FileSystemName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
DELETE( pDrive );
return 1;
}
message->Set( MSG_CONV_CONVERTING );
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
//
// there is no need to pass in /NoChkdsk
//
flags = Verbose ? CONVERT_VERBOSE_FLAG : 0;
flags |= Pause ? CONVERT_PAUSE_FLAG : 0;
flags |= NoSecurity ? CONVERT_NOSECURITY_FLAG : 0;
Converted = ConvertFATVolume( pDrive,
&FileSystemName,
&CvtZoneFileName,
message,
flags,
&Status );
DELETE( pDrive );
}
} else {
message->Set( MSG_FS_NOT_SUPPORTED );
message->Display( "%s%W", "AUTOCONV", &CurrentFsName );
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
return 1;
}
if ( Converted ) {
message->Set( MSG_CONV_CONVERSION_COMPLETE );
message->Display();
} else {
//
// The conversion was not successful. Determine what the problem was
// and return the appropriate CONVERT exit code.
//
switch ( Status ) {
case CONVERT_STATUS_CONVERTED:
//
// This is an inconsistent state, Convert should return
// TRUE if the conversion was successful!
//
message->Set( MSG_CONV_CONVERSION_MAYHAVE_FAILED );
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
break;
case CONVERT_STATUS_INVALID_FILESYSTEM:
//
// The conversion DLL does not recognize the target file system.
//
message->Set( MSG_CONV_INVALID_FILESYSTEM );
message->Display( "%W", &FileSystemName );
break;
case CONVERT_STATUS_CONVERSION_NOT_AVAILABLE:
//
// The target file system is valid, but the conversion is not
// available.
//
message->Set( MSG_CONV_CONVERSION_NOT_AVAILABLE );
message->Display( "%W%W", &CurrentFsName, &FileSystemName );
break;
case CONVERT_STATUS_NTFS_RESERVED_NAMES:
message->Set( MSG_CONV_NTFS_RESERVED_NAMES );
message->Display( "%W", &StrippedDriveName );
break;
case CONVERT_STATUS_WRITE_PROTECTED:
message->Set( MSG_CONV_WRITE_PROTECTED );
message->Display( "%W", &StrippedDriveName );
break;
case CONVERT_STATUS_INSUFFICIENT_FREE_SPACE:
case CONVERT_STATUS_CANNOT_LOCK_DRIVE:
case CONVERT_STATUS_DRIVE_IS_DIRTY:
case CONVERT_STATUS_ERROR:
//
// The conversion failed.
//
default:
//
// Invalid status code
//
message->Set( MSG_CONV_CONVERSION_FAILED );
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
DebugPrintTrace(("AUTOCONV: Failed %x\n", Status));
break;
}
}
SaveMessageLog( message, &DriveName );
DeRegister( argc, argv );
#if INCLUDE_OFS==1
CleanupExceptionSystem();
#endif // INCLUDE_OFS==1
return ( Converted ? 0 : 1 );
}
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"autoconv" ) ||
!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 ) );
}
BOOLEAN
SaveMessageLog(
IN OUT PMESSAGE Message,
IN PCWSTRING DriveName
)
/*++
Routine Description:
This function writes the logged messages from the supplied
message object to the file "BOOTEX.LOG" in the root of the
specified drive.
Arguments:
Message -- Supplies the message object.
DriveName -- Supplies the name of the drive.
Return Value:
TRUE upon successful completion.
--*/
{
DSTRING QualifiedName;
FSTRING BootExString;
HMEM Mem;
ULONG Length;
if( !Message->IsLoggingEnabled() ) {
return TRUE;
}
return( QualifiedName.Initialize( DriveName ) &&
BootExString.Initialize( L"\\BOOTEX.LOG" ) &&
QualifiedName.Strcat( &BootExString ) &&
Mem.Initialize() &&
Message->QueryPackedLog( &Mem, &Length ) &&
IFS_SYSTEM::WriteToFile( &QualifiedName,
Mem.GetBuf(),
Length,
TRUE ) );
}
BOOLEAN
FileDelete(
IN PCWSTRING DriveName,
IN PCWSTRING FileName
)
/*++
Routine Description:
This function deletes a file. It is used to clean up the
name translation table.
Arguments:
DriveName -- Supplies the drive on which the file resides.
FileName -- Supplies the file name. Note that the file
should be in the root directory.
Return Value:
TRUE upon successful completion.
--*/
{
DSTRING QualifiedName;
FSTRING Backslash;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
FILE_DISPOSITION_INFORMATION DispositionInfo;
HANDLE FileHandle;
NTSTATUS Status;
if( !Backslash.Initialize( L"\\" ) ||
!QualifiedName.Initialize( DriveName ) ||
!QualifiedName.Strcat( &Backslash ) ||
!QualifiedName.Strcat( FileName ) ) {
return FALSE;
}
UnicodeString.Buffer = (PWSTR)QualifiedName.GetWSTR();
UnicodeString.Length = (USHORT)( QualifiedName.QueryChCount() * sizeof( WCHAR ) );
UnicodeString.MaximumLength = UnicodeString.Length;
InitializeObjectAttributes( &ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
0,
0 );
Status = NtOpenFile( &FileHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_DELETE,
FILE_NON_DIRECTORY_FILE );
if( NT_SUCCESS( Status ) ) {
DispositionInfo.DeleteFile = TRUE;
Status = NtSetInformationFile( FileHandle,
&IoStatusBlock,
&DispositionInfo,
sizeof( DispositionInfo ),
FileDispositionInformation );
}
if( !NT_SUCCESS( Status ) ) {
return FALSE;
}
NtClose( FileHandle );
return TRUE;
}