1085 lines
26 KiB
C
1085 lines
26 KiB
C
/*++
|
||
|
||
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;
|
||
}
|