Source code of Windows XP (NT5)
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.

293 lines
7.6 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. syspart.c
  5. Abstract:
  6. Routines to determine the system partition on x86 machines.
  7. Author:
  8. Ted Miller (tedm) 30-June-1994
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #pragma hdrstop
  13. BOOL
  14. AppearsToBeSysPart(
  15. IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
  16. IN WCHAR Drive
  17. )
  18. {
  19. PARTITION_INFORMATION PartitionInfo,*p;
  20. BOOL IsPrimary;
  21. unsigned i;
  22. HANDLE FindHandle;
  23. WIN32_FIND_DATA FindData;
  24. PWSTR BootFiles[] = { L"BOOT.INI",
  25. L"NTLDR",
  26. L"NTDETECT.COM",
  27. NULL
  28. };
  29. WCHAR FileName[64];
  30. //
  31. // Get partition information for this partition.
  32. //
  33. if(!GetPartitionInfo(Drive,&PartitionInfo)) {
  34. return(FALSE);
  35. }
  36. //
  37. // See if the drive is a primary partition.
  38. //
  39. IsPrimary = FALSE;
  40. for(i=0; i<min(DriveLayout->PartitionCount,4); i++) {
  41. p = &DriveLayout->PartitionEntry[i];
  42. if((p->PartitionType != PARTITION_ENTRY_UNUSED)
  43. && (p->StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart)
  44. && (p->PartitionLength.QuadPart == PartitionInfo.PartitionLength.QuadPart)) {
  45. IsPrimary = TRUE;
  46. break;
  47. }
  48. }
  49. if(!IsPrimary) {
  50. return(FALSE);
  51. }
  52. //
  53. // Don't rely on the active partition flag. This could easily not be accurate
  54. // (like user is using os/2 boot manager, for example).
  55. //
  56. //
  57. // See whether nt boot files are present on this drive.
  58. //
  59. for(i=0; BootFiles[i]; i++) {
  60. wsprintf(FileName,L"%wc:\\%s",Drive,BootFiles[i]);
  61. FindHandle = FindFirstFile(FileName,&FindData);
  62. if(FindHandle == INVALID_HANDLE_VALUE) {
  63. return(FALSE);
  64. } else {
  65. FindClose(FindHandle);
  66. }
  67. }
  68. return(TRUE);
  69. }
  70. WCHAR
  71. x86DetermineSystemPartition(
  72. VOID
  73. )
  74. /*++
  75. Routine Description:
  76. Determine the system partition on x86 machines.
  77. The system partition is the primary partition on the boot disk.
  78. Usually this is the active partition on disk 0 and usually it's C:.
  79. However the user could have remapped drive letters and generally
  80. determining the system partition with 100% accuracy is not possible.
  81. The one thing we can be sure of is that the system partition is on
  82. the physical hard disk with the arc path multi(0)disk(0)rdisk(0).
  83. We can be sure of this because by definition this is the arc path
  84. for bios drive 0x80.
  85. This routine determines which drive letters represent drives on
  86. that physical hard drive, and checks each for the nt boot files.
  87. The first drive found with those files is assumed to be the system
  88. partition.
  89. If for some reason we cannot determine the system partition by the above
  90. method, we simply assume it's C:.
  91. Arguments:
  92. None.
  93. Return Value:
  94. Drive letter of system partition.
  95. --*/
  96. {
  97. BOOL GotIt;
  98. PWSTR NtDevicePath;
  99. WCHAR Drive;
  100. WCHAR DriveName[3];
  101. WCHAR Buffer[512];
  102. DWORD NtDevicePathLen;
  103. PWSTR p;
  104. DWORD PhysicalDriveNumber;
  105. HANDLE hDisk;
  106. BOOL b;
  107. DWORD DataSize;
  108. PVOID DriveLayout;
  109. DWORD DriveLayoutSize;
  110. DWORD hardDiskNumber;
  111. WCHAR TempBuffer[MAX_PATH]; //NEC98
  112. DriveName[1] = L':';
  113. DriveName[2] = 0;
  114. GotIt = FALSE;
  115. if (!IsNEC_98) {
  116. //
  117. // The system partition must be on multi(0)disk(0)rdisk(0)
  118. //
  119. if(NtDevicePath = ArcDevicePathToNtPath(L"multi(0)disk(0)rdisk(0)")) {
  120. //
  121. // The arc path for a disk device is usually linked
  122. // to partition0. Get rid of the partition part of the name.
  123. //
  124. CharLower(NtDevicePath);
  125. if(p = wcsstr(NtDevicePath,L"\\partition")) {
  126. *p = 0;
  127. }
  128. NtDevicePathLen = lstrlen(NtDevicePath);
  129. //
  130. // Determine the physical drive number of this drive.
  131. // If the name is not of the form \device\harddiskx then
  132. // something is very wrong.
  133. //
  134. if(!wcsncmp(NtDevicePath,L"\\device\\harddisk",16)) {
  135. PhysicalDriveNumber = wcstoul(NtDevicePath+16,NULL,10);
  136. wsprintf(Buffer,L"\\\\.\\PhysicalDrive%u",PhysicalDriveNumber);
  137. //
  138. // Get drive layout info for this physical disk.
  139. //
  140. hDisk = CreateFile(
  141. Buffer,
  142. GENERIC_READ,
  143. FILE_SHARE_READ | FILE_SHARE_WRITE,
  144. NULL,
  145. OPEN_EXISTING,
  146. 0,
  147. NULL
  148. );
  149. if(hDisk != INVALID_HANDLE_VALUE) {
  150. //
  151. // Get partition information.
  152. //
  153. DriveLayout = MyMalloc(1024);
  154. DriveLayoutSize = 1024;
  155. retry:
  156. b = DeviceIoControl(
  157. hDisk,
  158. IOCTL_DISK_GET_DRIVE_LAYOUT,
  159. NULL,
  160. 0,
  161. DriveLayout,
  162. DriveLayoutSize,
  163. &DataSize,
  164. NULL
  165. );
  166. if(!b && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  167. DriveLayoutSize += 1024;
  168. DriveLayout = MyRealloc(DriveLayout,DriveLayoutSize);
  169. goto retry;
  170. }
  171. CloseHandle(hDisk);
  172. if(b) {
  173. //
  174. // The system partition can only be a drive that is on
  175. // this disk. We make this determination by looking at NT drive names
  176. // for each drive letter and seeing if the nt equivalent of
  177. // multi(0)disk(0)rdisk(0) is a prefix.
  178. //
  179. for(Drive=L'C'; Drive<=L'Z'; Drive++) {
  180. if(MyGetDriveType(Drive) == DRIVE_FIXED) {
  181. DriveName[0] = Drive;
  182. if(QueryDosDevice(DriveName,Buffer,sizeof(Buffer)/sizeof(WCHAR))) {
  183. if (_wcsnicmp(Buffer, L"\\device\\harddisk", 16)) {
  184. hardDiskNumber = QueryHardDiskNumber((UCHAR) Drive);
  185. if (hardDiskNumber != (DWORD) -1) {
  186. swprintf(Buffer, TEXT("\\device\\harddisk%d"),
  187. hardDiskNumber);
  188. }
  189. }
  190. if(!_wcsnicmp(NtDevicePath,Buffer,NtDevicePathLen)) {
  191. //
  192. // Now look to see whether there's an nt boot sector and
  193. // boot files on this drive.
  194. //
  195. if(AppearsToBeSysPart(DriveLayout,Drive)) {
  196. GotIt = TRUE;
  197. break;
  198. }
  199. }
  200. }
  201. }
  202. }
  203. }
  204. MyFree(DriveLayout);
  205. }
  206. }
  207. MyFree(NtDevicePath);
  208. }
  209. } else { //NEC98
  210. //
  211. // Do not only see "multi(0)disk(0)rdisk(0)".
  212. //
  213. if(GetWindowsDirectory(TempBuffer,MAX_PATH)) {
  214. Drive = *TempBuffer;
  215. GotIt = TRUE;
  216. }
  217. } //NEC98
  218. return(GotIt ? Drive : L'C');
  219. }