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.
1766 lines
51 KiB
1766 lines
51 KiB
#define UNICODE 1
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntdddisk.h>
|
|
#include <ntddscsi.h>
|
|
#include <initguid.h>
|
|
#include <mountmgr.h>
|
|
#include <ntddramd.h>
|
|
|
|
#define _NTSCSI_USER_MODE_
|
|
#include <scsi.h>
|
|
|
|
#define PAGE_SIZE 4096
|
|
#define ROUND_TO_PAGE_SIZE(_x) (((_x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
|
|
|
#include <windows.h>
|
|
#include <devioctl.h>
|
|
#include <setupapi.h>
|
|
#include <cfgmgr32.h>
|
|
|
|
#include <rpc.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <sdistructs.h>
|
|
|
|
#define SECTOR_SIZE 0x200
|
|
#define SECTORS_PER_TRACK 0x80
|
|
#define TRACKS_PER_CYLINDER 0x10
|
|
#define CYLINDER_SIZE (SECTOR_SIZE * SECTORS_PER_TRACK * TRACKS_PER_CYLINDER)
|
|
|
|
#define arrayof(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
typedef struct _RAMCTRL_HEADER {
|
|
char Signature[8]; // "ramctrl"
|
|
GUID DiskGuid;
|
|
ULONG DiskOffset;
|
|
ULONG DiskType;
|
|
RAMDISK_CREATE_OPTIONS Options;
|
|
} RAMCTRL_HEADER, *PRAMCTRL_HEADER;
|
|
|
|
typedef union _RAMDISK_HEADER {
|
|
|
|
RAMCTRL_HEADER Ramctrl;
|
|
SDI_HEADER Sdi;
|
|
|
|
} RAMDISK_HEADER, *PRAMDISK_HEADER;
|
|
|
|
VOID
|
|
PrintError(
|
|
ULONG ErrorCode
|
|
)
|
|
{
|
|
WCHAR errorBuffer[512];
|
|
ULONG count;
|
|
|
|
count = FormatMessage(
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
ErrorCode,
|
|
0,
|
|
errorBuffer,
|
|
arrayof(errorBuffer),
|
|
NULL
|
|
);
|
|
|
|
if ( count != 0 ) {
|
|
printf( "%ws\n", errorBuffer );
|
|
} else {
|
|
printf( "Format message failed. Error: %d\n", GetLastError() );
|
|
}
|
|
|
|
return;
|
|
|
|
} // PrintError
|
|
|
|
VOID
|
|
ListDisks (
|
|
HANDLE ControlHandle
|
|
)
|
|
{
|
|
BOOL ok;
|
|
WCHAR actualDeviceName[MAX_PATH];
|
|
WCHAR foundDeviceName[MAX_PATH];
|
|
WCHAR dosDeviceName[MAX_PATH];
|
|
WCHAR driveLetterString[3] = L"A:";
|
|
BOOL foundRamDisk;
|
|
BOOL foundDriveLetter;
|
|
LPCGUID interfaceGuid;
|
|
GUID foundGuid;
|
|
PWSTR guidPtr;
|
|
UNICODE_STRING guidString;
|
|
GUID diskGuid;
|
|
HDEVINFO devinfo;
|
|
SP_DEVICE_INTERFACE_DATA interfaceData;
|
|
BYTE detailBuffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
|
|
SP_DEVINFO_DATA devinfoData;
|
|
DWORD i;
|
|
RAMDISK_QUERY_INPUT queryInput;
|
|
BYTE queryOutputBuffer[sizeof(RAMDISK_QUERY_OUTPUT) + (MAX_PATH * sizeof(WCHAR))];
|
|
PRAMDISK_QUERY_OUTPUT queryOutput;
|
|
DWORD returnedLength;
|
|
|
|
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)detailBuffer;
|
|
queryOutput = (PRAMDISK_QUERY_OUTPUT)queryOutputBuffer;
|
|
|
|
interfaceGuid = &RamdiskDiskInterface;
|
|
|
|
foundRamDisk = FALSE;
|
|
|
|
do {
|
|
|
|
devinfo = SetupDiGetClassDevs(
|
|
interfaceGuid,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
|
|
);
|
|
|
|
if ( devinfo == NULL ) {
|
|
|
|
printf( "ListDisks: SetupDiGetClassDevs failed: %d\n", GetLastError() );
|
|
return;
|
|
}
|
|
|
|
ZeroMemory( &interfaceData, sizeof(interfaceData) );
|
|
interfaceData.cbSize = sizeof(interfaceData);
|
|
|
|
//
|
|
// Enumerate the device interfaces of the class.
|
|
//
|
|
|
|
for (i = 0;
|
|
SetupDiEnumDeviceInterfaces( devinfo, NULL, interfaceGuid, i, &interfaceData );
|
|
i++ ) {
|
|
|
|
interfaceDetailData->cbSize = sizeof(*interfaceDetailData);
|
|
devinfoData.cbSize = sizeof(devinfoData);
|
|
|
|
if ( !SetupDiGetDeviceInterfaceDetail(
|
|
devinfo,
|
|
&interfaceData,
|
|
interfaceDetailData,
|
|
sizeof(detailBuffer),
|
|
NULL,
|
|
&devinfoData
|
|
) ) {
|
|
|
|
//printf( "ListDisks: SetupDiGetDeviceInterfaceDetail failed for item %d. (%d)\n", i, GetLastError() );
|
|
|
|
wcscpy( interfaceDetailData->DevicePath, L"<couldn't retrieve name>" );
|
|
}
|
|
|
|
//printf( "Enumerated device %ws\n", interfaceDetailData->DevicePath );
|
|
|
|
if ( !SetupDiGetDeviceRegistryProperty(
|
|
devinfo,
|
|
&devinfoData,
|
|
SPDRP_BUSTYPEGUID,
|
|
NULL,
|
|
(PBYTE)&foundGuid,
|
|
sizeof(foundGuid),
|
|
NULL
|
|
) ) {
|
|
|
|
DWORD error = GetLastError();
|
|
//printf( "ListDisks: SetupDiGetDeviceRegistryProperty (bus GUID) failed for %ws: %d\n", interfaceDetailData->DevicePath, error );
|
|
continue;
|
|
}
|
|
|
|
if ( memcmp( &foundGuid, &GUID_BUS_TYPE_RAMDISK, sizeof(GUID) ) != 0 ) {
|
|
|
|
//printf( "ListDisks: skipping non-ramdisk device %ws\n", interfaceDetailData->DevicePath );
|
|
continue;
|
|
}
|
|
|
|
if ( !SetupDiGetDeviceRegistryProperty(
|
|
devinfo,
|
|
&devinfoData,
|
|
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
|
|
NULL,
|
|
(PBYTE)actualDeviceName,
|
|
sizeof(actualDeviceName),
|
|
NULL
|
|
) ) {
|
|
|
|
DWORD error = GetLastError();
|
|
printf( "ListDisks: SetupDiGetDeviceRegistryProperty (name) failed for %ws: %d\n", interfaceDetailData->DevicePath, error );
|
|
continue;
|
|
}
|
|
|
|
foundRamDisk = TRUE;
|
|
|
|
printf( "\n%ws\n", interfaceDetailData->DevicePath );
|
|
printf( " Device name: %ws\n", actualDeviceName );
|
|
|
|
guidPtr = wcschr( actualDeviceName, L'{' );
|
|
swprintf( dosDeviceName, L"Ramdisk%ws", guidPtr );
|
|
|
|
if ( QueryDosDeviceW(dosDeviceName, foundDeviceName, arrayof(foundDeviceName)) ) {
|
|
|
|
printf( " DosDevice name %ws is assigned to this device\n", dosDeviceName );
|
|
|
|
} else {
|
|
|
|
printf( " No DosDevice name was assigned to this device\n" );
|
|
}
|
|
|
|
foundDriveLetter = FALSE;
|
|
|
|
for ( driveLetterString[0] = 'A';
|
|
driveLetterString[0] <= 'Z';
|
|
driveLetterString[0]++ ) {
|
|
|
|
if ( QueryDosDeviceW(driveLetterString, foundDeviceName, arrayof(foundDeviceName)) &&
|
|
(_wcsicmp(actualDeviceName, foundDeviceName) == 0) ) {
|
|
|
|
printf( " Drive letter %ws is assigned to this device\n", driveLetterString );
|
|
foundDriveLetter = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !foundDriveLetter ) {
|
|
printf( " No letter was assigned to this device\n" );
|
|
}
|
|
|
|
guidString.Buffer = guidPtr;
|
|
guidString.Length = (USHORT)(wcslen(guidPtr) * sizeof(WCHAR));
|
|
guidString.MaximumLength = guidString.Length;
|
|
|
|
RtlGUIDFromString( &guidString, &diskGuid );
|
|
|
|
queryInput.Version = sizeof(RAMDISK_QUERY_INPUT);
|
|
queryInput.DiskGuid = diskGuid;
|
|
|
|
ok = DeviceIoControl(
|
|
ControlHandle,
|
|
FSCTL_QUERY_RAM_DISK,
|
|
&queryInput,
|
|
sizeof(queryInput),
|
|
queryOutput,
|
|
sizeof(queryOutputBuffer),
|
|
&returnedLength,
|
|
FALSE
|
|
);
|
|
|
|
if ( !ok ) {
|
|
|
|
DWORD errorCode = GetLastError();
|
|
printf( "Error querying RAM disk: %d\n", errorCode );
|
|
PrintError( errorCode );
|
|
|
|
} else {
|
|
|
|
printf( " RAM disk information:\n" );
|
|
if ( queryOutput->DiskType == RAMDISK_TYPE_BOOT_DISK ) {
|
|
printf( " Type: boot disk\n" );
|
|
printf( " Base page: 0x%x\n", queryOutput->BasePage );
|
|
} else {
|
|
printf( " Type: %s\n",
|
|
queryOutput->DiskType == RAMDISK_TYPE_FILE_BACKED_VOLUME ? "volume" : "disk" );
|
|
printf( " File: %ws\n", queryOutput->FileName );
|
|
}
|
|
printf( " Length: 0x%I64x\n", queryOutput->DiskLength );
|
|
printf( " Offset: 0x%x\n", queryOutput->DiskOffset );
|
|
if ( queryOutput->DiskType != RAMDISK_TYPE_BOOT_DISK ) {
|
|
printf( " View count: 0x%x\n", queryOutput->ViewCount );
|
|
printf( " View length: 0x%x\n", queryOutput->ViewLength );
|
|
}
|
|
printf( " Options: " );
|
|
printf( "%s; ", queryOutput->Options.Fixed ? "fixed" : "removable" );
|
|
printf( "%s; ", queryOutput->Options.Readonly ? "readonly" : "writeable" );
|
|
printf( "%s; ", queryOutput->Options.NoDriveLetter ? "no drive letter" : "drive letter" );
|
|
printf( "%s; ", queryOutput->Options.Hidden ? "hidden" : "visible" );
|
|
printf( "%s\n", queryOutput->Options.NoDosDevice ? "no DosDevice" : "DosDevice" );
|
|
}
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList( devinfo );
|
|
|
|
if ( interfaceGuid == &RamdiskDiskInterface ) {
|
|
interfaceGuid = &MOUNTDEV_MOUNTED_DEVICE_GUID;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !foundRamDisk ) {
|
|
printf( "No RAM disks found\n" );
|
|
}
|
|
|
|
return;
|
|
|
|
} // ListDisks
|
|
|
|
VOID
|
|
FindDisk (
|
|
ULONG DiskType,
|
|
PUNICODE_STRING DiskGuidString,
|
|
BOOL WaitForDeletion
|
|
)
|
|
{
|
|
WCHAR actualDeviceName[MAX_PATH];
|
|
WCHAR foundDeviceName[MAX_PATH];
|
|
WCHAR dosDeviceName[MAX_PATH];
|
|
WCHAR driveLetterString[3] = L"A:";
|
|
BOOL found;
|
|
LPCGUID interfaceGuid;
|
|
HDEVINFO devinfo;
|
|
SP_DEVICE_INTERFACE_DATA interfaceData;
|
|
BYTE detailBuffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
|
|
SP_DEVINFO_DATA devinfoData;
|
|
DWORD i;
|
|
|
|
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)detailBuffer;
|
|
|
|
swprintf( actualDeviceName, L"\\Device\\Ramdisk%wZ", DiskGuidString );
|
|
|
|
printf( "Waiting for device %ws to be %s...",
|
|
actualDeviceName,
|
|
WaitForDeletion ? "deleted" : "ready" );
|
|
|
|
if ( DiskType == RAMDISK_TYPE_FILE_BACKED_DISK ) {
|
|
interfaceGuid = &RamdiskDiskInterface;
|
|
} else {
|
|
interfaceGuid = &MOUNTDEV_MOUNTED_DEVICE_GUID;
|
|
}
|
|
|
|
found = FALSE;
|
|
|
|
do {
|
|
|
|
devinfo = SetupDiGetClassDevs(
|
|
interfaceGuid,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
|
|
);
|
|
|
|
if ( devinfo == NULL ) {
|
|
|
|
printf( "\nFindDisk: SetupDiGetClassDevs failed: %d\n", GetLastError() );
|
|
return;
|
|
}
|
|
|
|
ZeroMemory( &interfaceData, sizeof(interfaceData) );
|
|
interfaceData.cbSize = sizeof(interfaceData);
|
|
|
|
//
|
|
// Enumerate the device interfaces of the class.
|
|
//
|
|
|
|
for (i = 0;
|
|
SetupDiEnumDeviceInterfaces( devinfo, NULL, interfaceGuid, i, &interfaceData );
|
|
i++ ) {
|
|
|
|
interfaceDetailData->cbSize = sizeof(*interfaceDetailData);
|
|
devinfoData.cbSize = sizeof(devinfoData);
|
|
|
|
if ( !SetupDiGetDeviceInterfaceDetail(
|
|
devinfo,
|
|
&interfaceData,
|
|
interfaceDetailData,
|
|
sizeof(detailBuffer),
|
|
NULL,
|
|
&devinfoData
|
|
) ) {
|
|
|
|
//printf( "\nFindDisk: SetupDiGetDeviceInterfaceDetail failed for item %d. (%d)\n", i, GetLastError() );
|
|
|
|
wcscpy( interfaceDetailData->DevicePath, L"<couldn't retrieve name>" );
|
|
}
|
|
|
|
//printf( "\nEnumerated device %ws\n", interfaceDetailData->DevicePath );
|
|
|
|
if ( !SetupDiGetDeviceRegistryProperty(
|
|
devinfo,
|
|
&devinfoData,
|
|
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
|
|
NULL,
|
|
(PBYTE)foundDeviceName,
|
|
sizeof(foundDeviceName),
|
|
NULL
|
|
) ) {
|
|
|
|
DWORD error = GetLastError();
|
|
//printf( "\nFindDisk: SetupDiGetDeviceRegistryProperty (name) failed for %ws: %d\n", interfaceDetailData->DevicePath, error );
|
|
continue;
|
|
}
|
|
|
|
//printf( "\nTarget device %ws\n", foundDeviceName );
|
|
|
|
if ( _wcsicmp( actualDeviceName, foundDeviceName ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList( devinfo );
|
|
|
|
if ( !found ) {
|
|
|
|
if ( WaitForDeletion ) {
|
|
|
|
printf( "\nRAM disk is now gone\n" );
|
|
return;
|
|
}
|
|
|
|
//printf( "Enumeration failed to find target device; sleeping\n" );
|
|
printf( "." );
|
|
|
|
Sleep( 500 );
|
|
|
|
} else {
|
|
|
|
if ( !WaitForDeletion ) {
|
|
|
|
printf( "\nRAM disk is now ready\n" );
|
|
break;
|
|
}
|
|
|
|
//printf( "Enumeration found target device; sleeping\n" );
|
|
printf( "." );
|
|
|
|
Sleep( 500 );
|
|
|
|
found = FALSE;
|
|
}
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( found ) {
|
|
|
|
swprintf( dosDeviceName, L"Ramdisk%wZ", DiskGuidString );
|
|
|
|
if ( QueryDosDeviceW(dosDeviceName, foundDeviceName, arrayof(foundDeviceName)) ) {
|
|
|
|
printf( " DosDevice name %ws is assigned to this device\n", dosDeviceName );
|
|
|
|
} else {
|
|
|
|
printf( " No DosDevice name was assigned to this device\n" );
|
|
}
|
|
|
|
found = FALSE;
|
|
|
|
for ( driveLetterString[0] = 'A';
|
|
driveLetterString[0] <= 'Z';
|
|
driveLetterString[0]++ ) {
|
|
|
|
if ( QueryDosDeviceW(driveLetterString, foundDeviceName, arrayof(foundDeviceName)) &&
|
|
(_wcsicmp(actualDeviceName, foundDeviceName) == 0) ) {
|
|
|
|
printf( " Drive letter %ws is assigned to this device\n", driveLetterString );
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !found ) {
|
|
printf( " No letter was assigned to this device\n" );
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
} // FindDisk
|
|
|
|
VOID
|
|
FullFilePath (
|
|
PWCHAR pwzPath
|
|
)
|
|
{
|
|
WCHAR wzDevPath[512] = L"";
|
|
WCHAR wzDosPath[512] = L"";
|
|
PWCHAR pwzDosName = wzDosPath;
|
|
DWORD dw;
|
|
WCHAR c;
|
|
|
|
dw = GetFullPathNameW(pwzPath, arrayof(wzDosPath), wzDosPath, NULL);
|
|
if (0 != dw) {
|
|
if (NULL != (pwzDosName = wcschr(wzDosPath, ':'))) {
|
|
pwzDosName++;
|
|
c = *pwzDosName;
|
|
*pwzDosName = '\0';
|
|
|
|
dw = QueryDosDeviceW(wzDosPath, wzDevPath, arrayof(wzDevPath));
|
|
if (0 != dw) {
|
|
*pwzDosName = c;
|
|
|
|
swprintf(pwzPath, L"%ls%ls", wzDevPath, pwzDosName);
|
|
}
|
|
else {
|
|
printf("QueryDosDeviceW(%ls) failed: %d\n", wzDosPath, GetLastError());
|
|
PrintError(GetLastError());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IsDriveLetter (
|
|
PWCHAR Name
|
|
)
|
|
{
|
|
if ((((Name[0] >= L'A') && (Name[0] <= L'Z')) ||
|
|
((Name[0] >= L'a') && (Name[0] <= L'z'))) &&
|
|
(Name[1] == L':') &&
|
|
(Name[2] == 0)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
DeleteRamdisk (
|
|
IN HANDLE ControlHandle,
|
|
IN PWSTR FileName
|
|
)
|
|
{
|
|
BOOL ok;
|
|
ULONG errorCode = 0;
|
|
ULONG returnedLength = 0;
|
|
UNICODE_STRING ustr;
|
|
OBJECT_ATTRIBUTES obja;
|
|
IO_STATUS_BLOCK iosb;
|
|
NTSTATUS status;
|
|
HANDLE imageFileHandle;
|
|
HANDLE volumeHandle;
|
|
RAMDISK_HEADER ramdiskHeader;
|
|
UNICODE_STRING guidString;
|
|
LARGE_INTEGER offset;
|
|
LPCGUID diskGuid;
|
|
ULONG diskType;
|
|
RAMDISK_QUERY_INPUT queryInput;
|
|
RAMDISK_MARK_FOR_DELETION_INPUT markInput;
|
|
BYTE queryOutputBuffer[sizeof(RAMDISK_QUERY_OUTPUT) + (MAX_PATH * sizeof(WCHAR))];
|
|
PRAMDISK_QUERY_OUTPUT queryOutput;
|
|
CONFIGRET cr;
|
|
DEVNODE devnode;
|
|
WCHAR devinst[MAX_PATH];
|
|
PNP_VETO_TYPE vetoType;
|
|
WCHAR vetoName[MAX_PATH];
|
|
WCHAR foundDeviceName[MAX_PATH];
|
|
|
|
queryOutput = (PRAMDISK_QUERY_OUTPUT)queryOutputBuffer;
|
|
|
|
if ( FileName[0] == L'{' ) {
|
|
|
|
guidString.Buffer = FileName;
|
|
guidString.Length = (USHORT)(wcslen(FileName) * sizeof(WCHAR));
|
|
guidString.MaximumLength = guidString.Length;
|
|
|
|
queryInput.Version = sizeof(RAMDISK_QUERY_INPUT);
|
|
RtlGUIDFromString( &guidString, &queryInput.DiskGuid );
|
|
|
|
ok = DeviceIoControl(
|
|
ControlHandle,
|
|
FSCTL_QUERY_RAM_DISK,
|
|
&queryInput,
|
|
sizeof(queryInput),
|
|
queryOutput,
|
|
sizeof(queryOutputBuffer),
|
|
&returnedLength,
|
|
FALSE
|
|
);
|
|
|
|
if ( !ok ) {
|
|
|
|
DWORD errorCode = GetLastError();
|
|
printf( "Error querying RAM disk: %d\n", errorCode );
|
|
PrintError( errorCode );
|
|
return;
|
|
|
|
}
|
|
|
|
diskGuid = &queryOutput->DiskGuid;
|
|
diskType = queryOutput->DiskType;
|
|
|
|
} else if (IsDriveLetter ( FileName ) ) {
|
|
|
|
//
|
|
// Treat FileName as a drive letter. See if this the supplied
|
|
// drive letter corresponds to a ramdisk.
|
|
//
|
|
|
|
if ((QueryDosDeviceW(FileName, foundDeviceName, arrayof(foundDeviceName)) == 0) ||
|
|
wcsncmp(foundDeviceName, L"\\Device\\Ramdisk", wcslen(L"\\Device\\Ramdisk"))) {
|
|
DWORD errorCode = GetLastError();
|
|
printf( "Drive letter \"%ws\" is not assigned to a RAM disk.\n",
|
|
FileName);
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
guidString.Buffer = wcschr( foundDeviceName, L'{' );
|
|
guidString.Length = (USHORT)(wcslen(guidString.Buffer) * sizeof(WCHAR));
|
|
guidString.MaximumLength = guidString.Length;
|
|
|
|
RtlGUIDFromString( &guidString, &queryInput.DiskGuid );
|
|
|
|
ok = DeviceIoControl(
|
|
ControlHandle,
|
|
FSCTL_QUERY_RAM_DISK,
|
|
&queryInput,
|
|
sizeof(queryInput),
|
|
queryOutput,
|
|
sizeof(queryOutputBuffer),
|
|
&returnedLength,
|
|
FALSE
|
|
);
|
|
|
|
if ( !ok ) {
|
|
|
|
DWORD errorCode = GetLastError();
|
|
printf( "Error querying RAM disk: %d\n", errorCode );
|
|
PrintError( errorCode );
|
|
return;
|
|
|
|
}
|
|
|
|
diskGuid = &queryOutput->DiskGuid;
|
|
diskType = queryOutput->DiskType;
|
|
|
|
} else {
|
|
|
|
RtlInitUnicodeString( &ustr, FileName );
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
|
|
status = NtOpenFile(
|
|
&imageFileHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_READ_ATTRIBUTES,
|
|
&obja,
|
|
&iosb,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_ALERT
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't open target file %ws: %x\n", FileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read and verify the header.
|
|
//
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtReadFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
&ramdiskHeader,
|
|
sizeof(ramdiskHeader),
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't read header from target file %ws: %x\n", FileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
if ( strcmp( ramdiskHeader.Ramctrl.Signature, "ramctrl" ) == 0 ) {
|
|
|
|
diskGuid = &ramdiskHeader.Ramctrl.DiskGuid;
|
|
diskType = ramdiskHeader.Ramctrl.DiskType;
|
|
|
|
} else if ( strncmp( ramdiskHeader.Sdi.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ) == 0 ) {
|
|
|
|
diskGuid = (LPCGUID)ramdiskHeader.Sdi.RuntimeGUID;
|
|
diskType = RAMDISK_TYPE_FILE_BACKED_VOLUME;
|
|
|
|
} else {
|
|
|
|
printf( "Header in target file not recognized\n" );
|
|
return;
|
|
}
|
|
|
|
|
|
NtClose( imageFileHandle );
|
|
|
|
RtlStringFromGUID( diskGuid, &guidString );
|
|
}
|
|
|
|
printf("Attempting to delete \\Device\\Ramdisk%wZ\n", &guidString );
|
|
|
|
swprintf( devinst, L"\\Device\\Ramdisk%ws", guidString.Buffer );
|
|
|
|
RtlInitUnicodeString( &ustr, devinst );
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
|
|
status = NtOpenFile(
|
|
&volumeHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&obja,
|
|
&iosb,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't open target device %ws: %x\n", devinst, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
printf( "Syncing %ws ... ", devinst );
|
|
|
|
if ( !FlushFileBuffers( volumeHandle ) ) {
|
|
|
|
errorCode = GetLastError();
|
|
// NOTE: [bassamt] FlushFileBuffers can fail with error code
|
|
// ERROR_INVALID_FUNCTION if the volume is not formatted.
|
|
// NOTE: [brimo] FlushFileBuffers can fail with error code
|
|
// ERROR_WRITE_PROTECT if the volume is mounted read-only
|
|
if ((errorCode != ERROR_INVALID_FUNCTION) && (errorCode != ERROR_WRITE_PROTECT)) {
|
|
printf( "flush failed (%u)\n", errorCode );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( !DeviceIoControl(
|
|
volumeHandle,
|
|
FSCTL_LOCK_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&returnedLength,
|
|
NULL
|
|
) ) {
|
|
|
|
errorCode = GetLastError();
|
|
printf( "lock volume failed (%u)\n", errorCode );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
if ( !DeviceIoControl(
|
|
volumeHandle,
|
|
FSCTL_DISMOUNT_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&returnedLength,
|
|
NULL
|
|
) ) {
|
|
|
|
errorCode = GetLastError();
|
|
printf( "dismount volume failed (%u)\n", errorCode );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
printf( "done\n" );
|
|
|
|
NtClose( volumeHandle );
|
|
|
|
markInput.Version = sizeof(RAMDISK_MARK_FOR_DELETION_INPUT);
|
|
markInput.DiskGuid = *diskGuid;
|
|
|
|
ok = DeviceIoControl(
|
|
ControlHandle,
|
|
FSCTL_MARK_RAM_DISK_FOR_DELETION,
|
|
&markInput,
|
|
sizeof(markInput),
|
|
NULL,
|
|
0,
|
|
&returnedLength,
|
|
FALSE
|
|
);
|
|
|
|
if ( !ok ) {
|
|
|
|
DWORD errorCode = GetLastError();
|
|
printf( "Error marking RAM disk: %d\n", errorCode );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
if ( diskType == RAMDISK_TYPE_FILE_BACKED_DISK ) {
|
|
swprintf( devinst, L"Ramdisk\\Ramdisk\\%ws", guidString.Buffer );
|
|
} else {
|
|
swprintf( devinst, L"Ramdisk\\Ramvolume\\%ws", guidString.Buffer );
|
|
}
|
|
|
|
cr = CM_Locate_DevNode( &devnode, devinst, 0 );
|
|
if ( cr != CR_SUCCESS ) {
|
|
printf( "Unable to locate devnode: %d\n", cr );
|
|
return;
|
|
}
|
|
cr = CM_Query_And_Remove_SubTree_Ex( devnode, &vetoType, vetoName, MAX_PATH, 0, NULL );
|
|
if ( cr != CR_SUCCESS ) {
|
|
printf( "Unable to remove devnode: %d\n", cr );
|
|
if ( cr == CR_REMOVE_VETOED ) {
|
|
printf( " veto type = 0x%x\n", vetoType );
|
|
printf( " veto name = %ws\n", vetoName );
|
|
}
|
|
return;
|
|
}
|
|
|
|
FindDisk( diskType, &guidString, TRUE );
|
|
|
|
printf( "RAM disk %wZ deleted\n", &guidString );
|
|
|
|
return;
|
|
|
|
} // DeleteRamdisk
|
|
|
|
void
|
|
AddBootFilesToSdi(
|
|
PWCHAR SdiFile,
|
|
PWCHAR StartromFile,
|
|
PWCHAR OsloaderFile
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING ustr;
|
|
OBJECT_ATTRIBUTES obja;
|
|
IO_STATUS_BLOCK iosb;
|
|
HANDLE imageFileHandle;
|
|
HANDLE startromHandle;
|
|
HANDLE osloaderHandle;
|
|
WCHAR dataFileName[512];
|
|
FILE_STANDARD_INFORMATION fileInfo;
|
|
FILE_ALLOCATION_INFORMATION allocInfo;
|
|
SDI_HEADER sdiHeader;
|
|
LARGE_INTEGER offset;
|
|
ULONGLONG diskOffset;
|
|
ULONGLONG diskLength;
|
|
ULONGLONG startromOffset;
|
|
ULONGLONG startromLength;
|
|
ULONGLONG startromLengthAligned;
|
|
ULONGLONG osloaderOffset;
|
|
ULONGLONG osloaderLength;
|
|
ULONGLONG osloaderLengthAligned;
|
|
ULONGLONG finalFileLength;
|
|
ULONG errorCode = 0;
|
|
PUCHAR buffer;
|
|
|
|
printf( "Adding boot files to SDI file %ws\n", SdiFile );
|
|
|
|
RtlInitUnicodeString( &ustr, SdiFile );
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
|
|
status = NtOpenFile(
|
|
&imageFileHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES,
|
|
&obja,
|
|
&iosb,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_ALERT
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't open target file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read and verify the header.
|
|
//
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtReadFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
&sdiHeader,
|
|
sizeof(sdiHeader),
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't read header from target file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
if ( strncmp( sdiHeader.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ) != 0 ) {
|
|
|
|
printf( "Header in target file not recognized\n" );
|
|
return;
|
|
}
|
|
|
|
diskOffset = sdiHeader.ToC[0].llOffset.LowPart;
|
|
diskLength = sdiHeader.ToC[0].llSize.QuadPart;
|
|
|
|
startromOffset = ROUND_TO_PAGE_SIZE( diskOffset + diskLength );
|
|
|
|
//
|
|
// Get the length of startrom.com.
|
|
//
|
|
|
|
wcscpy( dataFileName, StartromFile );
|
|
FullFilePath( dataFileName );
|
|
|
|
RtlInitUnicodeString( &ustr, dataFileName );
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
|
|
status = NtOpenFile(
|
|
&startromHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES,
|
|
&obja,
|
|
&iosb,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_ALERT
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't open startrom file %ws: %x\n", dataFileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
status = NtQueryInformationFile(
|
|
startromHandle,
|
|
&iosb,
|
|
&fileInfo,
|
|
sizeof(fileInfo),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
printf( "Can't query info for startrom file %ws: %x\n", dataFileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
startromLength = fileInfo.EndOfFile.QuadPart;
|
|
startromLengthAligned = ROUND_TO_PAGE_SIZE( startromLength );
|
|
|
|
osloaderOffset = startromOffset + startromLengthAligned;
|
|
|
|
//
|
|
// Get the length of osloader.exe.
|
|
//
|
|
|
|
wcscpy( dataFileName, OsloaderFile );
|
|
FullFilePath( dataFileName );
|
|
|
|
RtlInitUnicodeString( &ustr, dataFileName );
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
|
|
status = NtOpenFile(
|
|
&osloaderHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES,
|
|
&obja,
|
|
&iosb,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_ALERT
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't open osloader file %ws: %x\n", dataFileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
status = NtQueryInformationFile(
|
|
osloaderHandle,
|
|
&iosb,
|
|
&fileInfo,
|
|
sizeof(fileInfo),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
printf( "Can't query info for osloader file %ws: %x\n", dataFileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
osloaderLength = fileInfo.EndOfFile.QuadPart;
|
|
osloaderLengthAligned = ROUND_TO_PAGE_SIZE( startromLength );
|
|
|
|
finalFileLength = osloaderOffset + osloaderLengthAligned;
|
|
|
|
//
|
|
// Truncate the file at the end of the disk image, then extend it back.
|
|
//
|
|
|
|
printf( " truncating SDI file at end of ramdisk image %I64d [0x%I64x]\n",
|
|
startromOffset, startromOffset );
|
|
|
|
allocInfo.AllocationSize.QuadPart = startromOffset;
|
|
|
|
status = NtSetInformationFile(
|
|
imageFileHandle,
|
|
&iosb,
|
|
&allocInfo,
|
|
sizeof(allocInfo),
|
|
FileAllocationInformation
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
printf( "Can't set allocation size for image file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
allocInfo.AllocationSize.QuadPart = finalFileLength;
|
|
|
|
status = NtSetInformationFile(
|
|
imageFileHandle,
|
|
&iosb,
|
|
&allocInfo,
|
|
sizeof(allocInfo),
|
|
FileAllocationInformation
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
printf( "Can't set allocation size for image file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Copy startrom into the image file.
|
|
//
|
|
|
|
printf( " adding boot file %ws, length %I64d [0x%I64x]\n",
|
|
StartromFile, startromLength, startromLength );
|
|
|
|
buffer = malloc( (ULONG)startromLength );
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtReadFile(
|
|
startromHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
buffer,
|
|
(ULONG)startromLength,
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't read from startrom file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
offset.QuadPart = startromOffset;
|
|
|
|
status = NtWriteFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
buffer,
|
|
(ULONG)startromLength,
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't write startrom to image file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
free( buffer );
|
|
|
|
//
|
|
// Copy osloader into the image file.
|
|
//
|
|
|
|
printf( " adding load file %ws, length %I64d [0x%I64x]\n",
|
|
OsloaderFile, osloaderLength, osloaderLength );
|
|
|
|
buffer = malloc( (ULONG)osloaderLength );
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtReadFile(
|
|
osloaderHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
buffer,
|
|
(ULONG)osloaderLength,
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't read from osloader file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
offset.QuadPart = osloaderOffset;
|
|
|
|
status = NtWriteFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
buffer,
|
|
(ULONG)osloaderLength,
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't write osloader to image file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
free( buffer );
|
|
|
|
//
|
|
// Update the header.
|
|
//
|
|
|
|
printf( " updating header\n" );
|
|
|
|
sdiHeader.liBootCodeOffset.QuadPart = startromOffset;
|
|
sdiHeader.liBootCodeSize.QuadPart = startromLength;
|
|
|
|
sdiHeader.ToC[1].dwType = SDI_BLOBTYPE_BOOT;
|
|
sdiHeader.ToC[1].llOffset.QuadPart = startromOffset;
|
|
sdiHeader.ToC[1].llSize.QuadPart = startromLength;
|
|
|
|
sdiHeader.ToC[2].dwType = SDI_BLOBTYPE_LOAD;
|
|
sdiHeader.ToC[2].llOffset.QuadPart = osloaderOffset;
|
|
sdiHeader.ToC[2].llSize.QuadPart = osloaderLength;
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtWriteFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
&sdiHeader,
|
|
sizeof(sdiHeader),
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't write header to image file %ws: %x\n", SdiFile, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return;
|
|
}
|
|
|
|
printf( " done\n" );
|
|
|
|
NtClose( osloaderHandle );
|
|
NtClose( startromHandle );
|
|
NtClose( imageFileHandle );
|
|
|
|
return;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
wmain (
|
|
ULONG argc,
|
|
WCHAR *argv[])
|
|
{
|
|
BOOL ok;
|
|
HANDLE controlHandle = NULL;
|
|
PUCHAR dataBuffer = NULL;
|
|
UCHAR buffer[2048];
|
|
WCHAR string[25];
|
|
ULONG length = 0;
|
|
ULONG errorCode = 0;
|
|
ULONG returned = 0;
|
|
ULONG sizeInMb;
|
|
ULONG diskType;
|
|
WCHAR fileName[512];
|
|
ULONG desiredSize;
|
|
ULONG actualSize;
|
|
ULONG controlSize;
|
|
UNICODE_STRING ustr;
|
|
OBJECT_ATTRIBUTES obja;
|
|
IO_STATUS_BLOCK iosb;
|
|
NTSTATUS status;
|
|
PRAMDISK_CREATE_INPUT createInput;
|
|
ULONG arg;
|
|
BOOL fNeedHelp = FALSE;
|
|
HANDLE imageFileHandle;
|
|
LARGE_INTEGER allocation;
|
|
BOOL fixed;
|
|
BOOL readonly;
|
|
BOOL delete = FALSE;
|
|
ULONG diskNumber;
|
|
BOOL noDriveLetter;
|
|
BOOL hidden;
|
|
BOOL noDosDevice;
|
|
BOOL ignoreHeader;
|
|
BOOL bootDisk;
|
|
BOOL useSdi;
|
|
ULONG diskOffset;
|
|
RAMDISK_HEADER ramdiskHeader;
|
|
UNICODE_STRING guidString;
|
|
LARGE_INTEGER offset;
|
|
PWCHAR startromFile = NULL;
|
|
PWCHAR osloaderFile = NULL;
|
|
|
|
sizeInMb = 64;
|
|
diskType = RAMDISK_TYPE_FILE_BACKED_VOLUME;
|
|
fileName[0] = 0;
|
|
fixed = TRUE;
|
|
readonly = FALSE;
|
|
noDriveLetter = FALSE;
|
|
hidden = FALSE;
|
|
noDosDevice = FALSE;
|
|
ignoreHeader = FALSE;
|
|
bootDisk = FALSE;
|
|
diskOffset = PAGE_SIZE;
|
|
useSdi = FALSE;
|
|
|
|
for ( arg = 1; arg < argc; arg++ ) {
|
|
|
|
// process options
|
|
if ( (argv[arg][0] == '-') || (argv[arg][0] == '/') ) {
|
|
|
|
PWCHAR argn = argv[arg]+1; // Argument name
|
|
PWCHAR argp = argn; // Argument parameter
|
|
|
|
while ( *argp && (*argp != ':') ) {
|
|
argp++;
|
|
}
|
|
if ( *argp == ':' ) {
|
|
*argp++ = '\0';
|
|
}
|
|
|
|
switch ( argn[0] ) {
|
|
|
|
case 's': // Size in MB
|
|
case 'S':
|
|
|
|
if ( _wcsicmp( argn, L"sdi" ) == 0 ) {
|
|
useSdi = TRUE;
|
|
} else {
|
|
sizeInMb = _wtoi(argp);
|
|
}
|
|
break;
|
|
|
|
case 'a':
|
|
if ( _wcsicmp( argn, L"addboot" ) == 0 ) {
|
|
if ( arg+2 < argc ) {
|
|
startromFile = argv[++arg];
|
|
osloaderFile = argv[++arg];
|
|
} else {
|
|
printf( "Missing startrom/osloader file name\n" );
|
|
fNeedHelp = TRUE;
|
|
arg = argc - 1;
|
|
}
|
|
} else {
|
|
printf( "Unknown argument: %s\n", argv[arg] );
|
|
fNeedHelp = TRUE;
|
|
arg = argc - 1;
|
|
}
|
|
|
|
case 'i': // ignore header
|
|
case 'I':
|
|
ignoreHeader = TRUE;
|
|
break;
|
|
|
|
case 'b': // use boot disk GUID
|
|
case 'B':
|
|
bootDisk = TRUE;
|
|
break;
|
|
|
|
case 'd': // disk offset
|
|
case 'D':
|
|
diskOffset = _wtol(argp);
|
|
break;
|
|
|
|
case 'o':
|
|
case 'O': // Readonly, or options
|
|
if ( *argp ) {
|
|
|
|
BOOL sense = TRUE;
|
|
|
|
do {
|
|
|
|
if ( *argp == '-' ) {
|
|
sense = FALSE;
|
|
argp++;
|
|
} else if ( *argp == '+' ) {
|
|
sense = TRUE;
|
|
argp++;
|
|
}
|
|
|
|
switch ( *argp ) {
|
|
|
|
case 'v':
|
|
case 'V':
|
|
diskType = sense ? RAMDISK_TYPE_FILE_BACKED_VOLUME :
|
|
RAMDISK_TYPE_FILE_BACKED_DISK;
|
|
break;
|
|
|
|
case 'r':
|
|
case 'R':
|
|
readonly = sense;
|
|
break;
|
|
|
|
case 'f':
|
|
case 'F':
|
|
fixed = sense;
|
|
break;
|
|
|
|
case 'l':
|
|
case 'L':
|
|
noDriveLetter = !sense;
|
|
break;
|
|
|
|
case 'h':
|
|
case 'H':
|
|
hidden = sense;
|
|
break;
|
|
|
|
case 'd':
|
|
case 'D':
|
|
noDosDevice = !sense;
|
|
break;
|
|
|
|
}
|
|
|
|
sense = TRUE;
|
|
|
|
argp++;
|
|
|
|
} while ( *argp );
|
|
|
|
} else {
|
|
|
|
readonly = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'x': // Delete device, not create
|
|
case 'X':
|
|
delete = TRUE;
|
|
break;
|
|
|
|
case 'h': // Help
|
|
case 'H':
|
|
case '?':
|
|
fNeedHelp = TRUE;
|
|
arg = argc - 1;
|
|
break;
|
|
|
|
default:
|
|
printf( "Unknown argument: %s\n", argv[arg] );
|
|
fNeedHelp = TRUE;
|
|
arg = argc - 1;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
wcscpy( fileName, argv[arg] );
|
|
}
|
|
}
|
|
|
|
if ( fNeedHelp ) {
|
|
|
|
printf(
|
|
"Usage (to create):\n"
|
|
" ramdiskctrl [options] win32_disk_file_name\n"
|
|
"or (to delete)\n"
|
|
" ramdiskctrl -x win32_disk_file_name | {guid} | drive_letter:\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" -s:N Set size of disk image in MB (default: 64)\n"
|
|
" -i Ignore ramctrl header in existing ramdisk file.\n"
|
|
" -d:N Ramdisk offset from start of file. (default: 4096).\n"
|
|
" -o:options Options: (use - or + to set sense)\n"
|
|
" v Volume (vs. disk) (default: volume)\n"
|
|
" r Readonly (default: writeable)\n"
|
|
" f Fixed (default: removable)\n"
|
|
" l Assign drive letter (default: assign)\n"
|
|
" h Hidden (default: visible)\n"
|
|
" d Assign DosDevice name (default: assign)\n"
|
|
" -h or -? Display this help text.\n"
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
if ( !delete ||
|
|
((fileName[0] != L'{') &&
|
|
!IsDriveLetter(fileName))) {
|
|
FullFilePath( fileName );
|
|
}
|
|
|
|
if ( startromFile != NULL ) {
|
|
|
|
AddBootFilesToSdi( fileName, startromFile, osloaderFile );
|
|
|
|
return 0;
|
|
}
|
|
|
|
wcscpy( string, L"\\device\\ramdisk" );
|
|
RtlInitUnicodeString( &ustr, string );
|
|
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
//printf( "Opening %ws\n", string );
|
|
|
|
status = NtOpenFile(
|
|
&controlHandle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&obja,
|
|
&iosb,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Error opening control device %ws. Error: %x\n", string, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return 1;
|
|
}
|
|
|
|
if ( delete ) {
|
|
|
|
//
|
|
// Delete the disk.
|
|
//
|
|
|
|
DeleteRamdisk( controlHandle, fileName );
|
|
|
|
return 0;
|
|
}
|
|
|
|
if ( fileName[0] == 0 ) {
|
|
|
|
//
|
|
// Just list the disks.
|
|
//
|
|
|
|
ListDisks( controlHandle );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// If SDI, force the disk type to emulated volume, etc.
|
|
//
|
|
|
|
if ( useSdi ) {
|
|
diskType = RAMDISK_TYPE_FILE_BACKED_VOLUME;
|
|
bootDisk = FALSE;
|
|
fixed = TRUE;
|
|
readonly = FALSE;
|
|
noDriveLetter = FALSE;
|
|
hidden = FALSE;
|
|
noDosDevice = FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the disk.
|
|
//
|
|
|
|
desiredSize = sizeInMb * 1024 * 1024;
|
|
actualSize = ((desiredSize + CYLINDER_SIZE - 1) / CYLINDER_SIZE) * CYLINDER_SIZE;
|
|
if ( actualSize != desiredSize ) {
|
|
printf( "Using rounded-up disk size of %d instead of %d\n", actualSize, desiredSize );
|
|
}
|
|
|
|
controlSize = sizeof(RAMDISK_CREATE_INPUT) + (wcslen(fileName) * sizeof(WCHAR));
|
|
|
|
createInput = malloc( controlSize );
|
|
if ( createInput == NULL ) {
|
|
printf( "Can't allocate %d bytes for RAMDISK_CREATE_INPUT struct\n", controlSize );
|
|
return 1;
|
|
}
|
|
|
|
RtlZeroMemory( createInput, controlSize );
|
|
|
|
createInput->Version = sizeof(RAMDISK_CREATE_INPUT);
|
|
wcscpy( createInput->FileName, fileName );
|
|
|
|
allocation.QuadPart = actualSize + diskOffset;
|
|
|
|
RtlInitUnicodeString( &ustr, fileName );
|
|
InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
|
|
|
status = NtCreateFile(
|
|
&imageFileHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES,
|
|
&obja,
|
|
&iosb,
|
|
&allocation,
|
|
0,
|
|
0,
|
|
FILE_OPEN_IF,
|
|
FILE_SYNCHRONOUS_IO_ALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't create target file %ws: %x\n", fileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return 1;
|
|
}
|
|
|
|
if ( iosb.Information == FILE_CREATED || ignoreHeader ) {
|
|
|
|
if ( !bootDisk ) {
|
|
UuidCreate( &createInput->DiskGuid );
|
|
} else {
|
|
createInput->DiskGuid = RamdiskBootDiskGuid;
|
|
}
|
|
|
|
createInput->DiskOffset = diskOffset;
|
|
createInput->DiskLength = actualSize;
|
|
createInput->DiskType = diskType;
|
|
createInput->Options.Fixed = (BOOLEAN)fixed;
|
|
createInput->Options.Readonly = (BOOLEAN)readonly;
|
|
createInput->Options.NoDriveLetter = (BOOLEAN)noDriveLetter;
|
|
createInput->Options.Hidden = (BOOLEAN)hidden;
|
|
createInput->Options.NoDosDevice = (BOOLEAN)noDosDevice;
|
|
|
|
}
|
|
|
|
if ( iosb.Information == FILE_CREATED ) {
|
|
|
|
UCHAR byte = 0;
|
|
|
|
printf( "Created target file %ws\n", fileName );
|
|
|
|
//
|
|
// Extend the file to the desired length.
|
|
//
|
|
|
|
offset.QuadPart = actualSize + diskOffset - 1;
|
|
|
|
status = NtWriteFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
&byte,
|
|
1,
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't write to target file %ws: %x\n", fileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Write the header.
|
|
//
|
|
|
|
RtlZeroMemory( &ramdiskHeader, sizeof(ramdiskHeader) );
|
|
|
|
if ( !useSdi ) {
|
|
|
|
strcpy( ramdiskHeader.Ramctrl.Signature, "ramctrl" );
|
|
ramdiskHeader.Ramctrl.DiskGuid = createInput->DiskGuid;
|
|
ramdiskHeader.Ramctrl.DiskOffset = diskOffset;
|
|
ramdiskHeader.Ramctrl.DiskType = diskType;
|
|
ramdiskHeader.Ramctrl.Options = createInput->Options;
|
|
|
|
} else {
|
|
|
|
memcpy( ramdiskHeader.Sdi.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) );
|
|
ramdiskHeader.Sdi.dwMDBType = SDI_MDBTYPE_VOLATILE;
|
|
memcpy( ramdiskHeader.Sdi.RuntimeGUID, &createInput->DiskGuid, sizeof(GUID) );
|
|
ramdiskHeader.Sdi.dwPageAlignmentFactor = SDI_DEFAULTPAGEALIGNMENT;
|
|
ramdiskHeader.Sdi.ToC[0].dwType = SDI_BLOBTYPE_PART;
|
|
ramdiskHeader.Sdi.ToC[0].llOffset.QuadPart = diskOffset;
|
|
ramdiskHeader.Sdi.ToC[0].llSize.QuadPart = createInput->DiskLength;
|
|
}
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtWriteFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
&ramdiskHeader,
|
|
sizeof(ramdiskHeader),
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't write to target file %ws: %x\n", fileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
FILE_STANDARD_INFORMATION fileInfo;
|
|
|
|
printf( "Using existing target file %ws\n", fileName );
|
|
|
|
//
|
|
// Get the length of the existing file.
|
|
//
|
|
|
|
status = NtQueryInformationFile(
|
|
imageFileHandle,
|
|
&iosb,
|
|
&fileInfo,
|
|
sizeof(fileInfo),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
printf( "Can't query info for target file %ws: %x\n", fileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Read and verify the header.
|
|
//
|
|
if ( !ignoreHeader ) {
|
|
|
|
offset.QuadPart = 0;
|
|
|
|
status = NtReadFile(
|
|
imageFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
&ramdiskHeader,
|
|
sizeof(ramdiskHeader),
|
|
&offset,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Can't read header from target file %ws: %x\n", fileName, status );
|
|
errorCode = RtlNtStatusToDosError( status );
|
|
PrintError( errorCode );
|
|
return 0;
|
|
}
|
|
|
|
if ( strcmp( ramdiskHeader.Ramctrl.Signature, "ramctrl" ) == 0 ) {
|
|
|
|
createInput->DiskGuid = ramdiskHeader.Ramctrl.DiskGuid;
|
|
createInput->DiskOffset = ramdiskHeader.Ramctrl.DiskOffset;
|
|
createInput->DiskLength = fileInfo.EndOfFile.QuadPart - createInput->DiskOffset;
|
|
diskType = createInput->DiskType = ramdiskHeader.Ramctrl.DiskType;
|
|
createInput->Options = ramdiskHeader.Ramctrl.Options;
|
|
|
|
} else if ( strncmp( ramdiskHeader.Sdi.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ) == 0 ) {
|
|
|
|
memcpy( &createInput->DiskGuid, ramdiskHeader.Sdi.RuntimeGUID, sizeof(GUID) );
|
|
createInput->DiskOffset = ramdiskHeader.Sdi.ToC[0].llOffset.LowPart;
|
|
createInput->DiskLength = ramdiskHeader.Sdi.ToC[0].llSize.QuadPart;
|
|
diskType = createInput->DiskType = RAMDISK_TYPE_FILE_BACKED_VOLUME;
|
|
bootDisk = FALSE;
|
|
fixed = TRUE;
|
|
readonly = FALSE;
|
|
noDriveLetter = FALSE;
|
|
hidden = FALSE;
|
|
noDosDevice = FALSE;
|
|
createInput->Options.Fixed = (BOOLEAN)fixed;
|
|
createInput->Options.Readonly = (BOOLEAN)readonly;
|
|
createInput->Options.NoDriveLetter = (BOOLEAN)noDriveLetter;
|
|
createInput->Options.Hidden = (BOOLEAN)hidden;
|
|
createInput->Options.NoDosDevice = (BOOLEAN)noDosDevice;
|
|
|
|
} else {
|
|
|
|
printf( "Header in target file not recognized\n" );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
NtClose( imageFileHandle );
|
|
|
|
RtlStringFromGUID( &createInput->DiskGuid, &guidString );
|
|
|
|
printf( "Creating RAM disk:\n" );
|
|
printf( " File: %ws\n", createInput->FileName );
|
|
printf( " Type: %s\n",
|
|
createInput->DiskType == RAMDISK_TYPE_FILE_BACKED_VOLUME ? "volume" : "disk" );
|
|
printf( " Length: 0x%I64x\n", createInput->DiskLength );
|
|
printf( " Offset: 0x%x\n", createInput->DiskOffset );
|
|
printf( " GUID: %wZ\n", &guidString );
|
|
printf( " Options:" );
|
|
printf( "%s; ", createInput->Options.Fixed ? "fixed" : "removable" );
|
|
printf( "%s; ", createInput->Options.Readonly ? "readonly" : "writeable" );
|
|
printf( "%s; ", createInput->Options.NoDriveLetter ? "no drive letter" : "drive letter" );
|
|
printf( "%s; ", createInput->Options.Hidden ? "hidden" : "visible" );
|
|
printf( "%s\n", createInput->Options.NoDosDevice ? "no DosDevice" : "DosDevice" );
|
|
|
|
ok = DeviceIoControl(
|
|
controlHandle,
|
|
FSCTL_CREATE_RAM_DISK,
|
|
createInput,
|
|
controlSize,
|
|
NULL,
|
|
0,
|
|
&returned,
|
|
FALSE
|
|
);
|
|
|
|
if ( !ok ) {
|
|
errorCode = GetLastError();
|
|
printf( "Error creating RAM disk: %d\n", errorCode );
|
|
PrintError( errorCode );
|
|
return 1;
|
|
}
|
|
|
|
printf( "RAM disk created\n" );
|
|
|
|
FindDisk( createInput->DiskType, &guidString, FALSE );
|
|
|
|
return 0;
|
|
|
|
} // wmain
|
|
|