mirror of https://github.com/lianthony/NT4.0
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.
772 lines
19 KiB
772 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1991 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 "error.hxx"
|
|
#include "ifssys.hxx"
|
|
#include "rtmsg.h"
|
|
#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 _CRTAPI1
|
|
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] [/NAMETABLE:filename]
|
|
|
|
/v -- verbose output
|
|
/s -- run from setup
|
|
/o -- pause before the final reboot (oem setup)
|
|
|
|
|
|
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)
|
|
) {
|
|
DebugPrintf( "Failed to initialize U* Dlls" );
|
|
return 1;
|
|
}
|
|
|
|
|
|
PFAT_VOL FatVolume;
|
|
DP_DRIVE DpDrive;
|
|
PAUTOCHECK_MESSAGE message;
|
|
DSTRING DriveName;
|
|
DSTRING FileSystemName;
|
|
DSTRING CurrentFsName;
|
|
DSTRING FatName;
|
|
DSTRING NameTableFileName;
|
|
DSTRING QualifiedName;
|
|
FSTRING Backslash;
|
|
BOOLEAN Converted;
|
|
BOOLEAN Verbose = FALSE;
|
|
BOOLEAN Error;
|
|
CONVERT_STATUS Status;
|
|
BOOLEAN UseNameTable = FALSE;
|
|
int i;
|
|
BOOLEAN fInSetup = FALSE;
|
|
BOOLEAN Pause = FALSE;
|
|
|
|
LARGE_INTEGER DelayInterval;
|
|
|
|
FSTRING DosDevicesPattern;
|
|
DSTRING StrippedDriveName;
|
|
CHNUM position;
|
|
|
|
DebugPrintf( "Entering autoconv argc=%ld\n", argc );
|
|
for ( i = 0; i < argc; i++ )
|
|
{
|
|
DebugPrintf(" argv[%d] = %s\n", i, argv[i] );
|
|
}
|
|
|
|
if (!(perrstk = NEW ERRSTACK)) {
|
|
DebugPrintf( "Failed to create the error stack\n" );
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// 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] ) ) {
|
|
DebugPrintf( "Failed to intialize DriveName \n" );
|
|
return 1;
|
|
}
|
|
|
|
DosDevicesPattern.Initialize( (LPWSTR)L"\\??\\" );
|
|
position = StrippedDriveName.Strstr( &DosDevicesPattern );
|
|
if (position == 0)
|
|
StrippedDriveName.DeleteChAt(0, DosDevicesPattern.QueryChCount() );
|
|
|
|
DebugPrintf("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]) ) )
|
|
{
|
|
DebugPrintf( "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")) {
|
|
DebugPrintf("Found /s option\n");
|
|
fInSetup = TRUE;
|
|
}
|
|
|
|
if (0 == _stricmp(argv[i], "/O") || 0 == _stricmp(argv[i], "-O")) {
|
|
DebugPrintf("Found /o option\n");
|
|
Pause = TRUE;
|
|
}
|
|
|
|
if( _strnicmp( "/NAMETABLE:", argv[i], strlen("/NAMETABLE:") ) == 0 ||
|
|
_strnicmp( "-NAMETABLE:", argv[i], strlen("-NAMETABLE:") ) == 0 ) {
|
|
|
|
UseNameTable = TRUE;
|
|
if( !NameTableFileName.Initialize( &argv[i][strlen("-NAMETABLE:")] ) ) {
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( 0 == FileSystemName.QueryChCount() )
|
|
{
|
|
DebugPrintf( "No FileSystem name specified\n" );
|
|
return 1;
|
|
}
|
|
|
|
DebugPrintf("AUTOCONV: TargetFileSystem=%ws\n", FileSystemName.GetWSTR() );
|
|
|
|
if (fInSetup) {
|
|
message = NEW SP_AUTOCHECK_MESSAGE;
|
|
DebugPrintf("Using setup output\n");
|
|
} else {
|
|
DebugPrintf("Not using setup output\n");
|
|
message = NEW AUTOCHECK_MESSAGE;
|
|
}
|
|
|
|
if (NULL == message || !message->Initialize()) {
|
|
DebugPrintf( "Failed to intitialize message structure\n" );
|
|
return 1;
|
|
}
|
|
|
|
if (!FatName.Initialize("FAT")) {
|
|
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;
|
|
}
|
|
|
|
message->Set( MSG_FILE_SYSTEM_TYPE );
|
|
message->Display( "%W", &CurrentFsName );
|
|
|
|
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.
|
|
//
|
|
|
|
if (!Pause) {
|
|
|
|
message->Set( MSG_CONV_ALREADY_CONVERTED );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
}
|
|
|
|
if( UseNameTable ) {
|
|
|
|
FileDelete( &DriveName, &NameTableFileName );
|
|
// BUGBUG billmc -- delete the name table file.
|
|
//
|
|
}
|
|
}
|
|
|
|
SaveMessageLog( message, &DriveName );
|
|
DeRegister( argc, argv );
|
|
return iReturn;
|
|
}
|
|
|
|
// 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 ) {
|
|
|
|
if( !(FatVolume = NEW FAT_VOL) ||
|
|
!FatVolume->Initialize( &DriveName, message, TRUE ) ||
|
|
!FatVolume->ChkDsk( TotalFix, message, FALSE, FALSE ) ) {
|
|
|
|
message->Set( MSG_CONV_CANNOT_AUTOCHK );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
|
|
SaveMessageLog( message, &DriveName );
|
|
DeRegister( argc, argv );
|
|
return 1;
|
|
}
|
|
|
|
if ( IsFatToOfs( CurrentFsName, FileSystemName ) ) {
|
|
|
|
DELETE (FatVolume);
|
|
|
|
message->Set( MSG_CONV_CONVERTING );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
|
|
Converted = FatToOfs( &DriveName,
|
|
message,
|
|
Verbose,
|
|
fInSetup,
|
|
&Status );
|
|
}
|
|
else {
|
|
|
|
message->Set( MSG_CONV_CONVERTING );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
|
|
Converted = ConvertFATVolume( FatVolume,
|
|
&FileSystemName,
|
|
message,
|
|
Verbose,
|
|
Pause,
|
|
&Status );
|
|
|
|
DELETE( FatVolume );
|
|
}
|
|
|
|
} 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!
|
|
//
|
|
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", &FileSystemName );
|
|
break;
|
|
|
|
case CONVERT_STATUS_CANNOT_LOCK_DRIVE:
|
|
|
|
message->Set( MSG_CONV_CONVERSION_FAILED );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
break;
|
|
|
|
case CONVERT_STATUS_ERROR:
|
|
//
|
|
// The conversion failed.
|
|
//
|
|
message->Set( MSG_CONV_CONVERSION_FAILED );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Invalid status code
|
|
//
|
|
message->Set( MSG_CONV_CONVERSION_FAILED );
|
|
message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
|
|
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;
|
|
}
|