mirror of https://github.com/lianthony/NT4.0
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.
485 lines
14 KiB
485 lines
14 KiB
/** FILE: syspart.c ******** Module Header ********************************
|
|
*
|
|
* Control panel applet for System configuration. This file holds
|
|
* everything to do with finding the system partition where the
|
|
* boot.ini file for x86 systems resides.
|
|
*
|
|
* History:
|
|
* 08-Sep-1994 stevecat Took base routines from TedM's SETUP code
|
|
* 18-Sep-1995 stevecat Ported from SYSTEM.CPL to SYSCPL.CPL
|
|
* 23-Jan-1996 JonPa Ported from NT3.51+ and added out of mem checks
|
|
*
|
|
* Copyright (C) 1994-1996 Microsoft Corporation
|
|
*
|
|
*************************************************************************/
|
|
//==========================================================================
|
|
// Include files
|
|
//==========================================================================
|
|
|
|
// For NT apis
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include <ntdddisk.h>
|
|
|
|
#include <sysdm.h>
|
|
|
|
//==========================================================================
|
|
// Local Definitions
|
|
//==========================================================================
|
|
|
|
|
|
//==========================================================================
|
|
// Typedefs and Structs
|
|
//==========================================================================
|
|
|
|
|
|
//==========================================================================
|
|
// External Declarations
|
|
//==========================================================================
|
|
/* Functions */
|
|
extern void ErrMemDlg( HWND hParent );
|
|
|
|
|
|
//==========================================================================
|
|
// Local Data Declarations
|
|
//==========================================================================
|
|
TCHAR g_szDeviceHarddisk[] = TEXT("\\device\\harddisk");
|
|
#define CCH_DEVICE_HARDDISK (ARRAYSIZE(g_szDeviceHarddisk) - sizeof(TCHAR)) // Ignore size of terminating '\0'
|
|
|
|
//==========================================================================
|
|
// Local Function Prototypes
|
|
//==========================================================================
|
|
|
|
|
|
#ifdef _X86_
|
|
|
|
|
|
BOOL GetPartitionInfo( IN TCHAR Drive,
|
|
OUT PPARTITION_INFORMATION PartitionInfo )
|
|
{
|
|
TCHAR DriveName[] = TEXT("\\\\.\\?:");
|
|
HANDLE hDisk;
|
|
BOOL b;
|
|
DWORD DataSize;
|
|
|
|
DriveName[4] = Drive;
|
|
|
|
hDisk = CreateFile( DriveName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
if( hDisk == INVALID_HANDLE_VALUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
b = DeviceIoControl( hDisk,
|
|
IOCTL_DISK_GET_PARTITION_INFO,
|
|
NULL,
|
|
0,
|
|
PartitionInfo,
|
|
sizeof( PARTITION_INFORMATION ),
|
|
&DataSize,
|
|
NULL );
|
|
|
|
CloseHandle( hDisk );
|
|
|
|
return( b );
|
|
}
|
|
|
|
|
|
UINT MyGetDriveType( IN TCHAR Drive )
|
|
{
|
|
TCHAR DriveNameNt[] = TEXT("\\\\.\\?:");
|
|
TCHAR DriveName[] = TEXT("?:\\");
|
|
HANDLE hDisk;
|
|
BOOL b;
|
|
UINT rc;
|
|
DWORD DataSize;
|
|
DISK_GEOMETRY MediaInfo;
|
|
|
|
//
|
|
// First, get the win32 drive type. If it tells us DRIVE_REMOVABLE,
|
|
// then we need to see whether it's a floppy or hard disk. Otherwise
|
|
// just believe the api.
|
|
//
|
|
//
|
|
|
|
DriveName[0] = Drive;
|
|
|
|
if( (rc = GetDriveType( DriveName ) ) == DRIVE_REMOVABLE )
|
|
{
|
|
DriveNameNt[ 4 ] = Drive;
|
|
|
|
hDisk = CreateFile ( DriveNameNt,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
if( hDisk != INVALID_HANDLE_VALUE )
|
|
{
|
|
b = DeviceIoControl( hDisk,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&MediaInfo,
|
|
sizeof( MediaInfo ),
|
|
&DataSize,
|
|
NULL );
|
|
|
|
//
|
|
// It's really a hard disk if the media type is removable.
|
|
//
|
|
|
|
if( b && ( MediaInfo.MediaType == RemovableMedia ) )
|
|
{
|
|
rc = DRIVE_FIXED;
|
|
}
|
|
|
|
CloseHandle( hDisk );
|
|
}
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
PWSTR ArcPathToNtPath( IN PWSTR ArcPath )
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE ObjectHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING UnicodeString;
|
|
UCHAR Buffer[ 1024 ];
|
|
PWSTR arcPath;
|
|
PWSTR ntPath;
|
|
|
|
//
|
|
// Assume failure
|
|
//
|
|
|
|
ntPath = NULL;
|
|
|
|
arcPath = MemAlloc( LMEM_FIXED, (lstrlen(ArcPath) + 1) * sizeof(WCHAR) + sizeof(TEXT("\\ArcName")) );
|
|
|
|
if (arcPath == NULL)
|
|
return ntPath;
|
|
|
|
lstrcpy( arcPath, TEXT( "\\ArcName\\" ) );
|
|
lstrcat( arcPath, ArcPath );
|
|
|
|
RtlInitUnicodeString( &UnicodeString, arcPath );
|
|
|
|
InitializeObjectAttributes( &Obja,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = NtOpenSymbolicLinkObject( &ObjectHandle,
|
|
READ_CONTROL | SYMBOLIC_LINK_QUERY,
|
|
&Obja );
|
|
|
|
if( NT_SUCCESS( Status ) )
|
|
{
|
|
//
|
|
// Query the object to get the link target.
|
|
//
|
|
|
|
UnicodeString.Buffer = (PWSTR) Buffer;
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = sizeof( Buffer );
|
|
|
|
Status = NtQuerySymbolicLinkObject ( ObjectHandle,
|
|
&UnicodeString,
|
|
NULL );
|
|
|
|
if( NT_SUCCESS( Status ) )
|
|
{
|
|
ntPath = MemAlloc( LMEM_FIXED, UnicodeString.Length + sizeof(WCHAR) );
|
|
if (ntPath != NULL) {
|
|
CopyMemory( ntPath, UnicodeString.Buffer, UnicodeString.Length );
|
|
|
|
ntPath[ UnicodeString.Length / sizeof( WCHAR ) ] = 0;
|
|
}
|
|
}
|
|
|
|
NtClose( ObjectHandle );
|
|
}
|
|
|
|
MemFree( arcPath );
|
|
|
|
return( ntPath );
|
|
}
|
|
|
|
|
|
BOOL AppearsToBeSysPart( IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
|
|
IN WCHAR Drive )
|
|
{
|
|
PARTITION_INFORMATION PartitionInfo,*p;
|
|
BOOL IsPrimary;
|
|
unsigned i;
|
|
HANDLE FindHandle;
|
|
WIN32_FIND_DATA FindData;
|
|
|
|
PTSTR BootFiles[] = { TEXT( "BOOT.INI" ),
|
|
TEXT( "NTLDR" ),
|
|
TEXT( "NTDETECT.COM" ),
|
|
NULL
|
|
};
|
|
|
|
TCHAR FileName[ 64 ];
|
|
|
|
//
|
|
// Get partition information for this partition.
|
|
//
|
|
|
|
if( !GetPartitionInfo( (TCHAR) Drive, &PartitionInfo ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// See if the drive is a primary partition.
|
|
//
|
|
|
|
IsPrimary = FALSE;
|
|
|
|
for( i = 0; i < min( DriveLayout->PartitionCount , 4 ); i++ )
|
|
{
|
|
p = &DriveLayout->PartitionEntry[ i ];
|
|
|
|
if((p->PartitionType != PARTITION_ENTRY_UNUSED)
|
|
&& (p->StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart)
|
|
&& (p->PartitionLength.QuadPart == PartitionInfo.PartitionLength.QuadPart))
|
|
{
|
|
IsPrimary = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !IsPrimary )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Don't rely on the active partition flag. This could easily not be
|
|
// accurate (like user is using os/2 boot manager, for example).
|
|
//
|
|
|
|
//
|
|
// See whether an nt boot files are present on this drive.
|
|
//
|
|
|
|
for( i = 0; BootFiles[ i ]; i++ )
|
|
{
|
|
wsprintf( FileName, TEXT( "%wc:\\%s" ), Drive, BootFiles[ i ] );
|
|
|
|
FindHandle = FindFirstFile( FileName, &FindData );
|
|
|
|
if( FindHandle == INVALID_HANDLE_VALUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
FindClose( FindHandle );
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Determine the system partition on x86 machines.
|
|
//
|
|
// The system partition is the primary partition on the boot disk.
|
|
// Usually this is the active partition on disk 0 and usually it's C:.
|
|
// However the user could have remapped drive letters and generally
|
|
// determining the system partition with 100% accuracy is not possible.
|
|
//
|
|
// The one thing we can be sure of is that the system partition is on
|
|
// the physical hard disk with the arc path multi(0)disk(0)rdisk(0).
|
|
// We can be sure of this because by definition this is the arc path
|
|
// for bios drive 0x80.
|
|
//
|
|
// This routine determines which drive letters represent drives on
|
|
// that physical hard drive, and checks each for the nt boot files.
|
|
// The first drive found with those files is assumed to be the system
|
|
// partition.
|
|
//
|
|
// If for some reason we cannot determine the system partition by the above
|
|
// method, we simply assume it's C:.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// hdlg - Handle of topmost window currently being displayed. (unused)
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Drive letter of system partition.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
TCHAR x86DetermineSystemPartition( IN HWND hdlg )
|
|
{
|
|
BOOL GotIt;
|
|
PWSTR NtDevicePath;
|
|
WCHAR Drive;
|
|
WCHAR DriveName[ 3 ];
|
|
WCHAR Buffer[ 512 ];
|
|
DWORD NtDevicePathLen;
|
|
PWSTR p;
|
|
DWORD PhysicalDriveNumber;
|
|
HANDLE hDisk;
|
|
BOOL b;
|
|
DWORD DataSize;
|
|
PVOID DriveLayout;
|
|
DWORD DriveLayoutSize;
|
|
|
|
DriveName[1] = TEXT( ':' );
|
|
DriveName[2] = 0;
|
|
|
|
GotIt = FALSE;
|
|
|
|
//
|
|
// The system partition must be on multi(0)disk(0)rdisk(0)
|
|
//
|
|
|
|
if( NtDevicePath = ArcPathToNtPath( TEXT( "multi(0)disk(0)rdisk(0)" ) ) )
|
|
{
|
|
//
|
|
// The arc path for a disk device is usually linked
|
|
// to partition0. Get rid of the partition part of the name.
|
|
//
|
|
|
|
CharLowerW( NtDevicePath );
|
|
|
|
if( p = StrStr( NtDevicePath, TEXT( "\\partition" ) ) )
|
|
{
|
|
*p = 0;
|
|
}
|
|
|
|
NtDevicePathLen = lstrlenW( NtDevicePath );
|
|
|
|
//
|
|
// Determine the physical drive number of this drive.
|
|
// If the name is not of the form \device\harddiskx then
|
|
// something is very wrong.
|
|
//
|
|
|
|
if( IntlStrEqN(NtDevicePath, g_szDeviceHarddisk, CCH_DEVICE_HARDDISK) )
|
|
{
|
|
PhysicalDriveNumber = StringToInt( NtDevicePath + CCH_DEVICE_HARDDISK );
|
|
|
|
wsprintfW( Buffer, TEXT( "\\\\.\\PhysicalDrive%u" ), PhysicalDriveNumber );
|
|
|
|
//
|
|
// Get drive layout info for this physical disk.
|
|
//
|
|
|
|
hDisk = CreateFileW( Buffer,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
if( hDisk != INVALID_HANDLE_VALUE )
|
|
{
|
|
//
|
|
// Get partition information.
|
|
//
|
|
|
|
b = FALSE;
|
|
DriveLayoutSize = 1024;
|
|
|
|
do {
|
|
DriveLayout = MemAlloc( LMEM_FIXED, DriveLayoutSize );
|
|
|
|
// Out of memory
|
|
if (DriveLayout == NULL)
|
|
break;
|
|
|
|
b = DeviceIoControl( hDisk,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
NULL,
|
|
0,
|
|
DriveLayout,
|
|
DriveLayoutSize,
|
|
&DataSize,
|
|
NULL );
|
|
|
|
if( !b && ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) )
|
|
{
|
|
DriveLayoutSize += 1024;
|
|
MemFree( DriveLayout );
|
|
}
|
|
} while (!b && (GetLastError() == ERROR_INSUFFICIENT_BUFFER));
|
|
|
|
CloseHandle( hDisk );
|
|
|
|
if( b )
|
|
{
|
|
//
|
|
// The system partition can only be a drive that is on
|
|
// this disk. We make this determination by looking at NT drive names
|
|
// for each drive letter and seeing if the nt equivalent of
|
|
// multi(0)disk(0)rdisk(0) is a prefix.
|
|
//
|
|
|
|
for( Drive = TEXT( 'C' ); Drive <= TEXT( 'Z' ); Drive++)
|
|
{
|
|
if (MyGetDriveType( (TCHAR) Drive ) == DRIVE_FIXED )
|
|
{
|
|
DriveName[0] = Drive;
|
|
|
|
if( QueryDosDeviceW( DriveName, Buffer, sizeof( Buffer ) / sizeof( WCHAR ) ) )
|
|
{
|
|
if (IntlStrEqNI(NtDevicePath, Buffer, NtDevicePathLen))
|
|
{
|
|
//
|
|
// Now look to see whether there's
|
|
// an nt boot sector and
|
|
// boot files on this drive.
|
|
//
|
|
if( AppearsToBeSysPart( DriveLayout, Drive ) )
|
|
{
|
|
GotIt = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DriveLayout != NULL) {
|
|
MemFree( DriveLayout );
|
|
}
|
|
}
|
|
}
|
|
|
|
MemFree( NtDevicePath );
|
|
}
|
|
|
|
|
|
return( GotIt ? (TCHAR) Drive : TEXT( 'C' ) );
|
|
}
|
|
|
|
#endif // _x86_
|