mirror of https://github.com/tongzx/nt5src
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.
756 lines
20 KiB
756 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1990-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
entry.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains the entry points for UNTFS.DLL. These
|
|
include:
|
|
|
|
Chkdsk
|
|
ChkdskEx
|
|
Format
|
|
FormatEx
|
|
Recover
|
|
Extend
|
|
|
|
Author:
|
|
|
|
Bill McJohn (billmc) 31-05-91
|
|
|
|
Environment:
|
|
|
|
ULIB, User Mode
|
|
|
|
--*/
|
|
|
|
#include <pch.cxx>
|
|
|
|
#define _NTAPI_ULIB_
|
|
#define _UNTFS_MEMBER_
|
|
|
|
#include "ulib.hxx"
|
|
#include "error.hxx"
|
|
#include "untfs.hxx"
|
|
#include "ntfsvol.hxx"
|
|
#include "path.hxx"
|
|
#include "ifssys.hxx"
|
|
#include "rcache.hxx"
|
|
#include "ifsserv.hxx"
|
|
|
|
extern "C" {
|
|
#include "nturtl.h"
|
|
}
|
|
|
|
#include "message.hxx"
|
|
#include "rtmsg.h"
|
|
|
|
|
|
BOOLEAN
|
|
FAR APIENTRY
|
|
Chkdsk(
|
|
IN PCWSTRING NtDriveName,
|
|
IN OUT PMESSAGE Message,
|
|
IN BOOLEAN Fix,
|
|
IN BOOLEAN Verbose,
|
|
IN BOOLEAN OnlyIfDirty,
|
|
IN BOOLEAN Recover,
|
|
IN PPATH PathToCheck,
|
|
IN BOOLEAN Extend,
|
|
IN BOOLEAN ResizeLogFile,
|
|
IN ULONG DesiredLogFileSize,
|
|
OUT PULONG ExitStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check an NTFS volume.
|
|
|
|
Arguments:
|
|
|
|
NtDrivName supplies the name of the drive to check
|
|
Message supplies an outlet for messages
|
|
Fix TRUE if Chkdsk should fix errors
|
|
Verbose TRUE if Chkdsk should list every file it finds
|
|
OnlyIfDirty TRUE if the drive should be checked only if
|
|
it is dirty
|
|
Recover TRUE if the drive is to be completely checked
|
|
for bad sectors.
|
|
PathToCheck supplies a path to files Chkdsk should check
|
|
for contiguity
|
|
Extend TRUE if Chkdsk should extend the volume
|
|
ResizeLogfile TRUE if Chkdsk should resize the logfile.
|
|
DesiredLogfileSize if ResizeLogfile is true, supplies the desired logfile
|
|
size, or 0 if we're to resize the logfile to the
|
|
default size.
|
|
ExitStatus Returns information about whether the chkdsk failed
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful.
|
|
|
|
--*/
|
|
{
|
|
NTFS_VOL NtfsVol;
|
|
BOOLEAN RecoverFree, RecoverAlloc;
|
|
BOOLEAN r;
|
|
DWORD oldErrorMode;
|
|
ULONG flags;
|
|
|
|
if (Extend) {
|
|
|
|
LOG_IO_DP_DRIVE Drive;
|
|
SECRUN Secrun;
|
|
HMEM Mem;
|
|
|
|
PPACKED_BOOT_SECTOR BootSector;
|
|
|
|
if( !Drive.Initialize( NtDriveName, Message ) ||
|
|
!Drive.Lock() ||
|
|
!Mem.Initialize() ||
|
|
!Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
|
|
!Secrun.Read() ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
|
|
|
|
BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart();
|
|
BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
|
|
|
|
if (!Secrun.Write()) {
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
RecoverFree = RecoverAlloc = Recover;
|
|
|
|
if (Extend) {
|
|
|
|
// If we're to extend the volume, we also want to verify the
|
|
// new free space we're adding.
|
|
//
|
|
|
|
RecoverFree = TRUE;
|
|
}
|
|
|
|
// disable popups while we initialize the volume
|
|
oldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
|
|
if (!NtfsVol.Initialize(NtDriveName, Message)) {
|
|
SetErrorMode ( oldErrorMode );
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
|
|
// Re-enable hardware popups
|
|
SetErrorMode ( oldErrorMode );
|
|
|
|
if (Fix || (ResizeLogFile && DesiredLogFileSize != 0)) {
|
|
|
|
if (!NtfsVol.IsWriteable()) {
|
|
Message->DisplayMsg(MSG_CHK_WRITE_PROTECTED);
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NtfsVol.Lock()) {
|
|
|
|
// The client wants to modify the drive, but we can't lock it.
|
|
// Offer to do it on next reboot.
|
|
//
|
|
Message->DisplayMsg(MSG_CHKDSK_ON_REBOOT_PROMPT);
|
|
|
|
if (Message->IsYesResponse( FALSE )) {
|
|
|
|
flags = Recover ? CHKDSK_RECOVER : 0;
|
|
flags |= ResizeLogFile ? CHKDSK_RESIZE_LOGFILE : 0;
|
|
|
|
if (NtfsVol.ForceAutochk( Fix,
|
|
flags,
|
|
DesiredLogFileSize,
|
|
0,
|
|
NtDriveName )) {
|
|
|
|
Message->DisplayMsg(MSG_CHKDSK_SCHEDULED);
|
|
|
|
} else {
|
|
|
|
Message->DisplayMsg(MSG_CHKDSK_CANNOT_SCHEDULE);
|
|
}
|
|
}
|
|
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!Fix && ResizeLogFile) {
|
|
|
|
if (!NtfsVol.GetNtfsSuperArea()->ResizeCleanLogFile( Message,
|
|
TRUE, /* ExplicitResize */
|
|
DesiredLogFileSize )) {
|
|
Message->DisplayMsg(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
flags = (Verbose ? CHKDSK_VERBOSE : 0);
|
|
flags |= (OnlyIfDirty ? CHKDSK_CHECK_IF_DIRTY : 0);
|
|
flags |= (RecoverFree ? CHKDSK_RECOVER_FREE_SPACE : 0);
|
|
flags |= (RecoverAlloc ? CHKDSK_RECOVER_ALLOC_SPACE : 0);
|
|
flags |= (ResizeLogFile ? CHKDSK_RESIZE_LOGFILE : 0);
|
|
|
|
return NtfsVol.ChkDsk( Fix ? TotalFix : CheckOnly,
|
|
Message,
|
|
flags,
|
|
DesiredLogFileSize,
|
|
0,
|
|
ExitStatus );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FAR APIENTRY
|
|
ChkdskEx(
|
|
IN PCWSTRING NtDriveName,
|
|
IN OUT PMESSAGE Message,
|
|
IN BOOLEAN Fix,
|
|
IN PCHKDSKEX_FN_PARAM Param,
|
|
OUT PULONG ExitStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check an NTFS volume.
|
|
|
|
Arguments:
|
|
|
|
NtDrivName supplies the name of the drive to check
|
|
Message supplies an outlet for messages
|
|
Fix TRUE if Chkdsk should fix errors
|
|
Param supplies the chkdsk parameter block
|
|
ExitStatus Returns information about whether the chkdsk failed
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful.
|
|
|
|
--*/
|
|
{
|
|
NTFS_VOL NtfsVol;
|
|
BOOLEAN RecoverFree, RecoverAlloc;
|
|
BOOLEAN r;
|
|
DWORD oldErrorMode;
|
|
USHORT algorithm;
|
|
|
|
if (Param->Major != 1 || (Param->Minor != 0 && Param->Minor != 1)) {
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
|
|
if (Param->Major > 1 || (Param->Major == 1 && Param->Minor == 1)) {
|
|
algorithm = Param->Algorithm;
|
|
} else
|
|
algorithm = 0;
|
|
|
|
if (Param->Flags & CHKDSK_EXTEND) {
|
|
|
|
LOG_IO_DP_DRIVE Drive;
|
|
SECRUN Secrun;
|
|
HMEM Mem;
|
|
|
|
PPACKED_BOOT_SECTOR BootSector;
|
|
|
|
if( !Drive.Initialize( NtDriveName, Message ) ||
|
|
!Drive.Lock() ||
|
|
!Mem.Initialize() ||
|
|
!Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
|
|
!Secrun.Read() ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
|
|
|
|
BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart();
|
|
BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
|
|
|
|
if (!Secrun.Write()) {
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
RecoverFree = RecoverAlloc = (BOOLEAN)(Param->Flags & CHKDSK_RECOVER);
|
|
|
|
if (Param->Flags & CHKDSK_EXTEND) {
|
|
|
|
// If we're to extend the volume, we also want to verify the
|
|
// new free space we're adding.
|
|
//
|
|
|
|
RecoverFree = TRUE;
|
|
}
|
|
|
|
// disable popups while we initialize the volume
|
|
oldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
|
|
if (!NtfsVol.Initialize(NtDriveName, Message)) {
|
|
SetErrorMode ( oldErrorMode );
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
|
|
// Re-enable hardware popups
|
|
SetErrorMode ( oldErrorMode );
|
|
|
|
if (Fix || ((Param->Flags & CHKDSK_RESIZE_LOGFILE) &&
|
|
Param->LogFileSize != 0)) {
|
|
|
|
MSGID msgId = MSG_CHKDSK_ON_REBOOT_PROMPT;
|
|
WCHAR windows_path[MAX_PATH];
|
|
DSTRING sdrive, nt_drive_name;
|
|
BOOLEAN system_drive = FALSE;
|
|
BOOLEAN do_not_dismount = FALSE;
|
|
|
|
if (!NtfsVol.IsWriteable()) {
|
|
Message->DisplayMsg(MSG_CHK_WRITE_PROTECTED);
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetWindowsDirectory(windows_path, sizeof(windows_path)/sizeof(WCHAR)) &&
|
|
wcslen(windows_path) >= 2 &&
|
|
windows_path[1] == TEXT(':') &&
|
|
!(windows_path[2] = 0) &&
|
|
sdrive.Initialize(windows_path) &&
|
|
IFS_SYSTEM::DosDriveNameToNtDriveName(&sdrive, &nt_drive_name)) {
|
|
|
|
system_drive = nt_drive_name.Stricmp(NtDriveName) == 0;
|
|
} else {
|
|
|
|
Message->DisplayMsg(MSG_CHK_UNABLE_TO_TELL_IF_SYSTEM_DRIVE);
|
|
system_drive = FALSE;
|
|
}
|
|
|
|
if (!system_drive) {
|
|
if (!NtfsVol.Lock()) {
|
|
if (!(Param->Flags & CHKDSK_FORCE)) {
|
|
|
|
Message->DisplayMsg(MSG_CHKDSK_FORCE_DISMOUNT_PROMPT);
|
|
|
|
if (Message->IsYesResponse( FALSE )) {
|
|
if (IFS_SYSTEM::DismountVolume(NtDriveName)) {
|
|
Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
|
|
} else
|
|
msgId = MSG_CHKDSK_DISMOUNT_ON_REBOOT_PROMPT;
|
|
} else {
|
|
do_not_dismount = TRUE;
|
|
}
|
|
|
|
} else if (IFS_SYSTEM::DismountVolume(NtDriveName)) {
|
|
Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
|
|
} else
|
|
msgId = MSG_CHKDSK_DISMOUNT_ON_REBOOT_PROMPT;
|
|
|
|
// disable popups while we initialize the volume
|
|
oldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
|
|
if (!NtfsVol.Initialize(NtDriveName, Message)) {
|
|
SetErrorMode ( oldErrorMode );
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
|
|
// Re-enable hardware popups
|
|
SetErrorMode ( oldErrorMode );
|
|
}
|
|
}
|
|
|
|
if (do_not_dismount || !NtfsVol.Lock()) {
|
|
|
|
// The client wants to modify the drive, but we can't lock it.
|
|
// Offer to do it on next reboot.
|
|
//
|
|
Message->DisplayMsg(msgId);
|
|
|
|
if (Message->IsYesResponse( FALSE )) {
|
|
|
|
if (NtfsVol.ForceAutochk( Fix,
|
|
Param->Flags,
|
|
Param->LogFileSize,
|
|
algorithm,
|
|
NtDriveName )) {
|
|
|
|
Message->DisplayMsg(MSG_CHKDSK_SCHEDULED);
|
|
|
|
} else {
|
|
|
|
Message->DisplayMsg(MSG_CHKDSK_CANNOT_SCHEDULE);
|
|
}
|
|
}
|
|
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
if (!Fix && (Param->Flags & CHKDSK_RESIZE_LOGFILE)) {
|
|
|
|
if (!NtfsVol.GetNtfsSuperArea()->ResizeCleanLogFile( Message,
|
|
TRUE, /* ExplicitResize */
|
|
Param->LogFileSize )) {
|
|
Message->DisplayMsg(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
|
|
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
|
|
return FALSE;
|
|
}
|
|
*ExitStatus = CHKDSK_EXIT_SUCCESS;
|
|
return TRUE;
|
|
}
|
|
|
|
return NtfsVol.ChkDsk( Fix ? TotalFix : CheckOnly,
|
|
Message,
|
|
Param->Flags,
|
|
Param->LogFileSize,
|
|
algorithm,
|
|
ExitStatus );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FAR APIENTRY
|
|
Format(
|
|
IN PCWSTRING NtDriveName,
|
|
IN OUT PMESSAGE Message,
|
|
IN BOOLEAN Quick,
|
|
IN BOOLEAN BackwardCompatible,
|
|
IN MEDIA_TYPE MediaType,
|
|
IN PCWSTRING LabelString,
|
|
IN ULONG ClusterSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format an NTFS volume.
|
|
|
|
Arguments:
|
|
|
|
NtDriveName -- supplies the name (in NT API form) of the volume
|
|
Message -- supplies an outlet for messages
|
|
Quick -- supplies a flag to indicate whether to do Quick Format
|
|
BackwardCompatible
|
|
-- supplies a flag to indicate if formatting to previous
|
|
version of file system (e.g. FAT32->FAT16, NTFS 5.0->NTFS 4.0)
|
|
MediaType -- supplies the volume's Media Type
|
|
LabelString -- supplies the volume's label
|
|
ClusterSize -- supplies the cluster size for the volume.
|
|
|
|
--*/
|
|
{
|
|
DP_DRIVE DpDrive;
|
|
NTFS_VOL NtfsVol;
|
|
ULONG SectorsNeeded;
|
|
FORMAT_ERROR_CODE errcode;
|
|
ULONG flags;
|
|
|
|
if (ClusterSize && ClusterSize > 64*1024) {
|
|
Message->DisplayMsg(MSG_FMT_ALLOCATION_SIZE_EXCEEDED);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!DpDrive.Initialize( NtDriveName, Message )) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (DpDrive.IsFloppy()) {
|
|
|
|
Message->DisplayMsg(MSG_NTFS_FORMAT_NO_FLOPPIES);
|
|
return FALSE;
|
|
}
|
|
|
|
SectorsNeeded = NTFS_SA::QuerySectorsInElementaryStructures( &DpDrive );
|
|
|
|
if( SectorsNeeded > DpDrive.QuerySectors() ) {
|
|
|
|
Message->DisplayMsg( MSG_FMT_VOLUME_TOO_SMALL );
|
|
return FALSE;
|
|
}
|
|
|
|
errcode = NtfsVol.Initialize( NtDriveName,
|
|
Message,
|
|
FALSE,
|
|
!Quick,
|
|
MediaType );
|
|
|
|
if (errcode == NoError) {
|
|
flags = (BackwardCompatible ? FORMAT_BACKWARD_COMPATIBLE : 0);
|
|
errcode = NtfsVol.Format( LabelString, Message, flags, ClusterSize );
|
|
}
|
|
|
|
if (errcode == LockError) {
|
|
Message->DisplayMsg(MSG_CANT_LOCK_THE_DRIVE);
|
|
return FALSE;
|
|
} else
|
|
return (errcode == NoError);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FAR APIENTRY
|
|
FormatEx(
|
|
IN PCWSTRING NtDriveName,
|
|
IN OUT PMESSAGE Message,
|
|
IN PFORMATEX_FN_PARAM Param,
|
|
IN MEDIA_TYPE MediaType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format an NTFS volume.
|
|
|
|
Arguments:
|
|
|
|
NtDriveName -- supplies the name (in NT API form) of the volume
|
|
Message -- supplies an outlet for messages
|
|
Param -- supplies the format parameter block
|
|
MediaType -- supplies the volume's Media Type
|
|
|
|
--*/
|
|
{
|
|
DP_DRIVE DpDrive;
|
|
NTFS_VOL NtfsVol;
|
|
ULONG SectorsNeeded;
|
|
FORMAT_ERROR_CODE errcode;
|
|
|
|
if (Param->Major != 1 || Param->Minor != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Param->ClusterSize && Param->ClusterSize > 64*1024) {
|
|
Message->DisplayMsg(MSG_FMT_ALLOCATION_SIZE_EXCEEDED);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!DpDrive.Initialize( NtDriveName, Message )) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (DpDrive.IsFloppy()) {
|
|
|
|
Message->DisplayMsg(MSG_NTFS_FORMAT_NO_FLOPPIES);
|
|
return FALSE;
|
|
}
|
|
|
|
SectorsNeeded = NTFS_SA::QuerySectorsInElementaryStructures( &DpDrive );
|
|
|
|
if( SectorsNeeded > DpDrive.QuerySectors() ) {
|
|
|
|
Message->DisplayMsg( MSG_FMT_VOLUME_TOO_SMALL );
|
|
return FALSE;
|
|
}
|
|
|
|
errcode = NtfsVol.Initialize( NtDriveName,
|
|
Message,
|
|
FALSE,
|
|
(Param->Flags & FORMAT_QUICK) ? 0 : 1,
|
|
MediaType );
|
|
|
|
if (errcode == NoError) {
|
|
errcode = NtfsVol.Format( Param->LabelString,
|
|
Message,
|
|
Param->Flags,
|
|
Param->ClusterSize );
|
|
}
|
|
|
|
if (errcode == LockError) {
|
|
|
|
if (!(Param->Flags & FORMAT_FORCE)) {
|
|
Message->DisplayMsg(MSG_FMT_FORCE_DISMOUNT_PROMPT);
|
|
|
|
if (Message->IsYesResponse(FALSE) &&
|
|
IFS_SYSTEM::DismountVolume(NtDriveName)) {
|
|
Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
|
|
} else {
|
|
Message->DisplayMsg(MSG_CANT_LOCK_THE_DRIVE);
|
|
return FALSE;
|
|
}
|
|
} else if (IFS_SYSTEM::DismountVolume(NtDriveName)) {
|
|
Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
|
|
}
|
|
|
|
errcode = NtfsVol.Initialize( NtDriveName,
|
|
Message,
|
|
FALSE,
|
|
(Param->Flags & FORMAT_QUICK) ? 0 : 1,
|
|
MediaType );
|
|
|
|
if (errcode == NoError) {
|
|
errcode = NtfsVol.Format( Param->LabelString,
|
|
Message,
|
|
Param->Flags,
|
|
Param->ClusterSize );
|
|
}
|
|
|
|
if (errcode == LockError) {
|
|
Message->DisplayMsg(MSG_CANT_LOCK_THE_DRIVE);
|
|
return FALSE;
|
|
} else
|
|
return (errcode == NoError);
|
|
} else
|
|
return (errcode == NoError);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FAR APIENTRY
|
|
Recover(
|
|
IN PPATH RecFilePath,
|
|
IN OUT PMESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Recover a file on an NTFS disk.
|
|
|
|
Arguments:
|
|
|
|
RecFilePath -- supplies the path to the file to recover
|
|
Message -- supplies a channel for messages
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful.
|
|
|
|
--*/
|
|
{
|
|
NTFS_VOL NtfsVol;
|
|
PWSTRING FullPath;
|
|
PWSTRING DosDriveName;
|
|
DSTRING NtDriveName;
|
|
BOOLEAN Result;
|
|
|
|
FullPath = RecFilePath->QueryDirsAndName();
|
|
DosDriveName = RecFilePath->QueryDevice();
|
|
|
|
if ( DosDriveName == NULL ||
|
|
!IFS_SYSTEM::DosDriveNameToNtDriveName(DosDriveName,
|
|
&NtDriveName) ||
|
|
FullPath == NULL ) {
|
|
|
|
DELETE(DosDriveName);
|
|
DELETE(FullPath);
|
|
return FALSE;
|
|
}
|
|
|
|
Message->DisplayMsg(MSG_RECOV_BEGIN,
|
|
"%W", DosDriveName);
|
|
Message->WaitForUserSignal();
|
|
|
|
Result = ( NtfsVol.Initialize( &NtDriveName, Message ) &&
|
|
NtfsVol.Recover( FullPath, Message ) );
|
|
|
|
DELETE(DosDriveName);
|
|
DELETE(FullPath);
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
FAR APIENTRY
|
|
Extend(
|
|
IN PCWSTRING NtDriveName,
|
|
IN OUT PMESSAGE Message,
|
|
IN BOOLEAN Verify
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Extend an NTFS volume without going through the whole chkdsk
|
|
process.
|
|
|
|
Arguments:
|
|
|
|
NtDrivName Supplies the name of the drive to extend.
|
|
Message Supplies an outlet for messages.
|
|
Verify TRUE if we should verify the new space.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful.
|
|
|
|
--*/
|
|
{
|
|
BIG_INT nsecOldSize; // previous size in sectors
|
|
|
|
//
|
|
// First save the old volume size from the boot sector, then query
|
|
// the new size from the device driver and write a new boot sector
|
|
// contining that size. When the Drive object is destroyed, the
|
|
// dasd handle will be closed.
|
|
//
|
|
|
|
{
|
|
LOG_IO_DP_DRIVE Drive;
|
|
SECRUN Secrun;
|
|
HMEM Mem;
|
|
|
|
PPACKED_BOOT_SECTOR BootSector;
|
|
|
|
|
|
if( !Drive.Initialize( NtDriveName, Message ) ||
|
|
!Drive.Lock() ||
|
|
!Mem.Initialize() ||
|
|
!Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
|
|
!Secrun.Read() ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
|
|
|
|
nsecOldSize = BootSector->NumberSectors;
|
|
|
|
// Leave one sector at the end of the volume for the replica boot
|
|
// sector.
|
|
//
|
|
|
|
BootSector->NumberSectors.LowPart = (Drive.QuerySectors() - 1).GetLowPart();
|
|
BootSector->NumberSectors.HighPart = (Drive.QuerySectors() - 1).GetHighPart();
|
|
|
|
if (!Secrun.Write()) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// When the ntfs volume object is initialized, it will get the new
|
|
// size from the boot sector. When it opens a handle on the volume,
|
|
// the filesystem will re-mount and pick up the new size, as well.
|
|
//
|
|
|
|
NTFS_VOL ntfs_vol;
|
|
|
|
if (!ntfs_vol.Initialize(NtDriveName, Message) || !ntfs_vol.Lock()) {
|
|
return FALSE;
|
|
}
|
|
|
|
return ntfs_vol.Extend(Message, Verify, nsecOldSize);
|
|
}
|