|
|
/*++
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 );
}
|