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.

449 lines
11 KiB

  1. /*++
  2. Copyright (c) 1993 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. #define UNICODE
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <ntdddisk.h>
  16. #include <windows.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include "rc_ids.h"
  21. #include "patchdll.h"
  22. PWSTR
  23. ArcPathToNtPath(
  24. IN PWSTR ArcPath
  25. )
  26. {
  27. NTSTATUS Status;
  28. HANDLE ObjectHandle;
  29. OBJECT_ATTRIBUTES Obja;
  30. UNICODE_STRING UnicodeString;
  31. UCHAR Buffer[1024];
  32. PWSTR arcPath;
  33. PWSTR ntPath;
  34. //
  35. // Assume failure
  36. //
  37. ntPath = NULL;
  38. arcPath = MyMalloc(((wcslen(ArcPath)+1)*sizeof(WCHAR)) + sizeof(L"\\ArcName"));
  39. wcscpy(arcPath,L"\\ArcName\\");
  40. wcscat(arcPath,ArcPath);
  41. RtlInitUnicodeString(&UnicodeString,arcPath);
  42. InitializeObjectAttributes(
  43. &Obja,
  44. &UnicodeString,
  45. OBJ_CASE_INSENSITIVE,
  46. NULL,
  47. NULL
  48. );
  49. Status = NtOpenSymbolicLinkObject(
  50. &ObjectHandle,
  51. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  52. &Obja
  53. );
  54. if(NT_SUCCESS(Status)) {
  55. //
  56. // Query the object to get the link target.
  57. //
  58. UnicodeString.Buffer = (PWSTR)Buffer;
  59. UnicodeString.Length = 0;
  60. UnicodeString.MaximumLength = sizeof(Buffer);
  61. Status = NtQuerySymbolicLinkObject(
  62. ObjectHandle,
  63. &UnicodeString,
  64. NULL
  65. );
  66. if(NT_SUCCESS(Status)) {
  67. ntPath = MyMalloc(UnicodeString.Length+sizeof(WCHAR));
  68. CopyMemory(ntPath,UnicodeString.Buffer,UnicodeString.Length);
  69. ntPath[UnicodeString.Length/sizeof(WCHAR)] = 0;
  70. }
  71. NtClose(ObjectHandle);
  72. }
  73. MyFree(arcPath);
  74. return(ntPath);
  75. }
  76. BOOL
  77. GetPartitionInfo(
  78. IN WCHAR Drive,
  79. OUT PPARTITION_INFORMATION PartitionInfo
  80. )
  81. {
  82. WCHAR DriveName[] = L"\\\\.\\?:";
  83. HANDLE hDisk;
  84. BOOL b;
  85. DWORD DataSize;
  86. DriveName[4] = Drive;
  87. hDisk = CreateFileW(
  88. DriveName,
  89. GENERIC_READ,
  90. FILE_SHARE_READ | FILE_SHARE_WRITE,
  91. NULL,
  92. OPEN_EXISTING,
  93. 0,
  94. NULL
  95. );
  96. if(hDisk == INVALID_HANDLE_VALUE) {
  97. return(FALSE);
  98. }
  99. b = DeviceIoControl(
  100. hDisk,
  101. IOCTL_DISK_GET_PARTITION_INFO,
  102. NULL,
  103. 0,
  104. PartitionInfo,
  105. sizeof(PARTITION_INFORMATION),
  106. &DataSize,
  107. NULL
  108. );
  109. CloseHandle(hDisk);
  110. return(b);
  111. }
  112. BOOL
  113. AppearsToBeSysPart(
  114. IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
  115. IN WCHAR Drive
  116. )
  117. {
  118. PARTITION_INFORMATION PartitionInfo,*p;
  119. BOOL IsPrimary;
  120. unsigned i;
  121. HANDLE FindHandle;
  122. WIN32_FIND_DATA FindData;
  123. PWSTR BootFiles[] = { L"BOOT.INI",
  124. L"NTLDR",
  125. L"NTDETECT.COM",
  126. NULL
  127. };
  128. WCHAR FileName[64];
  129. //
  130. // Get partition information for this partition.
  131. //
  132. if(!GetPartitionInfo(Drive,&PartitionInfo)) {
  133. return(FALSE);
  134. }
  135. //
  136. // See if the drive is a primary partition.
  137. //
  138. IsPrimary = FALSE;
  139. for(i=0; i<min(DriveLayout->PartitionCount,4); i++) {
  140. p = &DriveLayout->PartitionEntry[i];
  141. if((p->PartitionType != PARTITION_ENTRY_UNUSED)
  142. && (p->StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart)
  143. && (p->PartitionLength.QuadPart == PartitionInfo.PartitionLength.QuadPart)) {
  144. IsPrimary = TRUE;
  145. break;
  146. }
  147. }
  148. if(!IsPrimary) {
  149. return(FALSE);
  150. }
  151. //
  152. // Don't rely on the active partition flag. This could easily not be accurate
  153. // (like user is using os/2 boot manager, for example).
  154. //
  155. //
  156. // See whether an nt boot files are present on this drive.
  157. //
  158. for(i=0; BootFiles[i]; i++) {
  159. wsprintf(FileName,L"%wc:\\%s",Drive,BootFiles[i]);
  160. FindHandle = FindFirstFile(FileName,&FindData);
  161. if(FindHandle == INVALID_HANDLE_VALUE) {
  162. return(FALSE);
  163. } else {
  164. FindClose(FindHandle);
  165. }
  166. }
  167. return(TRUE);
  168. }
  169. UINT
  170. MyGetDriveType(
  171. IN WCHAR Drive
  172. )
  173. {
  174. WCHAR DriveNameNt[] = L"\\\\.\\?:";
  175. WCHAR DriveName[] = L"?:\\";
  176. HANDLE hDisk;
  177. BOOL b;
  178. UINT rc;
  179. DWORD DataSize;
  180. DISK_GEOMETRY MediaInfo;
  181. //
  182. // First, get the win32 drive type. If it tells us DRIVE_REMOVABLE,
  183. // then we need to see whether it's a floppy or hard disk. Otherwise
  184. // just believe the api.
  185. //
  186. //
  187. DriveName[0] = Drive;
  188. if((rc = GetDriveType(DriveName)) == DRIVE_REMOVABLE) {
  189. DriveNameNt[4] = Drive;
  190. hDisk = CreateFile(
  191. DriveNameNt,
  192. GENERIC_READ,
  193. FILE_SHARE_READ | FILE_SHARE_WRITE,
  194. NULL,
  195. OPEN_EXISTING,
  196. 0,
  197. NULL
  198. );
  199. if(hDisk != INVALID_HANDLE_VALUE) {
  200. b = DeviceIoControl(
  201. hDisk,
  202. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  203. NULL,
  204. 0,
  205. &MediaInfo,
  206. sizeof(MediaInfo),
  207. &DataSize,
  208. NULL
  209. );
  210. //
  211. // It's really a hard disk if the media type is removable.
  212. //
  213. if(b && (MediaInfo.MediaType == RemovableMedia)) {
  214. rc = DRIVE_FIXED;
  215. }
  216. CloseHandle(hDisk);
  217. }
  218. }
  219. return(rc);
  220. }
  221. WCHAR
  222. x86DetermineSystemPartition(
  223. VOID
  224. )
  225. /*++
  226. Routine Description:
  227. Determine the system partition on x86 machines.
  228. The system partition is the primary partition on the boot disk.
  229. Usually this is the active partition on disk 0 and usually it's C:.
  230. However the user could have remapped drive letters and generally
  231. determining the system partition with 100% accuracy is not possible.
  232. The one thing we can be sure of is that the system partition is on
  233. the physical hard disk with the arc path multi(0)disk(0)rdisk(0).
  234. We can be sure of this because by definition this is the arc path
  235. for bios drive 0x80.
  236. This routine determines which drive letters represent drives on
  237. that physical hard drive, and checks each for the nt boot files.
  238. The first drive found with those files is assumed to be the system
  239. partition.
  240. If for some reason we cannot determine the system partition by the above
  241. method, we simply assume it's C:.
  242. Arguments:
  243. None
  244. Return Value:
  245. Drive letter of system partition.
  246. --*/
  247. {
  248. BOOL GotIt;
  249. PWSTR NtDevicePath;
  250. WCHAR Drive;
  251. WCHAR DriveName[3];
  252. WCHAR Buffer[512];
  253. DWORD NtDevicePathLen;
  254. PWSTR p;
  255. DWORD PhysicalDriveNumber;
  256. HANDLE hDisk;
  257. BOOL b;
  258. DWORD DataSize;
  259. PVOID DriveLayout;
  260. DWORD DriveLayoutSize;
  261. DriveName[1] = L':';
  262. DriveName[2] = 0;
  263. GotIt = FALSE;
  264. //
  265. // The system partition must be on multi(0)disk(0)rdisk(0)
  266. //
  267. if(NtDevicePath = ArcPathToNtPath(L"multi(0)disk(0)rdisk(0)")) {
  268. //
  269. // The arc path for a disk device is usually linked
  270. // to partition0. Get rid of the partition part of the name.
  271. //
  272. CharLowerW(NtDevicePath);
  273. if(p = wcsstr(NtDevicePath,L"\\partition")) {
  274. *p = 0;
  275. }
  276. NtDevicePathLen = lstrlenW(NtDevicePath);
  277. //
  278. // Determine the physical drive number of this drive.
  279. // If the name is not of the form \device\harddiskx then
  280. // something is very wrong.
  281. //
  282. if(!wcsncmp(NtDevicePath,L"\\device\\harddisk",16)) {
  283. PhysicalDriveNumber = wcstoul(NtDevicePath+16,NULL,10);
  284. wsprintfW(Buffer,L"\\\\.\\PhysicalDrive%u",PhysicalDriveNumber);
  285. //
  286. // Get drive layout info for this physical disk.
  287. //
  288. hDisk = CreateFileW(
  289. Buffer,
  290. GENERIC_READ,
  291. FILE_SHARE_READ | FILE_SHARE_WRITE,
  292. NULL,
  293. OPEN_EXISTING,
  294. 0,
  295. NULL
  296. );
  297. if(hDisk != INVALID_HANDLE_VALUE) {
  298. //
  299. // Get partition information.
  300. //
  301. DriveLayout = MyMalloc(1024);
  302. DriveLayoutSize = 1024;
  303. retry:
  304. b = DeviceIoControl(
  305. hDisk,
  306. IOCTL_DISK_GET_DRIVE_LAYOUT,
  307. NULL,
  308. 0,
  309. DriveLayout,
  310. DriveLayoutSize,
  311. &DataSize,
  312. NULL
  313. );
  314. if(!b && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  315. DriveLayoutSize += 1024;
  316. DriveLayout = MyRealloc(DriveLayout,DriveLayoutSize);
  317. goto retry;
  318. }
  319. CloseHandle(hDisk);
  320. if(b) {
  321. //
  322. // The system partition can only be a drive that is on
  323. // this disk. We make this determination by looking at NT drive names
  324. // for each drive letter and seeing if the nt equivalent of
  325. // multi(0)disk(0)rdisk(0) is a prefix.
  326. //
  327. for(Drive=L'C'; Drive<=L'Z'; Drive++) {
  328. if(MyGetDriveType(Drive) == DRIVE_FIXED) {
  329. DriveName[0] = Drive;
  330. if(QueryDosDeviceW(DriveName,Buffer,sizeof(Buffer)/sizeof(WCHAR))) {
  331. if(!_wcsnicmp(NtDevicePath,Buffer,NtDevicePathLen)) {
  332. //
  333. // Now look to see whether there's an nt boot sector and
  334. // boot files on this drive.
  335. //
  336. if(AppearsToBeSysPart(DriveLayout,Drive)) {
  337. GotIt = TRUE;
  338. break;
  339. }
  340. }
  341. }
  342. }
  343. }
  344. }
  345. MyFree(DriveLayout);
  346. }
  347. }
  348. MyFree(NtDevicePath);
  349. }
  350. return(GotIt ? Drive : L'C');
  351. }