📄 ramdisk.c
字号:
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
ramdisk.c
Abstract:
This is the Ram Disk driver.
Author:
Robert Nelson (RobertN) 10-Mar-1993.
Environment:
Kernel mode only.
Notes:
Revision History:
Added the IOCTL_DISK_GET_PARTITION_INFO query to make it work with NTFS
driver loaded (thanks Robert Vierthaler (RobertVi)).
--*/
//
// Include files.
//
#include <ntddk.h> // various NT definitions
#include <ntdddisk.h> // disk device driver I/O control codes
#include <ntiologc.h>
#include <kchecker.h>
#include <string.h>
#include "ramdisk.h"
#if DBG
ULONG RamDiskDebugLevel = 0;
#endif
NTSTATUS
DriverEntry(
IN OUT PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine is called by the Operating System to initialize the driver.
It fills in the dispatch entry points in the driver object. Then
RamDiskInitializeDisk is called to create the device object and complete
the initialization.
Arguments:
DriverObject - a pointer to the object that represents this device
driver.
RegistryPath - a pointer to our Services key in the registry.
Return Value:
STATUS_SUCCESS if this disk is initialized; an error otherwise.
--*/
{
NTSTATUS ntStatus;
UNICODE_STRING paramPath;
static WCHAR SubKeyString[] = L"\\Parameters";
//
// The registry path parameter points to our key, we will append
// the Parameters key and look for any additional configuration items
// there. We add room for a trailing NUL for those routines which
// require it.
BoundsCheckerInit(DriverObject);
BOUNDS_CHECKER(GENERIC_1, (DriverObject,
"Starting DriverEntry: pObject = DriverObject", 0, 0));
paramPath.MaximumLength = RegistryPath->Length + sizeof(SubKeyString);
paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
if (paramPath.Buffer != NULL)
{
RtlMoveMemory(
paramPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
RtlMoveMemory(
¶mPath.Buffer[RegistryPath->Length / 2], SubKeyString,
sizeof(SubKeyString));
paramPath.Length = paramPath.MaximumLength;
}
else
{
return STATUS_INSUFFICIENT_RESOURCES;
}
#if DBG
{
//
// We use this to query into the registry as to whether we
// should break at driver entry.
//
RTL_QUERY_REGISTRY_TABLE paramTable[3];
ULONG zero = 0;
ULONG debugLevel = 0;
ULONG shouldBreak = 0;
RtlZeroMemory(¶mTable[0], sizeof(paramTable));
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[0].Name = L"BreakOnEntry";
paramTable[0].EntryContext = &shouldBreak;
paramTable[0].DefaultType = REG_DWORD;
paramTable[0].DefaultData = &zero;
paramTable[0].DefaultLength = sizeof(ULONG);
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[1].Name = L"DebugLevel";
paramTable[1].EntryContext = &debugLevel;
paramTable[1].DefaultType = REG_DWORD;
paramTable[1].DefaultData = &zero;
paramTable[1].DefaultLength = sizeof(ULONG);
if (!NT_SUCCESS(RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
paramPath.Buffer, ¶mTable[0], NULL, NULL)))
{
shouldBreak = 0;
debugLevel = 0;
}
RamDiskDebugLevel = debugLevel;
if (shouldBreak)
{
DbgBreakPoint();
}
}
#endif
//
// Initialize the driver object with this driver's entry points.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = RamDiskCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamDiskCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = RamDiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = RamDiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamDiskDeviceControl;
//
// We'll enable unload when the Filesystem drivers support it
//
// DriverObject->DriverUnload = RamDiskUnloadDriver;
ntStatus = RamDiskInitializeDisk(DriverObject, ¶mPath);
//
// We don't need that path anymore.
//
if (paramPath.Buffer)
{
ExFreePool( paramPath.Buffer );
}
return ntStatus;
}
NTSTATUS
RamDiskInitializeDisk(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING ParamPath
)
/*++
Routine Description:
This routine is called at initialization time by DriverEntry().
It creates and initializes a device object for the disk. Memory for the
Ram Disk is allocated from the non-paged Pool. RamDiskFormatFat is called
to create a FAT filesystem in the memory buffer allocated.
Two parameters may be configured using the registry. DiskSize specifies
the desired size (in bytes). If the requested memory is not available in
the nonpaged pool then STATUS_INSUFFICIENT_RESOURCES is returned. The
default value is 0x00100000 (1MB).
DriveLetter is used to indicate the drive letter for the RamDisk. The
string must be a letter, optionally followed by :.
Arguments:
DriverObject - a pointer to the object that represents this device
driver.
ParamPath - a pointer to the Parameters key under our key in the Services
section of the registry.
Return Value:
STATUS_SUCCESS if this disk is initialized; an error otherwise.
--*/
{
STRING ntNameString; // NT Device Name "\Device\RamDisk"
UNICODE_STRING ntUnicodeString; // Unicode version of ntNameString
UNICODE_STRING Win32PathString; // Win32 Name "\DosDevices\Z:"
PDEVICE_OBJECT deviceObject = NULL; // ptr to device object
PRAMDISK_EXTENSION diskExtension = NULL; // ptr to device extension
NTSTATUS ntStatus;
RTL_QUERY_REGISTRY_TABLE paramTable[3];
ULONG defaultDiskSize = DEFAULT_DISK_SIZE;
ULONG diskSize = DEFAULT_DISK_SIZE;
UNICODE_STRING driveLetterString;
WCHAR driveLetterBuffer[sizeof(WCHAR) * 10];
RtlInitUnicodeString( &driveLetterString, NULL );
driveLetterString.MaximumLength = sizeof(WCHAR) * 9;
driveLetterString.Buffer = driveLetterBuffer;
RtlZeroMemory(¶mTable[0], sizeof(paramTable));
RtlZeroMemory(&driveLetterBuffer[0], sizeof(driveLetterBuffer));
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[0].Name = L"DiskSize";
paramTable[0].EntryContext = &diskSize;
paramTable[0].DefaultType = REG_DWORD;
paramTable[0].DefaultData = &defaultDiskSize;
paramTable[0].DefaultLength = sizeof(ULONG);
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[1].Name = L"DriveLetter";
paramTable[1].EntryContext = &driveLetterString;
if (!NT_SUCCESS(RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
ParamPath->Buffer, ¶mTable[0], NULL, NULL)))
{
diskSize = DEFAULT_DISK_SIZE;
}
ASSERT(sizeof(BOOT_SECTOR) == 512);
RtlInitString( &ntNameString, "\\Device\\Ramdisk" );
ntStatus = RtlAnsiStringToUnicodeString(
&ntUnicodeString, &ntNameString, TRUE );
if ( !NT_SUCCESS( ntStatus ) )
{
RamDiskDump(
RAMDERRORS, ("RAMDISK: Couldn't create the unicode device name\n"));
goto RamDiskInitializeDiskExit;
}
ntStatus = IoCreateDevice(
DriverObject, // Our Driver Object
sizeof( RAMDISK_EXTENSION ), // Size of state information
&ntUnicodeString, // Device name "\Device\RamDisk"
FILE_DEVICE_VIRTUAL_DISK, // Device type
0, // Device characteristics
FALSE, // Exclusive device
&deviceObject ); // Returned ptr to Device Object
BOUNDS_CHECKER(GENERIC_1, (deviceObject,
"RamDiskInitializeDisk: Device object created. pObject:DeviceObject ULong1: status",
ntStatus, 0));
if ( !NT_SUCCESS( ntStatus ) )
{
RamDiskDump(
RAMDERRORS, ("RAMDISK: Couldn't create the device object\n"));
goto RamDiskInitializeDiskExit;
}
//
// Initialize device object and extension.
//
deviceObject->Flags |= DO_DIRECT_IO;
deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
diskExtension = (PRAMDISK_EXTENSION)deviceObject->DeviceExtension;
RtlInitUnicodeString( &diskExtension->Win32NameString, NULL );
//
// Allocate and zero the memory disk image.
//
diskExtension->DiskImage = ExAllocatePool( NonPagedPool, diskSize );
if ( diskExtension->DiskImage == NULL )
{
RamDiskDump(
RAMDERRORS, ("RAMDISK: Can't allocate memory for disk image\n") );
goto RamDiskInitializeDiskExit;
}
RtlZeroMemory( diskExtension->DiskImage, diskSize );
//
// Fill in device-specific numbers based on disk size obtained from the
// configuration manager.
//
diskExtension->DeviceObject = deviceObject;
diskExtension->DiskLength = diskSize;
diskExtension->BytesPerSector = 512;
diskExtension->SectorsPerTrack = 32;
diskExtension->TracksPerCylinder = 2;
diskExtension->NumberOfCylinders = diskSize / 512 / 32 / 2;
// Format a FAT filesystem in the memory buffer
RamDiskFormatFat(diskExtension, ParamPath);
//
// Allocate and initialize a Unicode String containing the Win32 name
// for our device.
//
RtlInitUnicodeString( &Win32PathString, WIN32_PATH );
diskExtension->Win32NameString.Buffer = ExAllocatePool(
PagedPool,
sizeof(WIN32_PATH) + 2 * sizeof(WCHAR) );
if (!diskExtension->Win32NameString.Buffer) {
RamDiskDump(
RAMDERRORS,
("RAMDISK: Couldn't allocate buffer for the symbolic link\n")
);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto RamDiskInitializeDiskExit;
}
diskExtension->Win32NameString.MaximumLength = sizeof(WIN32_PATH) + sizeof(WCHAR);
//
// If a drive letter wasn't specified in the registry, use drive Z.
//
if (driveLetterBuffer[0] == L'\0')
{
driveLetterBuffer[0] = L'Z';
}
if (driveLetterBuffer[1] != L':')
{
driveLetterBuffer[1] = L':';
}
driveLetterBuffer[2] = L'\0';
driveLetterString.Length = 2 * sizeof(WCHAR);
RtlAppendUnicodeStringToString(
&diskExtension->Win32NameString, &Win32PathString );
RtlAppendUnicodeStringToString(
&diskExtension->Win32NameString, &driveLetterString );
BOUNDS_CHECKER(GENERIC_2, (NULL,
diskExtension->Win32NameString,
0, 0));
//
// Create a symbolic link between our device name "\Device\RamDisk" and
// the Win32 name (ie "\DosDevices\Z:").
//
ntStatus = IoCreateSymbolicLink(
&diskExtension->Win32NameString, &ntUnicodeString );
RamDiskInitializeDiskExit:
if (ntUnicodeString.Buffer != NULL)
{
RtlFreeUnicodeString( &ntUnicodeString );
}
if ( !NT_SUCCESS( ntStatus ) )
{
//
// Delete everything that this routine has allocated.
//
if ( deviceObject != NULL )
{
if (diskExtension->DiskImage != NULL)
{
ExFreePool( diskExtension->DiskImage );
}
if (diskExtension->Win32NameString.Buffer != NULL)
{
ExFreePool( diskExtension->Win32NameString.Buffer );
}
IoDeleteDevice( deviceObject );
}
}
return ntStatus;
}
VOID
RamDiskFormatFat(
IN PRAMDISK_EXTENSION DiskExtension,
IN PUNICODE_STRING ParamPath
)
/*++
Routine Description:
This routine is called by RamDiskInitializeDisk to format a FAT filesystem
on the memory buffer.
Two parameters may be configured using the registry. RootDirEntries
specifies the desired number of Root Directory entries. If necessary,
the value is rounded up to an integral number of ROOT_DIR_ENTRIES (16).
The default value (DEFAULT_ROOT_DIR_ENTRIES) is 512.
SectorsPerCluster determines the number of sectors in each cluster. The
default value (DEFAULT_SECTORS_PER_CLUSTER) is 2.
Arguments:
DiskExtension - a pointer to the object that represents the device
that I/O is to be done on.
ParamPath - a pointer to the Parameters key of our key under the Serices
section of the registry.
Return Value:
None
--*/
{
RTL_QUERY_REGISTRY_TABLE paramTable[3];
ULONG defaultRootDirEntries = DEFAULT_ROOT_DIR_ENTRIES;
ULONG rootDirEntries = DEFAULT_ROOT_DIR_ENTRIES;
ULONG defaultSectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;
ULONG sectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;
PBOOT_SECTOR bootSector = (PBOOT_SECTOR) DiskExtension->DiskImage;
PUCHAR firstFatSector;
int fatType; // Type of FAT - 12 or 16
USHORT fatEntries; // Number of cluster entries in FAT
USHORT fatSectorCnt; // Number of sectors for FAT
PDIR_ENTRY rootDir; // Pointer to first entry in root dir
//
// Retrieve user tunable parameters
//
BOUNDS_CHECKER(GENERIC_1, (NULL,
"Entering RamDiskFormatFat",
0, 0));
RtlZeroMemory(¶mTable[0], sizeof(paramTable));
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[0].Name = L"RootDirEntries";
paramTable[0].EntryContext = &rootDirEntries;
paramTable[0].DefaultType = REG_DWORD;
paramTable[0].DefaultData = &defaultRootDirEntries;
paramTable[0].DefaultLength = sizeof(ULONG);
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[1].Name = L"SectorsPerCluster";
paramTable[1].EntryContext = §orsPerCluster;
paramTable[1].DefaultType = REG_DWORD;
paramTable[1].DefaultData = &defaultSectorsPerCluster;
paramTable[1].DefaultLength = sizeof(ULONG);
if (!NT_SUCCESS(RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
ParamPath->Buffer, ¶mTable[0], NULL, NULL)))
{
rootDirEntries = DEFAULT_ROOT_DIR_ENTRIES;
sectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;
}
//
// Round Root Directory entries up if necessary
//
if (rootDirEntries & (DIR_ENTRIES_PER_SECTOR - 1))
{
RamDiskDump(RAMDDIAG1, ("RAMDISK: Adjusting RootDirEntries\n"));
rootDirEntries =
(rootDirEntries + ( DIR_ENTRIES_PER_SECTOR - 1 )) &
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -