/*++
Copyright (c) 1990-1993 Microsoft Corporation
Module Name:
fdmisc.c
Abstract:
Miscellaneous routines for NT fdisk.
Author:
Ted Miller (tedm) 7-Jan-1992
Modifications:
13-Dec-1993 (bobri) CdRom initialization support.
--*/
#include "fdisk.h"
#include <process.h>
extern HWND InitDlg;
extern BOOLEAN StartedAsIcon;
BOOL
AllDisksOffLine(
VOID
)
/*++
Routine Description:
Determine whether all hard disks are off line.
Arguments:
None.
Return Value:
TRUE if all disks off-line, false otherwise.
--*/
{
ULONG i;
FDASSERT(DiskCount);
for (i=0; i<DiskCount; i++) {
if (!IsDiskOffLine(i)) {
return FALSE;
}
}
return TRUE;
}
VOID
FdShutdownTheSystem(
VOID
)
/*++
Routine Description:
This routine attempts to update the caller privilege, then shutdown the
Windows NT system. If it fails it prints a warning dialog. If it
succeeds then it doesn't return to the caller.
Arguments:
None
Return Value:
None
--*/
{
NTSTATUS Status;
BOOLEAN PreviousPriv;
InfoDialog(MSG_MUST_REBOOT);
SetCursor(hcurWait);
WriteProfile();
// Enable shutdown privilege
Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
TRUE,
FALSE,
&PreviousPriv);
#if DBG
if (Status) {
DbgPrint("DISKMAN: Status %lx attempting to enable shutdown privilege\n",Status);
}
#endif
Sleep(3000);
if (!ExitWindowsEx(EWX_REBOOT,(DWORD)(-1))) {
WarningDialog(MSG_COULDNT_REBOOT);
}
}
LPTSTR
LoadAString(
IN DWORD StringID
)
/*++
Routine Description:
Loads a string from the resource file and allocates a buffer of exactly
the right size to hold it.
Arguments:
StringID - resource ID of string to load
Return Value:
pointer to buffer. If string is not found, the first
(and only) char in the returned buffer will be 0.
--*/
{
TCHAR text[500];
LPTSTR buffer;
text[0] = 0;
LoadString(hModule, StringID, text, sizeof(text)/sizeof(TCHAR));
buffer = Malloc((lstrlen(text)+1)*sizeof(TCHAR));
lstrcpy(buffer, text);
return buffer;
}
PWSTR
LoadWString(
IN DWORD StringID
)
/*++
Routine Description:
Loads a wide-char string from the resource file and allocates a
buffer of exactly the right size to hold it.
Arguments:
StringID - resource ID of string to load
Return Value:
pointer to buffer. If string is not found, the first
(and only) char in the returned buffer will be 0.
--*/
{
WCHAR text[500];
PWSTR buffer;
text[0] = 0;
LoadStringW(hModule, StringID, text, sizeof(text)/sizeof(WCHAR));
buffer = Malloc((lstrlenW(text)+1)*sizeof(WCHAR));
lstrcpyW(buffer, text);
return buffer;
}
int
GetHeightFromPoints(
IN int Points
)
/*++
Routine Description:
This routine calculates the height of a font given a point value.
The calculation is based on 72 points per inch and the display's
pixels/inch device capability.
Arguments:
Points - number of points
Return Value:
pixel count (negative and therefore suitable for passing to
CreateFont())
--*/
{
HDC hdc = GetDC(NULL);
int height = MulDiv(-Points, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(NULL, hdc);
return height;
}
VOID
UnicodeHack(
IN PCHAR Source,
OUT LPTSTR Dest
)
/*++
Routine Description:
Given a non-Unicode ASCII string, this routine will either convert it
to Unicode or copy it, depending on the current definition of TCHAR.
The 'conversion' is a simple hack that casts to TCHAR.
Arguments:
Source - source (ansi ascii) string
Dest - destination string or wide string
Return Value:
None.
--*/
{
int i;
int j = lstrlen(Source);
for (i=0; i<=j; i++) {
Dest[i] = (TCHAR)(UCHAR)Source[i];
}
}
VOID
_RetreiveAndFormatMessage(
IN DWORD Msg,
OUT LPTSTR Buffer,
IN DWORD BufferSize,
IN va_list arglist
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DWORD x;
TCHAR text[500];
// get message from system or app msg file.
x = FormatMessage( Msg >= MSG_FIRST_FDISK_MSG
? FORMAT_MESSAGE_FROM_HMODULE
: FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
Msg,
0,
Buffer,
BufferSize,
&arglist);
if (!x) { // couldn't find message
LoadString(hModule,
Msg >= MSG_FIRST_FDISK_MSG ? IDS_NOT_IN_APP_MSG_FILE : IDS_NOT_IN_SYS_MSG_FILE,
text,
sizeof(text)/sizeof(TCHAR));
wsprintf(Buffer, text, Msg);
}
}
DWORD
CommonDialog(
IN DWORD MsgCode,
IN LPTSTR Caption,
IN DWORD Flags,
IN va_list arglist
)
/*++
Routine Description:
Simple dialog routine to get dialogs out of the resource
for the program and run them as a message box.
Arguments:
MsgCode - dialog message code
Caption - message box caption
Flags - standard message box flags
arglist - list to be given when pulling the message text
Return Value:
The MessageBox() return value
--*/
{
TCHAR MsgBuf[MESSAGE_BUFFER_SIZE];
if (!StartedAsIcon) {
// Flags |= MB_SETFOREGROUND;
}
if (InitDlg) {
PostMessage(InitDlg,
(WM_USER + 1),
0,
0);
InitDlg = (HWND) 0;
}
_RetreiveAndFormatMessage(MsgCode, MsgBuf, sizeof(MsgBuf), arglist);
return MessageBox(GetActiveWindow(), MsgBuf, Caption, Flags);
}
VOID
ErrorDialog(
IN DWORD ErrorCode,
...
)
/*++
-Routine Description:
This routine retreives a message from the app or system message file
and displays it in a message box.
Arguments:
ErrorCode - number of message
... - strings for insertion into message
Return Value:
None.
--*/
{
va_list arglist;
va_start(arglist, ErrorCode);
CommonDialog(ErrorCode, NULL, MB_ICONHAND | MB_OK | MB_SYSTEMMODAL, arglist);
va_end(arglist);
}
VOID
WarningDialog(
IN DWORD MsgCode,
...
)
/*++
Routine Description:
This routine retreives a message from the app or system message file
and displays it in a message box.
Arguments:
MsgCode - number of message
... - strings for insertion into message
Return Value:
None.
--*/
{
TCHAR Caption[100];
va_list arglist;
va_start(arglist, MsgCode);
LoadString(hModule, IDS_APPNAME, Caption, sizeof(Caption)/sizeof(TCHAR));
CommonDialog(MsgCode, Caption, MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL, arglist);
va_end(arglist);
}
DWORD
ConfirmationDialog(
IN DWORD MsgCode,
IN DWORD Flags,
...
)
/*++
Routine Description:
Support for a simple confirmation dialog
Arguments:
MsgCode - resource code for message
Flags - dialog flags
Return Value:
Result from the CommonDialog() performed.
--*/
{
TCHAR Caption[100];
DWORD x;
va_list arglist;
va_start(arglist, Flags);
LoadString(hModule, IDS_CONFIRM, Caption, sizeof(Caption)/sizeof(TCHAR));
x = CommonDialog(MsgCode, Caption, Flags | MB_TASKMODAL, arglist);
va_end(arglist);
return x;
}
VOID
InfoDialog(
IN DWORD MsgCode,
...
)
/*++
Routine Description:
This routine retreives a message from the app or system message file
and displays it in a message box.
Arguments:
MsgCode - number of message
... - strings for insertion into message
Return Value:
None.
--*/
{
TCHAR Caption[100];
va_list arglist;
va_start(arglist, MsgCode);
LoadString(hModule, IDS_APPNAME, Caption, sizeof(Caption)/sizeof(TCHAR));
CommonDialog(MsgCode, Caption, MB_ICONINFORMATION | MB_OK | MB_TASKMODAL, arglist);
va_end(arglist);
}
PREGION_DESCRIPTOR
LocateRegionForFtObject(
IN PFT_OBJECT FtObject
)
/*++
Routine Description:
Given an FtObject, find the associated region descriptor
Arguments:
FtObject - the ft object to search for.
Return Value:
NULL - no descriptor found
!NULL - a pointer to the region descriptor for the FT object
++*/
{
PDISKSTATE diskState;
PREGION_DESCRIPTOR regionDescriptor;
DWORD disk,
region;
PPERSISTENT_REGION_DATA regionData;
for (disk = 0; disk < DiskCount; disk++) {
diskState = Disks[disk];
for (region = 0; region < diskState->RegionCount; region++) {
regionDescriptor = &diskState->RegionArray[region];
regionData = PERSISTENT_DATA(regionDescriptor);
if (regionData) {
if (regionData->FtObject == FtObject) {
return regionDescriptor;
}
}
}
}
return NULL;
}
VOID
InitVolumeLabelsAndTypeNames(
VOID
)
/*++
Routine Description:
Determine the volume label and type name for each significant
(non-extended, non-free, recognized) partition.
Assumes that persistent data has already been set up, and drive letters
determined.
Arguments:
None.
Return Value:
None.
--*/
{
DWORD disk,
region;
PDISKSTATE ds;
PREGION_DESCRIPTOR rd;
PPERSISTENT_REGION_DATA regionData;
WCHAR diskName[4];
WCHAR volumeLabel[100];
WCHAR typeName[100];
UINT errorMode;
lstrcpyW(diskName, L"x:\\");
for (disk=0; disk<DiskCount; disk++) {
ds = Disks[disk];
for (region=0; region<ds->RegionCount; region++) {
rd = &ds->RegionArray[region];
if (DmSignificantRegion(rd)) {
// If the region has a drive letter, use the drive letter
// to get the info via the Windows API. Otherwise we'll
// have to use the NT API.
regionData = PERSISTENT_DATA(rd);
if (!regionData) {
continue;
}
if ((regionData->DriveLetter == NO_DRIVE_LETTER_YET)
|| (regionData->DriveLetter == NO_DRIVE_LETTER_EVER)) {
PWSTR tempLabel,
tempName;
// No drive letter. Use NT API.
// If this is an FT set use the zero member disk for the
// call so all members get the right type and label
if (regionData->FtObject) {
PFT_OBJECT searchFtObject;
// Want to get rd pointing to the zeroth member
searchFtObject = regionData->FtObject->Set->Member0;
// Now search regions for this match
rd = LocateRegionForFtObject(searchFtObject);
if (!rd) {
continue;
}
}
if (GetVolumeLabel(rd->Disk, rd->PartitionNumber, &tempLabel) == NO_ERROR) {
lstrcpyW(volumeLabel, tempLabel);
Free(tempLabel);
} else {
*volumeLabel = 0;
}
if (GetTypeName(rd->Disk, rd->PartitionNumber, &tempName) == NO_ERROR) {
lstrcpyW(typeName, tempName);
Free(tempName);
} else {
lstrcpyW(typeName, wszUnknown);
}
} else {
// Use Windows API.
diskName[0] = (WCHAR)(UCHAR)regionData->DriveLetter;
errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
if (!GetVolumeInformationW(diskName, volumeLabel, sizeof(volumeLabel)/2, NULL, NULL, NULL, typeName, sizeof(typeName)/2)) {
lstrcpyW(typeName, wszUnknown);
*volumeLabel = 0;
}
SetErrorMode(errorMode);
}
if (!lstrcmpiW(typeName, L"raw")) {
lstrcpyW(typeName, wszUnknown);
}
regionData->TypeName = Malloc((lstrlenW(typeName) + 1) * sizeof(WCHAR));
regionData->VolumeLabel = Malloc((lstrlenW(volumeLabel) + 1) * sizeof(WCHAR));
lstrcpyW(regionData->TypeName, typeName);
lstrcpyW(regionData->VolumeLabel, volumeLabel);
}
}
}
}
VOID
DetermineRegionInfo(
IN PREGION_DESCRIPTOR Region,
OUT PWSTR *TypeName,
OUT PWSTR *VolumeLabel,
OUT PWCH DriveLetter
)
/*++
Routine Description:
For a given region, fetch the persistent data, appropriately modified
depending on whether the region is used or free, recognized, etc.
Arguments:
Region - supplies a pointer to the region whose data is to be fetched.
TypeName - receives a pointer to the type name. If the region is
unrecognized, the type is determined based on the system id of
the partition.
VolumeLabel - receives a pointer to the volume label. If the region is
free space or unrecognized, the volume label is "".
DriveLetter - receices the drive letter. If the region is free space
or unrecognized, the drive letter is ' ' (space).
Return Value:
None.
--*/
{
PWSTR typeName,
volumeLabel;
WCHAR driveLetter;
PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
if (DmSignificantRegion(Region)) {
typeName = regionData->TypeName;
volumeLabel = regionData->VolumeLabel;
driveLetter = (WCHAR)(UCHAR)regionData->DriveLetter;
if ((driveLetter == NO_DRIVE_LETTER_YET) || (driveLetter == NO_DRIVE_LETTER_EVER)) {
driveLetter = L' ';
}
} else {
typeName = GetWideSysIDName(Region->SysID);
volumeLabel = L"";
driveLetter = L' ';
}
*TypeName = typeName;
*VolumeLabel = volumeLabel;
*DriveLetter = driveLetter;
}
PREGION_DESCRIPTOR
RegionFromFtObject(
IN PFT_OBJECT FtObject
)
/*++
Routine Description:
Given an ft object, determine which region it belongs to. The algorithm
is brute force -- look at each region on each disk until a match is found.
Arguments:
FtObject - ft member whose region is to be located.
Return Value:
pointer to region descriptor
--*/
{
PREGION_DESCRIPTOR reg;
DWORD region,
disk;
PDISKSTATE ds;
for (disk=0; disk<DiskCount; disk++) {
ds = Disks[disk];
for (region=0; region<ds->RegionCount; region++) {
reg = &ds->RegionArray[region];
if (DmSignificantRegion(reg) && (GET_FT_OBJECT(reg) == FtObject)) {
return reg;
}
}
}
return NULL;
}
//
// For each drive letter, these arrays hold the disk and partition number
// the the drive letter is linked to.
//
#define M1 ((unsigned)(-1))
unsigned
DriveLetterDiskNumbers[26] = { M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,
M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1
},
DriveLetterPartitionNumbers[24] = { M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,
M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1
};
#undef M1
//
// Drive letter usage map. Bit n set means that drive letter 'C'+n is in use.
//
ULONG DriveLetterUsageMap = 0;
#define DRIVELETTERBIT(letter) (1 << (unsigned)((UCHAR)letter-(UCHAR)'C'))
#define SetDriveLetterUsed(letter) DriveLetterUsageMap |= DRIVELETTERBIT(letter)
#define SetDriveLetterFree(letter) DriveLetterUsageMap &= (~DRIVELETTERBIT(letter))
#define IsDriveLetterUsed(letter) (DriveLetterUsageMap & DRIVELETTERBIT(letter))
CHAR
GetAvailableDriveLetter(
VOID
)
/*++
Routine Description:
Scan the drive letter usage bitmap and return the next available
drive letter. May also mark the drivee letter used.
Arguments:
None.
Return Value:
The next available drive letter, or 0 if all are used.
--*/
{
CHAR driveLetter;
FDASSERT(!(DriveLetterUsageMap & 0xff000000));
for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
if (!IsDriveLetterUsed(driveLetter)) {
return driveLetter;
}
}
return 0;
}
VOID
MarkDriveLetterUsed(
IN CHAR DriveLetter
)
/*++
Routine Description:
Given an ASCII drive letter, mark it in the usage map as being used.
Arguments:
DriveLetter - the letter to mark
Return Value:
None
--*/
{
FDASSERT(!(DriveLetterUsageMap & 0xff000000));
if ((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER)) {
SetDriveLetterUsed(DriveLetter);
}
}
VOID
MarkDriveLetterFree(
IN CHAR DriveLetter
)
/*++
Routine Description:
Given a drive letter, remove it from the usage map, thereby making it available
for reuse.
Arguments:
Drive Letter - the letter to free
Return Value:
None
--*/
{
FDASSERT(!(DriveLetterUsageMap & 0xff000000));
if ((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER)) {
SetDriveLetterFree(DriveLetter);
}
}
BOOL
DriveLetterIsAvailable(
IN CHAR DriveLetter
)
/*++
Routine Description:
Determine if the drive letter given is available for use.
Arguments:
DriveLetter - the letter to check in the usage map
Return Value:
TRUE if it is free and can be used.
FALSE if it is currently in use.
--*/
{
FDASSERT(!(DriveLetterUsageMap & 0xff000000));
FDASSERT((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER));
return !IsDriveLetterUsed(DriveLetter);
}
BOOL
AllDriveLettersAreUsed(
VOID
)
/*++
Routine Description:
Determine if all possible drive letters are in use.
Arguments:
None
Return Value:
TRUE if all letters are in use - FALSE otherwise
--*/
{
FDASSERT(!(DriveLetterUsageMap & 0xff000000));
return(DriveLetterUsageMap == 0x00ffffff);
}
ULONG
GetDiskNumberFromDriveLetter(
IN CHAR DriveLetter
)
/*++
Routine Description:
Given a drive letter return the disk number that contains the partition
that is the drive letter.
Arguments:
DriveLetter - the drive letter to check.
Return Value:
-1 if the letter is invalid.
The disk number for the drive letter if it is valid.
--*/
{
DriveLetter = toupper( DriveLetter );
if (DriveLetter >= 'C' && DriveLetter <= 'Z') {
return DriveLetterDiskNumbers[ DriveLetter - 'C' ];
} else {
return (ULONG)(-1);
}
}
ULONG
GetPartitionNumberFromDriveLetter(
IN CHAR DriveLetter
)
/*++
Routine Description:
Given a drive letter return the numeric value for the partition that
the letter is associated with.
Arguments:
DriveLetter - the letter in question.
Return Value:
-1 if letter is invalid
Partition number for partition that is the drive letter
--*/
{
DriveLetter = toupper( DriveLetter );
if (DriveLetter >= 'C' && DriveLetter <= 'Z') {
return DriveLetterPartitionNumbers[ DriveLetter - 'C' ];
} else {
return (ULONG)(-1);
}
}
CHAR
LocateDriveLetterFromDiskAndPartition(
IN ULONG Disk,
IN ULONG Partition
)
/*++
Routine Description:
Given a disk and partition number return the drive letter assigned to it.
Arguments:
Disk - the disk index
Partition - the partition index
Return Value:
The drive letter for the specific partition or
NO_DRIVE_LETTER_YET if it is not assigned a letter.
--*/
{
unsigned i;
for (i=0; i<24; i++) {
if (Disk == DriveLetterDiskNumbers[i] &&
Partition == DriveLetterPartitionNumbers[i]) {
return((CHAR)(i+(unsigned)(UCHAR)'C'));
}
}
return NO_DRIVE_LETTER_YET;
}
CHAR
LocateDriveLetter(
IN PREGION_DESCRIPTOR Region
)
/*++
Routine Description:
Return the drive letter associated to a region.
Arguments:
Region - the region wanted.
Return Value:
The drive letter or NO_DRIVE_LETTER_YET
--*/
{
PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
if (regionData) {
if (regionData->FtObject) {
if (regionData->DriveLetter) {
return regionData->DriveLetter;
}
}
}
return LocateDriveLetterFromDiskAndPartition(Region->Disk,
Region->OriginalPartitionNumber);
}
#define IsDigitW(digit) (((digit) >= L'0') && ((digit) <= L'9'))
VOID
InitializeDriveLetterInfo(
VOID
)
/*++
Routine Description:
Initialze all of the external support structures for drive letter maintainence.
Arguments:
None
Return Value:
None
--*/
{
WCHAR DriveLetterW;
CHAR DriveLetter = '\0';
PWSTR LinkTarget;
WCHAR DosDevicesName[sizeof(L"\\DosDevices\\A:")];
int DiskNo,
PartNo;
PWSTR Pattern,
String;
DWORD x,
ec;
PFT_OBJECT FtObject;
PFT_OBJECT_SET FtSet;
PREGION_DESCRIPTOR Region;
// Construct list of drives with pagefiles
LoadExistingPageFileInfo();
// Initialize network information.
NetworkInitialize();
// For each drive letter c-z, query the symbolic link.
for (DriveLetterW=L'C'; DriveLetterW<=L'Z'; DriveLetterW++) {
wsprintfW(DosDevicesName, L"%ws%wc:", L"\\DosDevices\\", DriveLetterW);
if ((ec = GetDriveLetterLinkTarget(DosDevicesName, &LinkTarget)) == NO_ERROR) {
// Check if it is a Cdrom
if (_wcsnicmp(LinkTarget, L"\\Device\\CdRom", 13) == 0) {
// Save the information on this CdRom away
CdRomAddDevice(LinkTarget, DriveLetterW);
}
// The drive letter is used because it is linked to something,
// even if we can't figure out what. So mark it used here.
SetDriveLetterUsed(DriveLetterW);
CharUpperW(LinkTarget);
Pattern = L"\\DEVICE\\HARDDISK";
String = LinkTarget;
// Attempt to match the '\device\harddisk' part
for (x=0; x < (sizeof(L"\\DEVICE\\HARDDISK") / sizeof(WCHAR)) - 1; x++) {
if (*Pattern++ != *String++) {
goto next_letter;
}
}
// Now get the hard disk #
if (!IsDigitW(*String)) {
continue;
}
DiskNo = 0;
while (IsDigitW(*String)) {
DiskNo = (DiskNo * 10) + (*String - L'0');
*String++;
}
// Attempt to match the '\partition' part
Pattern = L"\\PARTITION";
for (x=0; x < (sizeof(L"\\PARTITION") / sizeof(WCHAR)) - 1; x++) {
if (*Pattern++ != *String++) {
goto next_letter;
}
}
// Now get the partition #, which cannot be 0
PartNo = 0;
while (IsDigitW(*String)) {
PartNo = (PartNo * 10) + (*String - L'0');
*String++;
}
if (!PartNo) {
continue;
}
// Make sure there is nothing left in the link target's name
if (*String) {
continue;
}
// We understand the link target. Store the disk and partition.
DriveLetterDiskNumbers[DriveLetterW-L'C'] = DiskNo;
DriveLetterPartitionNumbers[DriveLetterW-L'C'] = PartNo;
} else {
if (ec == ERROR_ACCESS_DENIED) {
ErrorDialog(MSG_ACCESS_DENIED);
// BUGBUG When system and workstation manager are the same
// thing, then we'd never have gotten here. We can't just
// send a WM_DESTROY message to hwndFrame because we're not
// in the message loop here -- we end up doing a bunch of
// processing before the quit message is pulled our of the
// queue. So just exit.
SendMessage(hwndFrame,WM_DESTROY,0,0);
exit(1);
}
}
next_letter:
{}
}
// Now for each non-ft, significant region on each disk, figure out its
// drive letter.
for (x=0; x<DiskCount; x++) {
PDISKSTATE ds = Disks[x];
unsigned reg;
for (reg=0; reg<ds->RegionCount; reg++) {
PREGION_DESCRIPTOR region = &ds->RegionArray[reg];
if (DmSignificantRegion(region)) {
// Handle drive letters for FT sets specially.
if (!GET_FT_OBJECT(region)) {
PERSISTENT_DATA(region)->DriveLetter = LocateDriveLetter(region);
}
}
}
// If this is a removable disk, record the reserved drive
// letter for that disk.
if (IsDiskRemovable[x]) {
RemovableDiskReservedDriveLetters[x] = LocateDriveLetterFromDiskAndPartition(x, 1);
} else {
RemovableDiskReservedDriveLetters[x] = NO_DRIVE_LETTER_YET;
}
}
// Now handle ft sets. For each set, loop through the objects twice.
// On the first pass, figure out which object actually is linked to the
// drive letter. On the second pass, assign the drive letter found to
// each of the objects in the set.
for (FtSet = FtObjects; FtSet; FtSet = FtSet->Next) {
for (FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next) {
Region = RegionFromFtObject(FtObject);
if (Region) {
if ((DriveLetter = LocateDriveLetter(Region)) != NO_DRIVE_LETTER_YET) {
break;
}
}
}
for (FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next) {
Region = RegionFromFtObject(FtObject);
if (Region) {
PERSISTENT_DATA(Region)->DriveLetter = DriveLetter;
}
}
}
}
#if DBG
VOID
FdiskAssertFailedRoutine(
IN char *Expression,
IN char *FileName,
IN int LineNumber
)
/*++
Routine Description:
Routine that is called when an assertion fails in the debug version.
Throw up a list box giving appriopriate information and terminate
the program.
Arguments:
Source - source (ansi ascii) string
Dest - destination string or wide string
Return Value:
None.
--*/
{
char text[500];
wsprintf(text,
"Line #%u in File '%s'\n[%s]\n\nClick OK to exit.",
LineNumber,
FileName,
Expression
);
MessageBoxA(NULL,text,"Assertion Failure",MB_TASKMODAL | MB_OK);
exit(1);
}
#include <stdio.h>
PVOID LogFile;
int LoggingLevel = 1000;
VOID
InitLogging(
VOID
)
/*++
Routine Description:
Open the log file for debug logging.
Arguments:
None
Return Value:
None
--*/
{
LogFile = (PVOID)fopen("c:\\fdisk.log","wt");
if(LogFile == NULL) {
MessageBox(GetActiveWindow(),"Can't open log file; logging turned off","DEBUG",MB_SYSTEMMODAL|MB_OK);
LoggingLevel = -1;
}
}
VOID
FdLog(
IN int Level,
IN PCHAR FormatString,
...
)
/*++
Routine Description:
Write a line into the log file for debugging.
Arguments:
Debug level and "printf" like argument string.
Return Value:
None
--*/
{
va_list arglist;
if(Level <= LoggingLevel) {
va_start(arglist,FormatString);
if(vfprintf((FILE *)LogFile,FormatString,arglist) < 0) {
LoggingLevel = -1;
MessageBox(GetActiveWindow(),"Error writing to log file; logging turned off","DEBUG",MB_SYSTEMMODAL|MB_OK);
fclose((FILE *)LogFile);
} else {
fflush((FILE *)LogFile);
}
va_end(arglist);
}
}
VOID
LOG_DISK_REGISTRY(
IN PCHAR RoutineName,
IN PDISK_REGISTRY DiskRegistry
)
/*++
Routine Description:
Log what was in the disk registry into the debugging log file.
Arguments:
RoutineName - calling routines name
DiskRegistry - registry information for disks
Return Value:
None
--*/
{
ULONG i;
PDISK_DESCRIPTION diskDesc;
FDLOG((2,"%s: %u disks; registry info follows:\n",RoutineName,DiskRegistry->NumberOfDisks));
diskDesc = DiskRegistry->Disks;
for(i=0; i<DiskRegistry->NumberOfDisks; i++) {
LOG_ONE_DISK_REGISTRY_DISK_ENTRY(NULL,diskDesc);
diskDesc = (PDISK_DESCRIPTION)&diskDesc->Partitions[diskDesc->NumberOfPartitions];
}
}
VOID
LOG_ONE_DISK_REGISTRY_DISK_ENTRY(
IN PCHAR RoutineName OPTIONAL,
IN PDISK_DESCRIPTION DiskDescription
)
/*++
Routine Description:
This routine walks through the partition information from
the registry for a single disk and writes lines in the
debugging log file.
Arguments:
RoutineName - the name of the calling routine
DiskDescription - the disk description portion of the registry
Return Value:
None
--*/
{
USHORT j;
PDISK_PARTITION partDesc;
PDISK_DESCRIPTION diskDesc = DiskDescription;
if(ARGUMENT_PRESENT(RoutineName)) {
FDLOG((2,"%s: disk registry entry follows:\n",RoutineName));
}
FDLOG((2," Disk signature : %08lx\n",diskDesc->Signature));
FDLOG((2," Partition count: %u\n",diskDesc->NumberOfPartitions));
if(diskDesc->NumberOfPartitions) {
FDLOG((2," # Dr FtTyp FtGrp FtMem Start Length\n"));
}
for(j=0; j<diskDesc->NumberOfPartitions; j++) {
CHAR dr1,dr2;
partDesc = &diskDesc->Partitions[j];
if(partDesc->AssignDriveLetter) {
if(partDesc->DriveLetter) {
dr1 = partDesc->DriveLetter;
dr2 = ':';
} else {
dr1 = dr2 = ' ';
}
} else {
dr1 = 'n';
dr2 = 'o';
}
FDLOG((2,
" %02u %c%c %-5u %-5u %-5u %08lx:%08lx %08lx:%08lx\n",
partDesc->LogicalNumber,
dr1,dr2,
partDesc->FtType,
partDesc->FtGroup,
partDesc->FtMember,
partDesc->StartingOffset.HighPart,
partDesc->StartingOffset.LowPart,
partDesc->Length.HighPart,
partDesc->Length.LowPart
));
}
}
VOID
LOG_DRIVE_LAYOUT(
IN PDRIVE_LAYOUT_INFORMATION DriveLayout
)
/*++
Routine Description:
Write the drive layout into the debugging log file.
Arguments:
DriveLayout - the layout to write
Return Value:
None
--*/
{
ULONG i;
FDLOG((2," Disk signature : %08lx\n",DriveLayout->Signature));
FDLOG((2," Partition count: %u\n",DriveLayout->PartitionCount));
for(i=0; i<DriveLayout->PartitionCount; i++) {
if(!i) {
FDLOG((2," ID Active Recog Start Size Hidden\n"));
}
FDLOG((2,
" %02x %s %s %08lx:%08lx %08lx:%08lx %08lx\n",
DriveLayout->PartitionEntry[i].PartitionType,
DriveLayout->PartitionEntry[i].BootIndicator ? "yes" : "no ",
DriveLayout->PartitionEntry[i].RecognizedPartition ? "yes" : "no ",
DriveLayout->PartitionEntry[i].StartingOffset.HighPart,
DriveLayout->PartitionEntry[i].StartingOffset.LowPart,
DriveLayout->PartitionEntry[i].PartitionLength.HighPart,
DriveLayout->PartitionEntry[i].PartitionLength.LowPart,
DriveLayout->PartitionEntry[i].HiddenSectors
));
}
}
#endif