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.
1084 lines
26 KiB
1084 lines
26 KiB
/*++
|
|
|
|
Copyright (c) 1991-1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fd_nt.c
|
|
|
|
Abstract:
|
|
|
|
This module wraps fdisk engine functions. This is done
|
|
to avoid having files that include both the full windows
|
|
and the full nt include file sets.
|
|
|
|
Functions that manipulate engine structures (REGIONs, for example)
|
|
are also placed here.
|
|
|
|
This file is targeted at NT, not Windows.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 5-Dec-1991
|
|
|
|
Revision History:
|
|
|
|
Misc cleanup (BobRi) 22-Jan-1994
|
|
|
|
--*/
|
|
|
|
#include "fdisk.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
// These partition ID's are for systems recognized by WINDISK,
|
|
// even though they don't appear in ntdddisk.h.
|
|
|
|
#define PARTITION_OS2_BOOT 0xa
|
|
#define PARTITION_EISA 0x12
|
|
|
|
|
|
WCHAR UnicodeSysIdName[100];
|
|
BYTE StringBuffer[100];
|
|
|
|
// Pagefile support structures.
|
|
|
|
typedef struct _PAGEFILE_LOCATION {
|
|
struct _PAGEFILE_LOCATION *Next;
|
|
CHAR DriveLetter;
|
|
} PAGEFILE_LOCATION, *PPAGEFILE_LOCATION;
|
|
|
|
PPAGEFILE_LOCATION PagefileHead = NULL;
|
|
|
|
// For some reason the file systems don't like being accessed shortly after
|
|
// a format or lock event.
|
|
|
|
#define SLEEP_TIME (1000*2) // 2 seconds
|
|
|
|
|
|
PWSTR
|
|
GetWideSysIDName(
|
|
IN UCHAR SysID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
ANSI_STRING ansiString;
|
|
UNICODE_STRING unicodeString;
|
|
DWORD stringId;
|
|
|
|
// Get the name, which is a byte-string.
|
|
|
|
switch (SysID) {
|
|
|
|
case PARTITION_ENTRY_UNUSED:
|
|
stringId = IDS_PARTITION_FREE;
|
|
break;
|
|
|
|
case PARTITION_XENIX_1:
|
|
stringId = IDS_PARTITION_XENIX1;
|
|
break;
|
|
|
|
case PARTITION_XENIX_2:
|
|
stringId = IDS_PARTITION_XENIX2;
|
|
break;
|
|
|
|
case PARTITION_OS2_BOOT:
|
|
stringId = IDS_PARTITION_OS2_BOOT;
|
|
break;
|
|
|
|
case PARTITION_EISA:
|
|
stringId = IDS_PARTITION_EISA;
|
|
break;
|
|
|
|
case PARTITION_UNIX:
|
|
stringId = IDS_PARTITION_UNIX;
|
|
break;
|
|
|
|
case PARTITION_PREP:
|
|
#ifdef _PPC_
|
|
stringId = IDS_PARTITION_POWERPC;
|
|
#else
|
|
|
|
// If not on a PPC platform, assume this is Eisa related
|
|
|
|
stringId = IDS_PARTITION_EISA;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
stringId = IDS_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
LoadString(hModule, stringId, StringBuffer, sizeof(StringBuffer));
|
|
RtlInitAnsiString(&ansiString, StringBuffer);
|
|
|
|
//
|
|
// Convert to Unicode
|
|
//
|
|
|
|
unicodeString.Buffer = UnicodeSysIdName;
|
|
unicodeString.MaximumLength = sizeof(UnicodeSysIdName);
|
|
RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
|
|
return UnicodeSysIdName;
|
|
}
|
|
|
|
|
|
ULONG
|
|
MyDiskRegistryGet(
|
|
OUT PDISK_REGISTRY *DiskRegistry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate memory for the size of the disk registry, obtain
|
|
the registry contents (if any) and return the pointer to the
|
|
allocated memory.
|
|
|
|
Arguments:
|
|
|
|
A pointer to a disk registry pointer.
|
|
|
|
Return Value:
|
|
|
|
status indicating success or failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG length;
|
|
PDISK_REGISTRY diskRegistry;
|
|
NTSTATUS status;
|
|
|
|
|
|
while (((status = DiskRegistryGet(NULL, &length)) == STATUS_NO_MEMORY)
|
|
|| (status == STATUS_INSUFFICIENT_RESOURCES))
|
|
{
|
|
ConfirmOutOfMemory();
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return EC(status);
|
|
}
|
|
|
|
diskRegistry = Malloc(length);
|
|
|
|
while (((status = DiskRegistryGet(diskRegistry, &length)) == STATUS_NO_MEMORY)
|
|
|| (status == STATUS_INSUFFICIENT_RESOURCES))
|
|
{
|
|
ConfirmOutOfMemory();
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
LOG_DISK_REGISTRY("MyDiskRegistryGet", diskRegistry);
|
|
*DiskRegistry = diskRegistry;
|
|
}
|
|
return EC(status);
|
|
}
|
|
|
|
|
|
ULONG
|
|
FormDiskSignature(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return a ULONG disk signature. This is derived from the current
|
|
system time.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
A 32-bit signature
|
|
|
|
--*/
|
|
|
|
{
|
|
LARGE_INTEGER time;
|
|
static ULONG baseSignature = 0;
|
|
|
|
if (!baseSignature) {
|
|
|
|
NtQuerySystemTime(&time);
|
|
time.QuadPart = time.QuadPart >> 16;
|
|
baseSignature = time.LowPart;
|
|
}
|
|
return baseSignature++;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
GetVolumeSizeMB(
|
|
IN ULONG Disk,
|
|
IN ULONG Partition,
|
|
OUT PULONG Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a disk and a partition, query the "volume" to get its size.
|
|
By performing the query on the 1st partition of a potential FT set,
|
|
the total size of the set will be returned. If the partition isn't
|
|
an FT set, it will work too.
|
|
|
|
Arguments:
|
|
|
|
Disk - the disk number
|
|
Partition - the partition number
|
|
Size - the size of the "volume"
|
|
|
|
Return Value:
|
|
|
|
TRUE - a size was returned.
|
|
FALSE - something failed in getting the size.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN retValue = FALSE;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
HANDLE handle;
|
|
STATUS_CODE sc;
|
|
PARTITION_INFORMATION partitionInfo;
|
|
LARGE_INTEGER partitionLength;
|
|
|
|
*Size = 0;
|
|
sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
|
|
if (sc == OK_STATUS) {
|
|
|
|
sc = NtDeviceIoControlFile(handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
IOCTL_DISK_GET_PARTITION_INFO,
|
|
NULL,
|
|
0,
|
|
&partitionInfo,
|
|
sizeof(PARTITION_INFORMATION));
|
|
|
|
if (sc == OK_STATUS) {
|
|
|
|
// Convert to MB
|
|
|
|
partitionLength.QuadPart = partitionInfo.PartitionLength.QuadPart >> 20;
|
|
*Size = partitionLength.LowPart;
|
|
retValue = TRUE;
|
|
}
|
|
LowCloseDisk(handle);
|
|
}
|
|
return retValue;
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetVolumeTypeAndSize(
|
|
IN ULONG Disk,
|
|
IN ULONG Partition,
|
|
OUT PWSTR *Label,
|
|
OUT PWSTR *Type,
|
|
OUT PULONG Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a disk and partition number, determine its size, label and file
|
|
system type. This routine will allocate the space for label and file
|
|
system type. It is the responsibility of the caller to free this memory.
|
|
|
|
Arguments:
|
|
|
|
Disk - the disk number
|
|
Partition - the partition number
|
|
Label - a pointer to a pointer for a WCHAR string to contain the label
|
|
Type - a pointer to a pointer for a WCHAR string to contain the file system
|
|
type.
|
|
Size - a pointer to a ULONG for the size of the disk in KB.
|
|
|
|
Return Value:
|
|
|
|
OK_STATUS - everything was performed.
|
|
!OK_STATUS - the error code that was returned in the process of performing
|
|
this work.
|
|
|
|
--*/
|
|
|
|
{
|
|
IO_STATUS_BLOCK statusBlock;
|
|
HANDLE handle;
|
|
unsigned char buffer[256];
|
|
PWSTR label,
|
|
name;
|
|
ULONG length;
|
|
DISK_GEOMETRY diskGeometry;
|
|
STATUS_CODE sc;
|
|
BOOLEAN firstTime = TRUE;
|
|
PFILE_FS_VOLUME_INFORMATION labelInfo = (PFILE_FS_VOLUME_INFORMATION)buffer;
|
|
PFILE_FS_ATTRIBUTE_INFORMATION info = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
|
|
|
|
while (1) {
|
|
sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
|
|
if (sc == OK_STATUS) {
|
|
|
|
sc = NtQueryVolumeInformationFile(handle,
|
|
&statusBlock,
|
|
buffer,
|
|
sizeof(buffer),
|
|
FileFsVolumeInformation);
|
|
if (sc == OK_STATUS) {
|
|
|
|
length = labelInfo->VolumeLabelLength;
|
|
labelInfo->VolumeLabel[length/sizeof(WCHAR)] = 0;
|
|
length = (length+1) * sizeof(WCHAR);
|
|
|
|
label = Malloc(length);
|
|
RtlMoveMemory(label, labelInfo->VolumeLabel, length);
|
|
} else {
|
|
|
|
label = Malloc(sizeof(WCHAR));
|
|
*label = 0;
|
|
}
|
|
*Label = label;
|
|
|
|
if (sc == OK_STATUS) {
|
|
sc = NtQueryVolumeInformationFile(handle,
|
|
&statusBlock,
|
|
buffer,
|
|
sizeof(buffer),
|
|
FileFsAttributeInformation);
|
|
if (sc == OK_STATUS) {
|
|
|
|
length = info->FileSystemNameLength;
|
|
info->FileSystemName[length/sizeof(WCHAR)] = 0;
|
|
length = (length+1)*sizeof(WCHAR);
|
|
name = Malloc(length);
|
|
RtlMoveMemory(name, info->FileSystemName, length);
|
|
} else {
|
|
|
|
name = Malloc(sizeof(WCHAR));
|
|
*name = 0;
|
|
}
|
|
*Type = name;
|
|
}
|
|
|
|
if (sc == OK_STATUS) {
|
|
sc = NtDeviceIoControlFile(handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
(PVOID)&diskGeometry,
|
|
sizeof(diskGeometry));
|
|
if (NT_SUCCESS(sc)) {
|
|
LARGE_INTEGER sizeInBytes;
|
|
ULONG cylinderBytes;
|
|
|
|
cylinderBytes = diskGeometry.TracksPerCylinder *
|
|
diskGeometry.SectorsPerTrack *
|
|
diskGeometry.BytesPerSector;
|
|
|
|
sizeInBytes.QuadPart = diskGeometry.Cylinders.QuadPart * cylinderBytes;
|
|
|
|
// Now convert everything to KB
|
|
|
|
sizeInBytes.QuadPart = sizeInBytes.QuadPart >> 10;
|
|
*Size = (ULONG) sizeInBytes.LowPart;
|
|
}
|
|
}
|
|
DmClose(handle);
|
|
sc = OK_STATUS;
|
|
break;
|
|
} else {
|
|
if (firstTime) {
|
|
firstTime = FALSE;
|
|
} else {
|
|
break;
|
|
}
|
|
Sleep(SLEEP_TIME);
|
|
}
|
|
}
|
|
|
|
return EC(sc);
|
|
}
|
|
|
|
ULONG
|
|
GetVolumeLabel(
|
|
IN ULONG Disk,
|
|
IN ULONG Partition,
|
|
OUT PWSTR *Label
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a disk number and a partition number return the volume label (if
|
|
any).
|
|
|
|
Arguments:
|
|
|
|
Disk - the disk number
|
|
Partition - the partition number
|
|
Label - a pointer to a pointer for a WCHAR string to contain the label
|
|
|
|
Return Value:
|
|
|
|
OK_STATUS - everything was performed.
|
|
!OK_STATUS - the error code that was returned in the process of performing
|
|
this work.
|
|
--*/
|
|
|
|
{
|
|
IO_STATUS_BLOCK statusBlock;
|
|
HANDLE handle;
|
|
unsigned char buffer[256];
|
|
PWSTR label;
|
|
ULONG length;
|
|
STATUS_CODE sc;
|
|
BOOLEAN firstTime = TRUE;
|
|
PFILE_FS_VOLUME_INFORMATION labelInfo = (PFILE_FS_VOLUME_INFORMATION)buffer;
|
|
|
|
while (1) {
|
|
sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
|
|
if (sc == OK_STATUS) {
|
|
|
|
sc = NtQueryVolumeInformationFile(handle,
|
|
&statusBlock,
|
|
buffer,
|
|
sizeof(buffer),
|
|
FileFsVolumeInformation);
|
|
DmClose(handle);
|
|
if (sc == OK_STATUS) {
|
|
|
|
length = labelInfo->VolumeLabelLength;
|
|
labelInfo->VolumeLabel[length/sizeof(WCHAR)] = 0;
|
|
length = (length+1) * sizeof(WCHAR);
|
|
|
|
label = Malloc(length);
|
|
RtlMoveMemory(label, labelInfo->VolumeLabel, length);
|
|
} else {
|
|
|
|
label = Malloc(sizeof(WCHAR));
|
|
sc = OK_STATUS;
|
|
*label = 0;
|
|
}
|
|
*Label = label;
|
|
break;
|
|
} else {
|
|
if (firstTime) {
|
|
firstTime = FALSE;
|
|
} else {
|
|
*Label = NULL;
|
|
break;
|
|
}
|
|
Sleep(SLEEP_TIME);
|
|
}
|
|
}
|
|
return EC(sc);
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetTypeName(
|
|
IN ULONG Disk,
|
|
IN ULONG Partition,
|
|
OUT PWSTR *Name
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a disk number and partition number return the file system type
|
|
string.
|
|
|
|
Arguments:
|
|
|
|
Disk - the disk number
|
|
Partition - the partition number
|
|
Name - a pointer to a pointer for a WCHAR string to contain the file system
|
|
type.
|
|
|
|
Return Value:
|
|
|
|
OK_STATUS - everything was performed.
|
|
!OK_STATUS - the error code that was returned in the process of performing
|
|
this work.
|
|
--*/
|
|
|
|
{
|
|
PWSTR name;
|
|
STATUS_CODE sc;
|
|
HANDLE handle;
|
|
unsigned char buffer[256];
|
|
IO_STATUS_BLOCK statusBlock;
|
|
ULONG length;
|
|
BOOLEAN firstTime = TRUE;
|
|
PFILE_FS_ATTRIBUTE_INFORMATION info = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
|
|
|
|
// For some reason, the file systems believe they are locked or need
|
|
// to be verified after formats and the like. Therefore this is attempted
|
|
// twice before it actually gives up.
|
|
|
|
while (1) {
|
|
sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
|
|
|
|
if (sc == OK_STATUS) {
|
|
sc = NtQueryVolumeInformationFile(handle,
|
|
&statusBlock,
|
|
buffer,
|
|
sizeof(buffer),
|
|
FileFsAttributeInformation);
|
|
DmClose(handle);
|
|
if (sc == OK_STATUS) {
|
|
|
|
length = info->FileSystemNameLength;
|
|
info->FileSystemName[length/sizeof(WCHAR)] = 0;
|
|
length = (length+1)*sizeof(WCHAR);
|
|
name = Malloc(length);
|
|
RtlMoveMemory(name, info->FileSystemName, length);
|
|
} else {
|
|
|
|
name = Malloc(sizeof(WCHAR));
|
|
*name = 0;
|
|
sc = OK_STATUS;
|
|
}
|
|
*Name = name;
|
|
break;
|
|
} else {
|
|
if (firstTime) {
|
|
firstTime = FALSE;
|
|
} else {
|
|
break;
|
|
}
|
|
Sleep(SLEEP_TIME);
|
|
}
|
|
}
|
|
|
|
return EC(sc);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsRemovable(
|
|
IN ULONG DiskNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function determines whether the specified physical
|
|
disk is removable.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber -- The Physical Disk Number of the disk in question.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the disk is removable.
|
|
|
|
--*/
|
|
|
|
{
|
|
STATUS_CODE sc;
|
|
NTSTATUS status;
|
|
HANDLE handle;
|
|
DISK_GEOMETRY diskGeometry;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
PCHAR name;
|
|
|
|
name = GetDiskName(DiskNumber);
|
|
sc = LowOpenDisk(name, &handle);
|
|
|
|
if (sc == OK_STATUS) {
|
|
status = NtDeviceIoControlFile(handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
(PVOID)&diskGeometry,
|
|
sizeof(diskGeometry));
|
|
LowCloseDisk(handle);
|
|
if (NT_SUCCESS(status)) {
|
|
if (diskGeometry.MediaType == RemovableMedia) {
|
|
char ntDeviceName[100];
|
|
|
|
// Do a dismount/force mount sequence to make sure
|
|
// the media hasn't changed since last mount.
|
|
// Dismount partition 1 by lock/unlock/close.
|
|
|
|
sprintf(ntDeviceName, "%s\\Partition1", name);
|
|
status= LowOpenNtName(ntDeviceName, &handle);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
LowLockDrive(handle);
|
|
LowUnlockDrive(handle);
|
|
LowCloseDisk(handle);
|
|
|
|
// Now force the mount by opening the device with a '\'
|
|
// This is done on partition 1 of the device.
|
|
|
|
sprintf(ntDeviceName, "%s\\Partition1\\", name);
|
|
status= LowOpenNtName(ntDeviceName, &handle);
|
|
if (NT_SUCCESS(status)) {
|
|
LowCloseDisk(handle);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetDriveLetterLinkTarget(
|
|
IN PWSTR SourceNameStr,
|
|
OUT PWSTR *LinkTarget
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
static WCHAR targetNameBuffer[50];
|
|
UNICODE_STRING sourceName,
|
|
targetName;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES attributes;
|
|
HANDLE handle;
|
|
|
|
|
|
RtlInitUnicodeString(&sourceName, SourceNameStr);
|
|
InitializeObjectAttributes(&attributes, &sourceName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
status = NtOpenSymbolicLinkObject(&handle, READ_CONTROL | SYMBOLIC_LINK_QUERY, &attributes);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
RtlZeroMemory(targetNameBuffer, 50 * sizeof(WCHAR));
|
|
targetName.Buffer = targetNameBuffer;
|
|
targetName.MaximumLength = sizeof(targetNameBuffer);
|
|
status = NtQuerySymbolicLinkObject(handle, &targetName, NULL);
|
|
NtClose(handle);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
*LinkTarget = targetName.Buffer;
|
|
} else {
|
|
*LinkTarget = NULL;
|
|
}
|
|
|
|
return EC(status);
|
|
}
|
|
|
|
|
|
#include "bootmbr.h"
|
|
|
|
#if X86BOOTCODE_SIZE < MBOOT_CODE_SIZE
|
|
#error Something is wrong with the boot code (it's too small)!
|
|
#endif
|
|
|
|
|
|
ULONG
|
|
MasterBootCode(
|
|
IN ULONG Disk,
|
|
IN ULONG Signature,
|
|
IN BOOLEAN SetBootCode,
|
|
IN BOOLEAN SetSignature
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If the zero sector of the disk does not have a valid MBR
|
|
signature (i.e. AA55), update it such that it has a valid
|
|
MBR and fill in the disk signature and bootcode in the
|
|
process.
|
|
|
|
Arguments:
|
|
|
|
Disk - the disk ordinal to be affected
|
|
SetSignature - if TRUE update the disk signature
|
|
Signature - the disk signature for the update
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE handle;
|
|
STATUS_CODE status;
|
|
PUCHAR unalignedSectorBuffer,
|
|
sectorBuffer;
|
|
ULONG bps,
|
|
dummy,
|
|
i;
|
|
BOOLEAN writeIt;
|
|
PCHAR diskName = GetDiskName(Disk);
|
|
|
|
#ifndef max
|
|
#define max(a,b) ((a > b) ? a : b)
|
|
#endif
|
|
|
|
if (SetBootCode) {
|
|
writeIt = FALSE;
|
|
|
|
// allocate sector buffer
|
|
|
|
status = LowGetDriveGeometry(diskName, &dummy, &bps, &dummy, &dummy);
|
|
if (status != OK_STATUS) {
|
|
return EC(status);
|
|
}
|
|
if (bps < 512) {
|
|
bps = 512;
|
|
}
|
|
unalignedSectorBuffer = Malloc(2*bps);
|
|
sectorBuffer = (PUCHAR)(((ULONG)unalignedSectorBuffer+bps) & ~(bps-1));
|
|
|
|
// open entire disk (partition 0)
|
|
|
|
if ((status = LowOpenDisk(diskName, &handle)) != OK_STATUS) {
|
|
return EC(status);
|
|
}
|
|
|
|
// read (at least) first 512 bytes
|
|
|
|
status = LowReadSectors(handle, bps, 0, 1, sectorBuffer);
|
|
if (status == OK_STATUS) {
|
|
|
|
if ((sectorBuffer[MBOOT_SIG_OFFSET+0] != MBOOT_SIG1)
|
|
|| (sectorBuffer[MBOOT_SIG_OFFSET+1] != MBOOT_SIG2)) {
|
|
|
|
// xfer boot code into sectorBuffer
|
|
|
|
for (i=0; i<MBOOT_CODE_SIZE; i++) {
|
|
sectorBuffer[i] = x86BootCode[i];
|
|
}
|
|
|
|
// wipe partition table
|
|
|
|
for (i=MBOOT_CODE_SIZE; i<MBOOT_SIG_OFFSET; i++) {
|
|
sectorBuffer[i] = 0;
|
|
}
|
|
|
|
// set the signature
|
|
|
|
sectorBuffer[MBOOT_SIG_OFFSET+0] = MBOOT_SIG1;
|
|
sectorBuffer[MBOOT_SIG_OFFSET+1] = MBOOT_SIG2;
|
|
|
|
writeIt = TRUE;
|
|
}
|
|
|
|
if (writeIt) {
|
|
status = LowWriteSectors(handle, bps, 0, 1, sectorBuffer);
|
|
}
|
|
}
|
|
|
|
LowCloseDisk(handle);
|
|
Free(unalignedSectorBuffer);
|
|
}
|
|
|
|
if (SetSignature) {
|
|
PDRIVE_LAYOUT_INFORMATION layout;
|
|
|
|
// Use the IOCTL to set the signature. This code really does
|
|
// not know where the MBR exists. (ezDrive extensions).
|
|
|
|
status = LowGetDiskLayout(diskName, &layout);
|
|
|
|
if (status == OK_STATUS) {
|
|
layout->Signature = Signature;
|
|
LowSetDiskLayout(diskName, layout);
|
|
}
|
|
}
|
|
|
|
return EC(status);
|
|
}
|
|
|
|
|
|
ULONG
|
|
UpdateMasterBootCode(
|
|
IN ULONG Disk
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine updates the zero sector of the disk to insure that boot
|
|
code is present.
|
|
|
|
Arguments:
|
|
|
|
Disk - the disk number onto which to put the boot code.
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE handle;
|
|
STATUS_CODE status;
|
|
PUCHAR unalignedSectorBuffer,
|
|
sectorBuffer;
|
|
ULONG bps,
|
|
dummy,
|
|
i;
|
|
PCHAR diskName = GetDiskName(Disk);
|
|
|
|
#ifndef max
|
|
#define max(a,b) ((a > b) ? a : b)
|
|
#endif
|
|
|
|
// allocate sector buffer
|
|
|
|
status = LowGetDriveGeometry(diskName, &dummy, &bps, &dummy, &dummy);
|
|
if (status != OK_STATUS) {
|
|
return EC(status);
|
|
}
|
|
if (bps < 512) {
|
|
bps = 512;
|
|
}
|
|
unalignedSectorBuffer = Malloc(2*bps);
|
|
sectorBuffer = (PUCHAR)(((ULONG)unalignedSectorBuffer+bps) & ~(bps-1));
|
|
|
|
// open entire disk (partition 0)
|
|
|
|
if ((status = LowOpenDisk(diskName, &handle)) != OK_STATUS) {
|
|
return EC(status);
|
|
}
|
|
|
|
// read (at least) first 512 bytes
|
|
|
|
status = LowReadSectors(handle, bps, 0, 1, sectorBuffer);
|
|
if (status == OK_STATUS) {
|
|
|
|
|
|
// xfer boot code into sectorBuffer. This avoids changing the
|
|
// disk signature and the partition table information.
|
|
|
|
for (i=0; i<MBOOT_CODE_SIZE; i++) {
|
|
sectorBuffer[i] = x86BootCode[i];
|
|
}
|
|
|
|
status = LowWriteSectors(handle, bps, 0, 1, sectorBuffer);
|
|
}
|
|
|
|
LowCloseDisk(handle);
|
|
|
|
// free the sector buffer
|
|
|
|
Free(unalignedSectorBuffer);
|
|
return EC(status);
|
|
}
|
|
|
|
|
|
#if i386
|
|
|
|
VOID
|
|
MakePartitionActive(
|
|
IN PREGION_DESCRIPTOR DiskRegionArray,
|
|
IN ULONG RegionCount,
|
|
IN ULONG RegionIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the information in the internal structures to indicate
|
|
that the specified partition is active.
|
|
|
|
Arguments:
|
|
|
|
DiskRegionArray
|
|
RegionCount
|
|
RegionIndex
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
unsigned i;
|
|
|
|
for (i=0; i<RegionCount; i++) {
|
|
if (DiskRegionArray[i].RegionType == REGION_PRIMARY) {
|
|
DiskRegionArray[i].Active = FALSE;
|
|
SetPartitionActiveFlag(&DiskRegionArray[i], FALSE);
|
|
}
|
|
}
|
|
DiskRegionArray[RegionIndex].Active = (BOOLEAN)0x80;
|
|
SetPartitionActiveFlag(&DiskRegionArray[RegionIndex], 0x80);
|
|
}
|
|
|
|
#endif
|
|
|
|
VOID
|
|
LoadExistingPageFileInfo(
|
|
IN VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds all pagefiles in the system and updates the internal
|
|
structures.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
SYSTEM_INFO sysInfo;
|
|
UCHAR genericBuffer[0x10000];
|
|
PSYSTEM_PAGEFILE_INFORMATION pageFileInfo;
|
|
ANSI_STRING ansiPageFileName;
|
|
PPAGEFILE_LOCATION pageFileListEntry;
|
|
PCHAR p;
|
|
|
|
GetSystemInfo(&sysInfo);
|
|
|
|
status = NtQuerySystemInformation(SystemPageFileInformation,
|
|
genericBuffer,
|
|
sizeof(genericBuffer),
|
|
NULL);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
// It's possible that this call will fail if the
|
|
// the system is running without ANY paging files.
|
|
|
|
return;
|
|
}
|
|
|
|
pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION) genericBuffer;
|
|
|
|
for (;;) {
|
|
|
|
RtlUnicodeStringToAnsiString(&ansiPageFileName,
|
|
&pageFileInfo->PageFileName,
|
|
TRUE);
|
|
|
|
// Since the format of the pagefile name generally
|
|
// looks something like "\DosDevices\h:\pagefile.sys",
|
|
// just use the first character before the colon
|
|
// and assume that's the drive letter.
|
|
|
|
p = strchr(_strlwr(ansiPageFileName.Buffer), ':');
|
|
|
|
if ((p-- != NULL) && (*p >= 'a') && (*p <= 'z')) {
|
|
|
|
pageFileListEntry = Malloc(sizeof(PAGEFILE_LOCATION));
|
|
if (pageFileListEntry) {
|
|
if (PagefileHead) {
|
|
pageFileListEntry->Next = PagefileHead;
|
|
} else {
|
|
PagefileHead = pageFileListEntry;
|
|
pageFileListEntry->Next = NULL;
|
|
}
|
|
pageFileListEntry->DriveLetter = *p;
|
|
}
|
|
|
|
}
|
|
|
|
RtlFreeAnsiString(&ansiPageFileName);
|
|
|
|
if (pageFileInfo->NextEntryOffset == 0) {
|
|
break;
|
|
}
|
|
|
|
pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR) pageFileInfo
|
|
+ pageFileInfo->NextEntryOffset);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IsPagefileOnDrive(
|
|
CHAR DriveLetter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walk the page file list and determine if the drive letter given has
|
|
a paging file. NOTE: The assumption is that drive letters that
|
|
contain paging files can never get changed during the execution of
|
|
Disk Administrator. Therefore this list is never updated, but
|
|
can be used during the execution of Disk Administrator.
|
|
|
|
Arguments:
|
|
|
|
DriveLetter - the drive in question.
|
|
|
|
Return Value:
|
|
|
|
TRUE if this drive contains a page file.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPAGEFILE_LOCATION pageFileListEntry = PagefileHead;
|
|
|
|
while (pageFileListEntry) {
|
|
if (pageFileListEntry->DriveLetter == DriveLetter) {
|
|
return TRUE;
|
|
}
|
|
pageFileListEntry = pageFileListEntry->Next;
|
|
}
|
|
return FALSE;
|
|
}
|