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.
778 lines
24 KiB
778 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spdblfmt.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the functions that format an existing compressed
|
|
drive.
|
|
To format a compressed drive we have to unmount the drive, map its
|
|
cvf file in memory, initialize its varios regions, unmap the file
|
|
from memory, and mount the drive.
|
|
|
|
Author:
|
|
|
|
Jaime Sasson (jaimes) 15-October-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "cvf.h"
|
|
|
|
#define MIN_CLUS_BIG 4085 // Minimum clustre for a big fat.
|
|
|
|
//
|
|
// This variable is needed since it contains a buffer that can
|
|
// be used in kernel mode. The buffer is used by NtSetInformationFile,
|
|
// since the Zw API is not exported
|
|
//
|
|
extern PSETUP_COMMUNICATION CommunicationParams;
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
|
|
HANDLE _FileHandle = NULL;
|
|
HANDLE _SectionHandle = NULL;
|
|
PVOID _FileBaseAddress = NULL;
|
|
ULONG _ViewSize = 0;
|
|
ULONG _Maximumcapacity = 0;
|
|
|
|
NTSTATUS
|
|
SpChangeFileAttribute(
|
|
IN PWSTR FileName,
|
|
IN ULONG FileAttributes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change the attributes of a file.
|
|
|
|
Arguments:
|
|
|
|
FileName - Contains the file's full path (NT name).
|
|
|
|
FileAttributes - New desired file attributes.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Returns a NT status code indicating whether or not
|
|
the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeFileName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIO_STATUS_BLOCK KernelModeIoStatusBlock;
|
|
HANDLE Handle;
|
|
PFILE_BASIC_INFORMATION KernelModeBasicInfo;
|
|
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Entering SpChangeFileAttribute() \n" ) );
|
|
|
|
RtlInitUnicodeString( &UnicodeFileName,
|
|
FileName );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = ZwOpenFile( &Handle,
|
|
FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwOpenFile() failed. Status = %x\n",Status ) );
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Set attributes.
|
|
// Note that since we use the NtSetInformationFile API instead of the
|
|
// Zw API (this one is not exported), we need a buffer for IoStatusBlock
|
|
// and for FileBasicInformation, that can be used in kernel mode.
|
|
// We use the the region of memory pointed by CommunicationParams for this
|
|
// purpose.
|
|
//
|
|
KernelModeIoStatusBlock = ( PIO_STATUS_BLOCK )( &(CommunicationParams->Buffer[0]) );
|
|
*KernelModeIoStatusBlock = IoStatusBlock;
|
|
KernelModeBasicInfo = ( PFILE_BASIC_INFORMATION )( &(CommunicationParams->Buffer[128]) );
|
|
RtlZeroMemory( KernelModeBasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
|
|
KernelModeBasicInfo->FileAttributes = ( FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS ) | FILE_ATTRIBUTE_NORMAL;
|
|
|
|
Status = NtSetInformationFile( Handle,
|
|
KernelModeIoStatusBlock,
|
|
KernelModeBasicInfo,
|
|
sizeof( FILE_BASIC_INFORMATION ),
|
|
FileBasicInformation );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: NtSetInformationFile failed, Status = %x\n", Status) );
|
|
}
|
|
ZwClose( Handle );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Exiting SpChangeFileAttribute() \n" ) );
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
SpMapCvfFileInMemory(
|
|
IN PWSTR FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a CVF file in memory.
|
|
|
|
Arguments:
|
|
|
|
FileName - Contains the file's full path (NT name).
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Returns a NT status code indicating whether or not
|
|
the operation succeeded.
|
|
If the file is mapped successfully, this function will
|
|
initialize the global variables _FileHandle, _SectionHandle,
|
|
and _FileBaseAddress.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeFileName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
LARGE_INTEGER SectionOffset;
|
|
|
|
//
|
|
// Open the CVF file for READ and WRITE access
|
|
//
|
|
RtlInitUnicodeString( &UnicodeFileName,
|
|
FileName );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = ZwOpenFile( &_FileHandle,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_NONALERT );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwOpenFile() failed. Status = %x\n",Status ) );
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Map the CVF file in memory
|
|
//
|
|
Status =
|
|
ZwCreateSection( &_SectionHandle,
|
|
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
NULL,
|
|
NULL, // entire file.
|
|
PAGE_READWRITE,
|
|
SEC_COMMIT,
|
|
_FileHandle
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwCreateSection failed, Status = %x\n",Status));
|
|
ZwClose( _FileHandle );
|
|
_FileHandle = NULL;
|
|
return(Status);
|
|
}
|
|
|
|
SectionOffset.LowPart = 0;
|
|
SectionOffset.HighPart = 0;
|
|
_ViewSize = 0;
|
|
Status = ZwMapViewOfSection( _SectionHandle,
|
|
NtCurrentProcess(),
|
|
&_FileBaseAddress,
|
|
0,
|
|
0,
|
|
&SectionOffset,
|
|
&_ViewSize,
|
|
ViewShare,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "File size = %x\n", _ViewSize ) );
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwMapViewOfSection failed, Status = %x\n", Status));
|
|
ZwClose( _SectionHandle );
|
|
ZwClose( _FileHandle );
|
|
_FileBaseAddress = NULL;
|
|
_SectionHandle = NULL;
|
|
_FileHandle = NULL;
|
|
return(Status);
|
|
}
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpUnmapCvfFileFromMemory(
|
|
IN BOOLEAN SaveChanges
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unmap the CFV file previously mapped in memory.
|
|
|
|
Arguments:
|
|
|
|
SaveChanges - Indicates whether or not the caller wants the changes made
|
|
to the file flushed to disk.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Returns a NT status code indicating whether or not
|
|
the operation succeeded.
|
|
This function clears the global variables _FileHandle, _SectionHandle,
|
|
and _FileBaseAddress.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
NTSTATUS PreviousStatus;
|
|
|
|
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Entering SpUnmapCvfFileFromMemory \n" ) );
|
|
PreviousStatus = STATUS_SUCCESS;
|
|
if( SaveChanges ) {
|
|
Status = SpFlushVirtualMemory( _FileBaseAddress,
|
|
_ViewSize );
|
|
//
|
|
// Status = NtFlushVirtualMemory( NtCurrentProcess(),
|
|
// &_FileBaseAddress,
|
|
// &_ViewSize,
|
|
// &IoStatus );
|
|
//
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
PreviousStatus = Status;
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFlushVirtualMemory() failed, Status = %x\n", Status ) );
|
|
}
|
|
}
|
|
Status = ZwUnmapViewOfSection( NtCurrentProcess(), _FileBaseAddress );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwUnmapViewOfSection() failed, Status = %x \n", Status ) );
|
|
}
|
|
ZwClose( _SectionHandle );
|
|
ZwClose( _FileHandle );
|
|
_FileHandle = NULL;
|
|
_SectionHandle = NULL;
|
|
_FileBaseAddress = NULL;
|
|
if( !NT_SUCCESS( PreviousStatus ) ) {
|
|
return( PreviousStatus );
|
|
}
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Exiting SpUnmapCvfFileFromMemory \n" ) );
|
|
return( Status );
|
|
}
|
|
|
|
ULONG
|
|
ComputeMaximumCapacity(
|
|
IN ULONG HostDriveSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function computes the maximum capacity for a compressed
|
|
volume file on a host volume of a given size.
|
|
|
|
Arguments:
|
|
|
|
HostDriveSize -- Supplies the size in bytes of the host drive.
|
|
|
|
Return Value:
|
|
|
|
The appropriate Maximum Capacity.
|
|
|
|
--*/
|
|
{
|
|
ULONG MaxCap;
|
|
|
|
if( HostDriveSize < 20 * 1024L * 1024L ) {
|
|
|
|
MaxCap = 16 * HostDriveSize;
|
|
|
|
} else if ( HostDriveSize < 64 * 1024L * 1024L ) {
|
|
|
|
MaxCap = 8 * HostDriveSize;
|
|
|
|
} else {
|
|
|
|
MaxCap = 4 * HostDriveSize;
|
|
}
|
|
|
|
if( MaxCap < 4 * 1024L * 1024L ) {
|
|
|
|
MaxCap = 4 * 1024L * 1024L;
|
|
|
|
} else if( MaxCap > 512 * 1024L * 1024L ) {
|
|
|
|
MaxCap = 512 * 1024L * 1024L;
|
|
}
|
|
|
|
return MaxCap;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CreateCvfHeader(
|
|
OUT PCVF_HEADER CvfHeader,
|
|
IN ULONG MaximumCapacity
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a Compressed Volume File and fills in
|
|
the first sector with a valid CVF Header. The number of sectors
|
|
in the DOS BPB is set to zero, to indicate that this volume
|
|
file is not initialized.
|
|
|
|
Arguments:
|
|
|
|
CvfHeader -- Receives the created CVF header.
|
|
MaximumCapacity -- Supplies the maximum capacity for the
|
|
double-space volume, in bytes.
|
|
|
|
Return Value:
|
|
|
|
TRUE upon successful completion.
|
|
|
|
--*/
|
|
{
|
|
ULONG Sectors, Clusters, Offset, SectorsInBitmap, SectorsInCvfFatExtension;
|
|
|
|
if( MaximumCapacity % (8L * 1024L * 1024L) ) {
|
|
|
|
// The volume maximum capacity must be a multiple of
|
|
// eight megabytes.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
// Most of the fields in the DOS BPB have fixed values:
|
|
//
|
|
CvfHeader->Jump = 0xEB;
|
|
CvfHeader->JmpOffset = 0x903c;
|
|
|
|
memcpy( CvfHeader->Oem, "MSDSP6.0", 8 );
|
|
|
|
CvfHeader->Bpb.BytesPerSector = DoubleSpaceBytesPerSector;
|
|
CvfHeader->Bpb.SectorsPerCluster = DoubleSpaceSectorsPerCluster;
|
|
// ReservedSectors computed below.
|
|
CvfHeader->Bpb.Fats = DoubleSpaceFats;
|
|
CvfHeader->Bpb.RootEntries = DoubleSpaceRootEntries;
|
|
CvfHeader->Bpb.Sectors = 0;
|
|
CvfHeader->Bpb.Media = DoubleSpaceMediaByte;
|
|
// SectorsPerFat computed below.
|
|
CvfHeader->Bpb.SectorsPerTrack = DoubleSpaceSectorsPerTrack;
|
|
CvfHeader->Bpb.Heads = DoubleSpaceHeads;
|
|
CvfHeader->Bpb.HiddenSectors = DoubleSpaceHiddenSectors;
|
|
CvfHeader->Bpb.LargeSectors = 0;
|
|
|
|
// Compute the number of sectors and clusters for the given
|
|
// maximum capacity:
|
|
//
|
|
Sectors = MaximumCapacity / CvfHeader->Bpb.BytesPerSector;
|
|
Clusters = Sectors / CvfHeader->Bpb.SectorsPerCluster;
|
|
|
|
// Reserve space for a 16-bit FAT that's big enough for the
|
|
// maximum number of clusters.
|
|
//
|
|
CvfHeader->Bpb.SectorsPerFat =
|
|
( USHORT )( (2 * Clusters + CvfHeader->Bpb.BytesPerSector - 1)/
|
|
CvfHeader->Bpb.BytesPerSector );
|
|
|
|
// DOS 6.2 requires that the first sector of the Sector Heap
|
|
// be cluster aligned; since the Root Directory is one cluster,
|
|
// this means that ReservedSectors plus SectorsPerFat must be
|
|
// a multiple of SectorsPerCluster.
|
|
//
|
|
CvfHeader->Bpb.ReservedSectors = DoubleSpaceReservedSectors;
|
|
|
|
Offset = (CvfHeader->Bpb.ReservedSectors + CvfHeader->Bpb.SectorsPerFat) %
|
|
CvfHeader->Bpb.SectorsPerCluster;
|
|
|
|
if( Offset != 0 ) {
|
|
|
|
CvfHeader->Bpb.ReservedSectors +=
|
|
( USHORT )( CvfHeader->Bpb.SectorsPerCluster - Offset );
|
|
}
|
|
|
|
// So much for the DOS BPB. Now for the Double Space
|
|
// BPB extensions. The location of the CVFFatExtension
|
|
// table is preceded by sector zero, the bitmap, and
|
|
// one reserved sector. Note that MaximumCapacity must
|
|
// be a multiple of 8 Meg (8 * 1024 * 1024), which simplifies
|
|
// calculation of SectorsInBitmap, SectorsInCvfFatExtension,
|
|
// and CvfBitmap2KSize.
|
|
//
|
|
SectorsInBitmap = (Sectors / 8) / CvfHeader->Bpb.BytesPerSector;
|
|
SectorsInCvfFatExtension = (Clusters * 4) / CvfHeader->Bpb.BytesPerSector;
|
|
|
|
CvfHeader->CvfFatExtensionsLbnMinus1 = ( UCHAR )( SectorsInBitmap + 1 );
|
|
CvfHeader->LogOfBytesPerSector = DoubleSpaceLog2BytesPerSector;
|
|
CvfHeader->DosBootSectorLbn = ( USHORT )( DoubleSpaceReservedSectors2 +
|
|
CvfHeader->CvfFatExtensionsLbnMinus1 + 1 +
|
|
SectorsInCvfFatExtension );
|
|
CvfHeader->DosRootDirectoryOffset =
|
|
CvfHeader->Bpb.ReservedSectors + CvfHeader->Bpb.SectorsPerFat;
|
|
CvfHeader->CvfHeapOffset =
|
|
CvfHeader->DosRootDirectoryOffset + DoubleSpaceSectorsInRootDir;
|
|
CvfHeader->CvfFatFirstDataEntry =
|
|
CvfHeader->CvfHeapOffset / CvfHeader->Bpb.SectorsPerCluster - 2;
|
|
CvfHeader->CvfBitmap2KSize = ( UCHAR )( SectorsInBitmap / DSSectorsPerBitmapPage );
|
|
CvfHeader->LogOfSectorsPerCluster = DoubleSpaceLog2SectorsPerCluster;
|
|
CvfHeader->Is12BitFat = 1;
|
|
|
|
CvfHeader->MinFile = 32L * DoubleSpaceRootEntries +
|
|
( CvfHeader->DosBootSectorLbn +
|
|
CvfHeader->Bpb.ReservedSectors +
|
|
CvfHeader->Bpb.SectorsPerFat +
|
|
CVF_MIN_HEAP_SECTORS ) *
|
|
CvfHeader->Bpb.BytesPerSector;
|
|
|
|
CvfHeader->CvfMaximumCapacity = (USHORT)(MaximumCapacity/(1024L * 1024L));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
ULONG
|
|
ComputeVirtualSectors(
|
|
IN PCVF_HEADER CvfHeader,
|
|
IN ULONG HostFileSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function computes the appropriate number of virtual
|
|
sectors for the given Compressed Volume File. Note that
|
|
it always uses a ratio of 2.
|
|
|
|
Arguments:
|
|
|
|
CvfHeader -- Supplies the Compressed Volume File Header.
|
|
HostFileSize -- Supplies the size of the host file in bytes.
|
|
|
|
Return Value:
|
|
|
|
The number of virtual sectors appropriate to this Compressed
|
|
Volume File.
|
|
|
|
--*/
|
|
{
|
|
CONST DefaultRatio = 2;
|
|
ULONG SystemOverheadSectors, SectorsInFile,
|
|
VirtualSectors, MaximumSectors, VirtualClusters;
|
|
|
|
if( CvfHeader == NULL ||
|
|
CvfHeader->Bpb.BytesPerSector == 0 ||
|
|
CvfHeader->Bpb.SectorsPerCluster == 0 ) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
SystemOverheadSectors = CvfHeader->DosBootSectorLbn +
|
|
CvfHeader->CvfHeapOffset +
|
|
2;
|
|
|
|
SectorsInFile = HostFileSize / CvfHeader->Bpb.BytesPerSector;
|
|
|
|
if( SectorsInFile < SystemOverheadSectors ) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
VirtualSectors = (SectorsInFile - SystemOverheadSectors) * DefaultRatio +
|
|
CvfHeader->CvfHeapOffset;
|
|
|
|
// VirtualSectors cannot result in more that 0xfff8 clusters on
|
|
// the volume, nor can it be greater than the volume's maximum
|
|
// capacity.
|
|
//
|
|
VirtualSectors = min( VirtualSectors,
|
|
( ULONG )( 0xfff8L * CvfHeader->Bpb.SectorsPerCluster ) );
|
|
|
|
MaximumSectors = (CvfHeader->CvfMaximumCapacity * 1024L * 1024L) /
|
|
CvfHeader->Bpb.BytesPerSector;
|
|
|
|
VirtualSectors = min( VirtualSectors, MaximumSectors );
|
|
|
|
// To avoid problems with DOS, do not create a volume with
|
|
// a number-of-clusters value in the range [0xFEF, 0xFF7].
|
|
//
|
|
VirtualClusters = VirtualSectors / CvfHeader->Bpb.SectorsPerCluster;
|
|
|
|
if( VirtualClusters >= 0xFEF && VirtualClusters <= 0xFF7 ) {
|
|
|
|
VirtualSectors = 0xFEEL * CvfHeader->Bpb.SectorsPerCluster;
|
|
}
|
|
|
|
return VirtualSectors;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpDoubleSpaceFormat(
|
|
IN PDISK_REGION Region
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does a DoubleSpace format on the given partition.
|
|
|
|
The caller should have cleared the screen and displayed
|
|
any message in the upper portion; this routine will
|
|
maintain the gas gauge in the lower portion of the screen.
|
|
|
|
Arguments:
|
|
|
|
Region - supplies the disk region descriptor for the
|
|
partition to be formatted.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
WCHAR CvfFileName[ 512 ];
|
|
NTSTATUS Status;
|
|
PUCHAR BaseAddress;
|
|
ULONG BytesPerSector;
|
|
PHARD_DISK pHardDisk;
|
|
ULONG MaximumCapacity;
|
|
CVF_HEADER CvfHeader;
|
|
ULONG BitFatSize;
|
|
ULONG MdFatSize;
|
|
ULONG Reserved2Size;
|
|
ULONG SuperAreaSize;
|
|
UCHAR SystemId;
|
|
ULONG max_sec_per_sa;
|
|
ULONG FatSize;
|
|
ULONG RootDirectorySize;
|
|
|
|
ASSERT(Region->Filesystem == FilesystemDoubleSpace);
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Entering SpFormatDoubleSpace() \n") );
|
|
|
|
SpNtNameFromRegion(
|
|
Region,
|
|
CvfFileName,
|
|
sizeof(CvfFileName),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
|
|
CvfFileName[ wcslen( CvfFileName ) - (3+1+8+1) ] = ( WCHAR )'\\';
|
|
//
|
|
// Change the CVF file attribute to NORMAL
|
|
//
|
|
Status = SpChangeFileAttribute( CvfFileName, FILE_ATTRIBUTE_NORMAL );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to change attribute of %ls \n", CvfFileName ) );
|
|
return( Status );
|
|
}
|
|
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CvfFileName = %ls \n", CvfFileName ) );
|
|
Status = SpMapCvfFileInMemory( CvfFileName );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to map CVF file in memory \n" ) );
|
|
SpChangeFileAttribute( CvfFileName,
|
|
FILE_ATTRIBUTE_READONLY |
|
|
FILE_ATTRIBUTE_HIDDEN |
|
|
FILE_ATTRIBUTE_SYSTEM );
|
|
return( Status );
|
|
}
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CVF file is mapped in memory \n" ) );
|
|
|
|
//
|
|
// Compute the maximum capacity of the compressed drive.
|
|
// The capacity of the compressed drive is based on the
|
|
// size of the host size.
|
|
//
|
|
// Note that MaximumCapacity is rounded up to the next
|
|
// highest multiple of 8 Meg.
|
|
//
|
|
|
|
pHardDisk = &HardDisks[Region->HostRegion->DiskNumber];
|
|
BytesPerSector = pHardDisk->Geometry.BytesPerSector;
|
|
MaximumCapacity = ComputeMaximumCapacity( Region->HostRegion->SectorCount * BytesPerSector );
|
|
MaximumCapacity = ( ( MaximumCapacity + EIGHT_MEG - 1 ) / EIGHT_MEG ) * EIGHT_MEG;
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: MaximumCapacity = %x\n", MaximumCapacity ));
|
|
//
|
|
// Create the Compressed Volume File Header:
|
|
//
|
|
CreateCvfHeader( &CvfHeader, MaximumCapacity );
|
|
|
|
//
|
|
// Now fill in the value of Virtual Sectors.
|
|
//
|
|
CvfHeader.Bpb.LargeSectors = ComputeVirtualSectors( &CvfHeader, _ViewSize );
|
|
if( CvfHeader.Bpb.LargeSectors >= ( ULONG )( MIN_CLUS_BIG*DoubleSpaceSectorsPerCluster ) ) {
|
|
CvfHeader.Is12BitFat = ( UCHAR )0;
|
|
}
|
|
|
|
BaseAddress = ( PUCHAR )_FileBaseAddress;
|
|
memset( BaseAddress, 0, BytesPerSector );
|
|
|
|
//
|
|
// Write the CVF Header
|
|
//
|
|
CvfPackCvfHeader( ( PPACKED_CVF_HEADER )_FileBaseAddress, &CvfHeader );
|
|
|
|
#if 0
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CalculatedMaximumCapacity = %x, MaximumCapacity = %x \n",
|
|
(USHORT)CvfHeader.CvfMaximumCapacity,
|
|
*((PUSHORT)((ULONG)_FileBaseAddress + 62))
|
|
) );
|
|
#endif
|
|
|
|
//
|
|
// Initialize the BitFAT area
|
|
//
|
|
BaseAddress += BytesPerSector;
|
|
BitFatSize = MaximumCapacity / ( BytesPerSector*8 );
|
|
memset( BaseAddress, 0, BitFatSize );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: BitFAT address = %x, BitFAT size = %x\n", BaseAddress, BitFatSize ));
|
|
|
|
//
|
|
// Initialize the 1st reserved area (Reserved1)
|
|
//
|
|
BaseAddress += BitFatSize;
|
|
memset( BaseAddress, 0, BytesPerSector );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Reserved1 address = %x, Reserved1 size = %x\n", BaseAddress, BytesPerSector ));
|
|
|
|
//
|
|
// Initialize MDFAT
|
|
//
|
|
|
|
BaseAddress += BytesPerSector;
|
|
MdFatSize = 4*( MaximumCapacity/( BytesPerSector*CvfHeader.Bpb.SectorsPerCluster ) );
|
|
memset( BaseAddress, 0, MdFatSize );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: MDFAT address = %x, MDFAT size = %x\n", BaseAddress, MdFatSize ));
|
|
|
|
//
|
|
// Initialize the 2nd reserved area (Reserved2)
|
|
//
|
|
|
|
BaseAddress += MdFatSize;
|
|
Reserved2Size = DoubleSpaceReservedSectors2*BytesPerSector;
|
|
memset( BaseAddress, 0, Reserved2Size );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Reserved2 address = %x, Reserved2 size = %x\n", BaseAddress, Reserved2Size ));
|
|
|
|
//
|
|
// Initialize Boot Sector
|
|
//
|
|
|
|
max_sec_per_sa = 1 +
|
|
2*((2*65536 - 1)/BytesPerSector + 1) +
|
|
((512*32 - 1)/BytesPerSector + 1);
|
|
BaseAddress += Reserved2Size;
|
|
FmtFillFormatBuffer( ( ULONG )CvfHeader.Bpb.LargeSectors,
|
|
( ULONG )( ( USHORT )CvfHeader.Bpb.BytesPerSector ),
|
|
( ULONG )( ( USHORT )CvfHeader.Bpb.SectorsPerTrack ),
|
|
( ULONG )( ( USHORT )CvfHeader.Bpb.Heads ),
|
|
( ULONG )CvfHeader.Bpb.HiddenSectors,
|
|
BaseAddress,
|
|
max_sec_per_sa,
|
|
&SuperAreaSize,
|
|
NULL,
|
|
0,
|
|
&SystemId );
|
|
|
|
|
|
//
|
|
// Initialize the 3rd reserved area (Reserved3)
|
|
//
|
|
|
|
BaseAddress += BytesPerSector;
|
|
memcpy( BaseAddress, FirstDbSignature, DbSignatureLength );
|
|
|
|
//
|
|
// Initialize the FAT area
|
|
//
|
|
BaseAddress += ( ( ULONG )CvfHeader.Bpb.ReservedSectors - 1 )*BytesPerSector;;
|
|
FatSize = ( ULONG )CvfHeader.Bpb.SectorsPerFat * BytesPerSector;
|
|
memset( BaseAddress, 0, FatSize );
|
|
*BaseAddress = 0xF8;
|
|
*( BaseAddress + 1 ) = 0xFF;
|
|
*( BaseAddress + 2 ) = 0xFF;
|
|
if( CvfHeader.Is12BitFat == 0 ) {
|
|
*( BaseAddress + 3 ) = 0xFF;
|
|
}
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: FAT address = %x, Fat size = %x\n", BaseAddress, FatSize ));
|
|
|
|
//
|
|
// Initialize the Root Directory area
|
|
//
|
|
|
|
BaseAddress += FatSize;
|
|
RootDirectorySize = DoubleSpaceSectorsInRootDir*BytesPerSector;
|
|
memset( BaseAddress, 0, RootDirectorySize );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: RootDirectory address = %x, RootDirectory size = %x\n", BaseAddress, RootDirectorySize ));
|
|
|
|
//
|
|
// Initialization of the 4th reserved area (Reserved4) is not necessary
|
|
//
|
|
|
|
//
|
|
// Initialization of the sector heap is not necessary
|
|
//
|
|
|
|
//
|
|
// Initialize the 2nd stamp
|
|
//
|
|
|
|
BaseAddress = ( PUCHAR )(( ULONG )_FileBaseAddress + _ViewSize - BytesPerSector);
|
|
memset( BaseAddress, 0, BytesPerSector );
|
|
memcpy( BaseAddress, SecondDbSignature, DbSignatureLength );
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SecondStamp address = %x, SecondStamp size = %x\n", BaseAddress, BytesPerSector ));
|
|
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: _FileBaseAddress = %lx, _ViewSize = %lx\n", _FileBaseAddress, _ViewSize ) );
|
|
|
|
|
|
SpUnmapCvfFileFromMemory( TRUE );
|
|
|
|
SpChangeFileAttribute( CvfFileName,
|
|
FILE_ATTRIBUTE_READONLY |
|
|
FILE_ATTRIBUTE_HIDDEN |
|
|
FILE_ATTRIBUTE_SYSTEM );
|
|
return( Status );
|
|
|
|
}
|