Leaked source code of windows server 2003
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.

1805 lines
47 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. #include "precomp.h"
  12. #pragma hdrstop
  13. #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS)
  14. //
  15. // Command-line param that allows someone to force a particular drive
  16. // to be the system partition. Useful in certain preinstall scenarios.
  17. //
  18. TCHAR ForcedSystemPartition;
  19. #define WINNT_DONT_MATCH_PARTITION 0
  20. #define WINNT_MATCH_PARTITION_NUMBER 1
  21. #define WINNT_MATCH_PARTITION_STARTING_OFFSET 2
  22. #define BUFFERSIZE 1024
  23. //
  24. // NT-specific routines we use from ntdll.dll and kernel32.dll
  25. //
  26. //NTSYSAPI
  27. NTSTATUS
  28. (NTAPI *NtOpenSymLinkRoutine)(
  29. OUT PHANDLE LinkHandle,
  30. IN ACCESS_MASK DesiredAccess,
  31. IN POBJECT_ATTRIBUTES ObjectAttributes
  32. );
  33. //NTSYSAPI
  34. NTSTATUS
  35. (NTAPI *NtQuerSymLinkRoutine)(
  36. IN HANDLE LinkHandle,
  37. IN OUT PUNICODE_STRING LinkTarget,
  38. OUT PULONG ReturnedLength OPTIONAL
  39. );
  40. //NTSYSAPI
  41. NTSTATUS
  42. (NTAPI *NtQuerDirRoutine) (
  43. IN HANDLE DirectoryHandle,
  44. OUT PVOID Buffer,
  45. IN ULONG Length,
  46. IN BOOLEAN ReturnSingleEntry,
  47. IN BOOLEAN RestartScan,
  48. IN OUT PULONG Context,
  49. OUT PULONG ReturnLength OPTIONAL
  50. );
  51. //NTSYSAPI
  52. NTSTATUS
  53. (NTAPI *NtOpenDirRoutine) (
  54. OUT PHANDLE DirectoryHandle,
  55. IN ACCESS_MASK DesiredAccess,
  56. IN POBJECT_ATTRIBUTES ObjectAttributes
  57. );
  58. //WINBASEAPI
  59. HANDLE
  60. (WINAPI *pFindFirstVolume) (
  61. LPWSTR lpszVolumeName,
  62. DWORD cchBufferLength
  63. );
  64. //WINBASEAPI
  65. BOOL
  66. (WINAPI *pFindNextVolume)(
  67. HANDLE hFindVolume,
  68. LPWSTR lpszVolumeName,
  69. DWORD cchBufferLength
  70. );
  71. //WINBASEAPI
  72. BOOL
  73. (WINAPI *pFindVolumeClose)(
  74. HANDLE hFindVolume
  75. );
  76. //WINBASEAPI
  77. BOOL
  78. (WINAPI *pGetVolumeNameForVolumeMountPoint)(
  79. LPCWSTR lpszVolumeMountPoint,
  80. LPWSTR lpszVolumeName,
  81. DWORD cchBufferLength
  82. );
  83. DWORD
  84. FindSystemPartitionSignature(
  85. IN LPCTSTR AdapterKeyName,
  86. OUT LPTSTR Signature
  87. );
  88. DWORD
  89. GetSystemVolumeGUID(
  90. IN LPTSTR Signature,
  91. OUT LPTSTR SysVolGuid
  92. );
  93. BOOL
  94. DoDiskSignaturesCompare(
  95. IN LPCTSTR Signature,
  96. IN LPCTSTR DriveName,
  97. IN OUT PVOID Compare,
  98. IN DWORD Action
  99. );
  100. DWORD
  101. GetNT4SystemPartition(
  102. IN LPTSTR Signature,
  103. OUT LPTSTR SysPart
  104. );
  105. BOOL
  106. ArcPathToNtPath(
  107. IN LPCTSTR ArcPath,
  108. OUT LPTSTR NtPath,
  109. IN UINT NtPathBufferLen
  110. )
  111. {
  112. WCHAR arcPath[256];
  113. UNICODE_STRING UnicodeString;
  114. OBJECT_ATTRIBUTES Obja;
  115. HANDLE ObjectHandle;
  116. NTSTATUS Status;
  117. WCHAR Buffer[512];
  118. PWSTR ntPath;
  119. lstrcpyW(arcPath,L"\\ArcName\\");
  120. #ifdef UNICODE
  121. lstrcpynW(arcPath+9,ArcPath,(sizeof(arcPath)/sizeof(WCHAR))-9);
  122. #else
  123. MultiByteToWideChar(
  124. CP_ACP,
  125. 0,
  126. ArcPath,
  127. -1,
  128. arcPath+9,
  129. (sizeof(arcPath)/sizeof(WCHAR))-9
  130. );
  131. #endif
  132. UnicodeString.Buffer = arcPath;
  133. UnicodeString.Length = lstrlenW(arcPath)*sizeof(WCHAR);
  134. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  135. InitializeObjectAttributes(
  136. &Obja,
  137. &UnicodeString,
  138. OBJ_CASE_INSENSITIVE,
  139. NULL,
  140. NULL
  141. );
  142. Status = (*NtOpenSymLinkRoutine)(
  143. &ObjectHandle,
  144. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  145. &Obja
  146. );
  147. if(NT_SUCCESS(Status)) {
  148. //
  149. // Query the object to get the link target.
  150. //
  151. UnicodeString.Buffer = Buffer;
  152. UnicodeString.Length = 0;
  153. UnicodeString.MaximumLength = sizeof(Buffer)-sizeof(WCHAR);
  154. Status = (*NtQuerSymLinkRoutine)(ObjectHandle,&UnicodeString,NULL);
  155. CloseHandle(ObjectHandle);
  156. if(NT_SUCCESS(Status)) {
  157. Buffer[UnicodeString.Length/sizeof(WCHAR)] = 0;
  158. #ifdef UNICODE
  159. lstrcpyn(NtPath,Buffer,NtPathBufferLen);
  160. #else
  161. WideCharToMultiByte(CP_ACP,0,Buffer,-1,NtPath,NtPathBufferLen,NULL,NULL);
  162. #endif
  163. return(TRUE);
  164. }
  165. }
  166. return(FALSE);
  167. }
  168. BOOL
  169. AppearsToBeSysPart(
  170. IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
  171. IN TCHAR Drive
  172. )
  173. {
  174. PARTITION_INFORMATION PartitionInfo,*p;
  175. BOOL IsPrimary;
  176. UINT i;
  177. DWORD d;
  178. LPTSTR BootFiles[] = { TEXT("BOOT.INI"),
  179. TEXT("NTLDR"),
  180. TEXT("NTDETECT.COM"),
  181. NULL
  182. };
  183. TCHAR FileName[64];
  184. //
  185. // Get partition information for this partition.
  186. //
  187. if(!GetPartitionInfo(Drive,&PartitionInfo)) {
  188. return(FALSE);
  189. }
  190. //
  191. // See if the drive is a primary partition.
  192. //
  193. IsPrimary = FALSE;
  194. for(i=0; i<min(DriveLayout->PartitionCount,4); i++) {
  195. p = &DriveLayout->PartitionEntry[i];
  196. if((p->PartitionType != PARTITION_ENTRY_UNUSED)
  197. && (p->StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart)
  198. && (p->PartitionLength.QuadPart == PartitionInfo.PartitionLength.QuadPart)) {
  199. IsPrimary = TRUE;
  200. break;
  201. }
  202. }
  203. if(!IsPrimary) {
  204. return(FALSE);
  205. }
  206. //
  207. // Don't rely on the active partition flag. This could easily not be accurate
  208. // (like user is using os/2 boot manager, for example).
  209. //
  210. //
  211. // See whether all NT boot files are present on this drive.
  212. //
  213. for(i=0; BootFiles[i]; i++) {
  214. wsprintf(FileName,TEXT("%c:\\%s"),Drive,BootFiles[i]);
  215. d = GetFileAttributes(FileName);
  216. if(d == (DWORD)(-1)) {
  217. return(FALSE);
  218. }
  219. }
  220. return(TRUE);
  221. }
  222. DWORD
  223. QueryHardDiskNumber(
  224. IN TCHAR DriveLetter
  225. )
  226. {
  227. TCHAR driveName[10];
  228. HANDLE h;
  229. BOOL b;
  230. STORAGE_DEVICE_NUMBER number;
  231. DWORD bytes;
  232. driveName[0] = '\\';
  233. driveName[1] = '\\';
  234. driveName[2] = '.';
  235. driveName[3] = '\\';
  236. driveName[4] = DriveLetter;
  237. driveName[5] = ':';
  238. driveName[6] = 0;
  239. h = CreateFile(driveName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  240. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  241. INVALID_HANDLE_VALUE);
  242. if (h == INVALID_HANDLE_VALUE) {
  243. return (DWORD) -1;
  244. }
  245. b = DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  246. &number, sizeof(number), &bytes, NULL);
  247. CloseHandle(h);
  248. if (!b) {
  249. return (DWORD) -1;
  250. }
  251. return number.DeviceNumber;
  252. }
  253. BOOL
  254. MarkPartitionActive(
  255. IN TCHAR DriveLetter
  256. )
  257. {
  258. DWORD DriveNum;
  259. TCHAR DosName[7];
  260. TCHAR Name[MAX_PATH];
  261. DISK_GEOMETRY DiskGeom;
  262. PARTITION_INFORMATION PartitionInfo;
  263. HANDLE h;
  264. BOOL b;
  265. DWORD Bytes;
  266. PUCHAR UnalignedBuffer,Buffer;
  267. unsigned i;
  268. BOOL Rewrite;
  269. BOOL FoundIt;
  270. //
  271. // This concept is n/a for PC98 and the stuff below
  272. // won't work on Win9x.
  273. //
  274. if(IsNEC98() || !ISNT()) {
  275. return(TRUE);
  276. }
  277. //
  278. // Get geometry info and partition info for this drive.
  279. // We get geometry info because we need the bytes per sector info.
  280. //
  281. wsprintf(DosName,TEXT("\\\\.\\%c:"),DriveLetter);
  282. h = CreateFile(
  283. DosName,
  284. GENERIC_READ,
  285. FILE_SHARE_READ | FILE_SHARE_WRITE,
  286. NULL,
  287. OPEN_EXISTING,
  288. 0,
  289. NULL
  290. );
  291. if(h == INVALID_HANDLE_VALUE) {
  292. return(FALSE);
  293. }
  294. b = DeviceIoControl(
  295. h,
  296. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  297. NULL,
  298. 0,
  299. &DiskGeom,
  300. sizeof(DISK_GEOMETRY),
  301. &Bytes,
  302. NULL
  303. );
  304. if(!b || (DiskGeom.BytesPerSector < 512)) {
  305. CloseHandle(h);
  306. return(FALSE);
  307. }
  308. b = DeviceIoControl(
  309. h,
  310. IOCTL_DISK_GET_PARTITION_INFO,
  311. NULL,
  312. 0,
  313. &PartitionInfo,
  314. sizeof(PARTITION_INFORMATION),
  315. &Bytes,
  316. NULL
  317. );
  318. CloseHandle(h);
  319. if(!b) {
  320. return(FALSE);
  321. }
  322. //
  323. // Figure out which physical drive this partition is on.
  324. //
  325. DriveNum = QueryHardDiskNumber(DriveLetter);
  326. if(DriveNum == (DWORD)(-1)) {
  327. if (OsVersion.dwMajorVersion >= 5) {
  328. //
  329. // if QueryHardDiskNumber failed, it's likely the volume is on a dynamic disk
  330. // so in this case we better don't try to make (wrong) guesses;
  331. // just bail out
  332. //
  333. return FALSE;
  334. }
  335. // Have to do it the old-fashioned way. Convert to an NT path
  336. // and parse the result.
  337. //
  338. if(!QueryDosDevice(DosName+4,Name,MAX_PATH)) {
  339. return(FALSE);
  340. }
  341. if( _tcsnicmp( Name, TEXT("\\device\\harddisk"), 16 )) {
  342. //
  343. // We have no idea what this name represents. Punt.
  344. //
  345. return(FALSE);
  346. }
  347. DriveNum = _tcstoul(Name+16,NULL,10);
  348. }
  349. //
  350. // Allocate a buffer and align it.
  351. //
  352. UnalignedBuffer = MALLOC(2*DiskGeom.BytesPerSector);
  353. if(!UnalignedBuffer) {
  354. return(FALSE);
  355. }
  356. Buffer = (PVOID)(((DWORD_PTR)UnalignedBuffer + (DiskGeom.BytesPerSector - 1)) & ~((DWORD_PTR)(DiskGeom.BytesPerSector - 1)));
  357. //
  358. // Now we open up the physical drive and read the partition table.
  359. // We try to locate the partition by matching start offsets.
  360. // Note that active status is only meaningful for primary partitions.
  361. //
  362. wsprintf(Name,TEXT("\\\\.\\PhysicalDrive%u"),DriveNum);
  363. h = CreateFile(
  364. Name,
  365. GENERIC_READ | GENERIC_WRITE,
  366. FILE_SHARE_READ | FILE_SHARE_WRITE,
  367. NULL,
  368. OPEN_EXISTING,
  369. FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
  370. NULL
  371. );
  372. if(h == INVALID_HANDLE_VALUE) {
  373. FREE(UnalignedBuffer);
  374. return(FALSE);
  375. }
  376. if(!ReadFile(h,Buffer,DiskGeom.BytesPerSector,&Bytes,NULL)) {
  377. FREE(UnalignedBuffer);
  378. CloseHandle(h);
  379. return(FALSE);
  380. }
  381. Rewrite = FALSE;
  382. FoundIt = FALSE;
  383. for(i=0; i<4; i++) {
  384. if(*(DWORD *)(Buffer + 0x1be + 8 + (i*16))
  385. == (DWORD)(PartitionInfo.StartingOffset.QuadPart / DiskGeom.BytesPerSector)) {
  386. FoundIt = TRUE;
  387. if(Buffer[0x1be+(i*16)] != 0x80) {
  388. //
  389. // Not already active, or active for some other bios unit #,
  390. // so we need to whack it.
  391. //
  392. Buffer[0x1be+(i*16)] = 0x80;
  393. Rewrite = TRUE;
  394. }
  395. } else {
  396. if(Buffer[0x1be+(i*16)]) {
  397. //
  398. // Not inactive, and needs to be, so whack it.
  399. //
  400. Buffer[0x1be+(i*16)] = 0;
  401. Rewrite = TRUE;
  402. }
  403. }
  404. }
  405. if(FoundIt) {
  406. if(Rewrite) {
  407. Bytes = 0;
  408. if(SetFilePointer(h,0,&Bytes,FILE_BEGIN) || Bytes) {
  409. b = FALSE;
  410. } else {
  411. b = WriteFile(h,Buffer,DiskGeom.BytesPerSector,&Bytes,NULL);
  412. }
  413. } else {
  414. b = TRUE;
  415. }
  416. } else {
  417. b = FALSE;
  418. }
  419. CloseHandle(h);
  420. FREE(UnalignedBuffer);
  421. return(b);
  422. }
  423. BOOL
  424. x86DetermineSystemPartition(
  425. IN HWND ParentWindow,
  426. OUT PTCHAR SysPartDrive
  427. )
  428. /*++
  429. Routine Description:
  430. Determine the system partition on x86 machines.
  431. On Win95, we always return C:. For NT, read on.
  432. The system partition is the primary partition on the boot disk.
  433. Usually this is the active partition on disk 0 and usually it's C:.
  434. However the user could have remapped drive letters and generally
  435. determining the system partition with 100% accuracy is not possible.
  436. With there being differences in the IO system mapping and introduction of Volumes for NT 50
  437. this has now become complicated. Listed below are the algorithms
  438. NT 5.0 Beta 2 and above :
  439. 1. Get the signature from the registry. Located at
  440. HKLM\Hardware\Description\System\<MultifunctionAdapter or EisaAdapter>\<some Bus No.>\DiskController\0\DiskPeripheral\0\Identifier
  441. 2. Go Through all of the volumes in the system with FindFirstVolume/FindNextVolume/FindVolumeClose.
  442. 3. Take off the trailing backslash to the name returne to get \\?\Volume{guid}.
  443. 4. IOCTL_STORAGE_GET_DEVICE_NUMBER with \\?\Volume{guid} => Check for FILE_DEVICE_DISK. Remember the partition number. Goto 6
  444. 5. If IOCTL_STORAGE_GET_DEVICE_NUMBER fails then use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS which returns a list of harddisks.
  445. For each harddisk remember the starting offset and goto 6.
  446. 6. Check Harddisk # by using \\.\PhysicalDrive# with IOCTL_DISK_GET_DRIVE_LAYOUT. If the signature matches then this is the disk we boot from.
  447. 7. To find the partition that we boot from we look for boot indicator. If we used 2 we try to match the partition number stored in 6
  448. else if 3 we try to match the starting offset.Then you have a \\?\Volume{guid}\ name for the SYSTEM volume.
  449. 8. Call GetVolumeNameForVolumeMountPoint with A:\, B:\, C:\, ... and check the result of the form \\?\Volume{guid}\ against your match
  450. to see what the drive letter is.
  451. Important: Since the *Volume* APIs are post Beta2 we do dynamic loading of kernel32.dll based on the build number returned.
  452. Versions below NT 5.0 Beta 2
  453. 1. Get the signature from the registry. Located at
  454. HKLM\Hardware\Description\System\<MultifunctionAdapter or EisaAdapter>\<some Bus No.>\DiskController\0\DiskPeripheral\0\Identifier
  455. 2. Enumerate the \?? directory and look for all entries that begin with PhysicalDrive#.
  456. 3. For each of the Disks look for a match with the signature above and if they match then find out the partition number used to boot
  457. using IOCTL_DISK_GET_DRIVE_LAYOUT and the BootIndicator bit.
  458. 4. On finding the Boot partition create a name of the form \Device\Harddisk#\Partition#
  459. 5. Then go through c:,d:...,z: calling QueryDosDeviceName and look for a match. That would be your system partition drive letter
  460. Arguments:
  461. ParentWindow - supplies window handle for window to be the parent for
  462. any dialogs, etc.
  463. SysPartDrive - if successful, receives drive letter of system partition.
  464. Return Value:
  465. Boolean value indicating whether SysPartDrive has been filled in.
  466. If FALSE, the user will have been infomred about why.
  467. --*/
  468. {
  469. TCHAR DriveName[4];
  470. BOOL GotIt=FALSE;
  471. TCHAR Buffer[512];
  472. TCHAR Drive;
  473. BOOL b;
  474. TCHAR SysPartSig[100], PartitionNum[MAX_PATH], SysVolGuid[MAX_PATH];
  475. TCHAR DriveVolGuid[MAX_PATH];
  476. if(ForcedSystemPartition) {
  477. //
  478. // NT5 for NEC98 can't boot up from ATA Card and
  479. // removable drive. We need check dive type.
  480. //
  481. if (IsNEC98() &&
  482. ((MyGetDriveType(ForcedSystemPartition) != DRIVE_FIXED) ||
  483. // Drive is not Fixed.
  484. !IsValidDrive(ForcedSystemPartition))){
  485. // HD format type is not NEC98.
  486. return(FALSE);
  487. }
  488. *SysPartDrive = ForcedSystemPartition;
  489. return(TRUE);
  490. }
  491. if(IsNEC98()) {
  492. if(!MyGetWindowsDirectory(Buffer,sizeof(Buffer)/sizeof(TCHAR)))
  493. return FALSE;
  494. *SysPartDrive = Buffer[0];
  495. return(TRUE);
  496. }
  497. if(!ISNT()) {
  498. *SysPartDrive = TEXT('C');
  499. return(TRUE);
  500. }
  501. // Code for NT starts here
  502. //Get signature from registry - Step 1 listed above
  503. if( (FindSystemPartitionSignature(TEXT("Hardware\\Description\\System\\EisaAdapter"),SysPartSig) != ERROR_SUCCESS )
  504. && (FindSystemPartitionSignature(TEXT("Hardware\\Description\\System\\MultiFunctionAdapter"),SysPartSig) != ERROR_SUCCESS ) ){
  505. GotIt = FALSE;
  506. goto c0;
  507. }
  508. if( ISNT() && (BUILDNUM() >= 1877) ){
  509. //Get the SystemVolumeGUID - steps 2 through 7 listed above ( Beta 2 and after )
  510. if( GetSystemVolumeGUID( SysPartSig, SysVolGuid ) != ERROR_SUCCESS ){
  511. GotIt = FALSE;
  512. goto c0;
  513. }
  514. }else{
  515. if( GetNT4SystemPartition( SysPartSig, PartitionNum ) != ERROR_SUCCESS){
  516. GotIt = FALSE;
  517. goto c0;
  518. }
  519. }
  520. DriveName[1] = TEXT(':');
  521. //
  522. // Enumerate all drive letters and compare their device names
  523. //
  524. for(Drive=TEXT('A'); Drive<=TEXT('Z'); Drive++) {
  525. if(MyGetDriveType(Drive) == DRIVE_FIXED) {
  526. DriveName[0] = Drive;
  527. if( BUILDNUM() >= 1877){ //Versions Beta2 and after
  528. DriveName[2] = '\\';
  529. DriveName[3] = 0;
  530. if((pGetVolumeNameForVolumeMountPoint)((LPWSTR)DriveName, (LPWSTR)DriveVolGuid, MAX_PATH*sizeof(TCHAR))){
  531. if(!lstrcmp(DriveVolGuid, SysVolGuid) ){
  532. GotIt = TRUE; // Found it
  533. break;
  534. }
  535. }
  536. }else{
  537. DriveName[2] = 0;
  538. if(QueryDosDevice(DriveName,Buffer,sizeof(Buffer)/sizeof(TCHAR))) {
  539. if( !lstrcmpi(Buffer, PartitionNum) ) {
  540. GotIt = TRUE; // Found it
  541. break;
  542. }
  543. }
  544. }//Versions earlier than Beta 2
  545. }
  546. }
  547. // This helps for some builds ~1500 < buildnum < 1877 that are in a tough spot
  548. if(!GotIt) {
  549. //
  550. // Strange case, just assume C:
  551. //
  552. GotIt = TRUE;
  553. Drive = TEXT('C');
  554. }
  555. c0:
  556. if(GotIt) {
  557. *SysPartDrive = Drive;
  558. #if defined(REMOTE_BOOT)
  559. } else if (RemoteBoot) {
  560. GotIt = TRUE;
  561. *SysPartDrive = TEXT('C');
  562. #endif
  563. }
  564. return(GotIt);
  565. }
  566. DWORD
  567. GetSystemVolumeGUID(
  568. IN LPTSTR Signature,
  569. OUT LPTSTR SysVolGuid
  570. )
  571. /*++
  572. Routine Description:
  573. This routine enumerates all the volumes and if successful returns the \\?\Volume{guid} name for the system partition.
  574. Arguments:
  575. Signature - supplies a disk signature of the Boot disk so that it can be compared against. The details
  576. to getting this value are detailed in the comments for x86DetermineSystemPartition.
  577. SysVolGuid - If successful, will contain a name of form \\?\Volume{guid} for the System Partition (the one we use to boot)
  578. Return Value:
  579. Returns NO_ERROR if successful, otherwise it contains the error code.
  580. --*/
  581. {
  582. HANDLE hVolume, h;
  583. TCHAR VolumeName[MAX_PATH];
  584. PTSTR q;
  585. TCHAR driveName[30];
  586. BOOL b,ret, DoExtent, MatchFound;
  587. STORAGE_DEVICE_NUMBER number;
  588. DWORD Err,cnt;
  589. PVOLUME_DISK_EXTENTS Extent;
  590. PDISK_EXTENT Start, i;
  591. DWORD ExtentSize, bytes;
  592. PVOID p;
  593. ULONG PartitionNumToCompare;
  594. LARGE_INTEGER StartingOffToCompare;
  595. DWORD ioctlCode;
  596. Err = NO_ERROR;
  597. //Enuberate all volumes
  598. hVolume = (pFindFirstVolume)( (LPWSTR)VolumeName, MAX_PATH );
  599. if( hVolume == INVALID_HANDLE_VALUE ){
  600. return GetLastError();
  601. }
  602. MatchFound = FALSE;
  603. do{
  604. //Remove trailing backslash
  605. DoExtent = FALSE;
  606. if( q=_tcsrchr( VolumeName,TEXT('\\')) ){
  607. *q = 0;
  608. }else{
  609. continue;
  610. }
  611. //Open the volume
  612. h = CreateFile(VolumeName, GENERIC_READ, FILE_SHARE_READ |
  613. FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  614. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  615. if (h == INVALID_HANDLE_VALUE) {
  616. Err = GetLastError();
  617. continue; // Move on to next volume
  618. }
  619. //Get the disk number
  620. ret = DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  621. &number, sizeof(number), &bytes, NULL);
  622. if( !ret ){
  623. // Try using IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS if the above failed
  624. Extent = MALLOC(1024);
  625. ExtentSize = 1024;
  626. if(!Extent) {
  627. CloseHandle( h );
  628. Err = ERROR_NOT_ENOUGH_MEMORY;
  629. goto cleanup;
  630. }
  631. ioctlCode = IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS;
  632. retry:
  633. ret = DeviceIoControl( h, ioctlCode,
  634. NULL,0,(PVOID)Extent,ExtentSize,&bytes,NULL);
  635. if(!ret) {
  636. if((Err=GetLastError()) == ERROR_MORE_DATA) {
  637. ExtentSize += 1024;
  638. if(p = REALLOC((PVOID)Extent, ExtentSize)) {
  639. (PVOID)Extent = p;
  640. } else {
  641. CloseHandle( h );
  642. Err = ERROR_NOT_ENOUGH_MEMORY;
  643. goto cleanup;
  644. }
  645. goto retry;
  646. } else {
  647. if (ioctlCode == IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS) {
  648. ioctlCode = IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN;
  649. goto retry;
  650. }
  651. CloseHandle( h );
  652. continue;
  653. }
  654. }else{
  655. DoExtent = TRUE;
  656. }
  657. }
  658. // Done with the handle this time around
  659. CloseHandle( h );
  660. if( !DoExtent ){
  661. //
  662. // Check to see if this is a disk and not CDROM etc.
  663. //
  664. if( number.DeviceType == FILE_DEVICE_DISK ){
  665. // Remember the partition number
  666. PartitionNumToCompare = number.PartitionNumber;
  667. wsprintf( driveName, TEXT("\\\\.\\PhysicalDrive%lu"), number.DeviceNumber );
  668. if(DoDiskSignaturesCompare( Signature, driveName, (PVOID)&PartitionNumToCompare, WINNT_MATCH_PARTITION_NUMBER ) ){
  669. MatchFound = TRUE;
  670. Err = NO_ERROR;
  671. lstrcpy( SysVolGuid, VolumeName );
  672. SysVolGuid[lstrlen(VolumeName)]=TEXT('\\');
  673. SysVolGuid[lstrlen(VolumeName)+1]=0;
  674. break;
  675. }
  676. }
  677. // Move on ..
  678. continue;
  679. }else{
  680. // Go through all disks and try for match
  681. Start = Extent->Extents;
  682. cnt = 0;
  683. for( i = Start; cnt < Extent->NumberOfDiskExtents; i++ ){
  684. cnt++;
  685. // Remember the starting offset
  686. StartingOffToCompare = i->StartingOffset;
  687. wsprintf( driveName, TEXT("\\\\.\\PhysicalDrive%lu"), i->DiskNumber );
  688. if(DoDiskSignaturesCompare( Signature, driveName, (PVOID)&StartingOffToCompare, WINNT_MATCH_PARTITION_STARTING_OFFSET ) ){
  689. MatchFound = TRUE;
  690. Err = NO_ERROR;
  691. lstrcpy( SysVolGuid, VolumeName );
  692. SysVolGuid[lstrlen(VolumeName)]=TEXT('\\');
  693. SysVolGuid[lstrlen(VolumeName)+1]=0;
  694. break;
  695. }
  696. }
  697. }
  698. if( MatchFound )
  699. break;
  700. }while( (pFindNextVolume)( hVolume, (LPWSTR)VolumeName, MAX_PATH ));
  701. cleanup:
  702. if( hVolume != INVALID_HANDLE_VALUE )
  703. (pFindVolumeClose)( hVolume );
  704. return Err;
  705. }
  706. BOOL
  707. DoDiskSignaturesCompare(
  708. IN LPCTSTR Signature,
  709. IN LPCTSTR DriveName,
  710. IN OUT PVOID Compare,
  711. IN DWORD Action
  712. )
  713. /*++
  714. Routine Description:
  715. This routine compares the given disk signature with the one for the specified physical disk.
  716. Arguments:
  717. Signature - supplies a disk signature of the Boot disk so that it can be compared against. The details
  718. to getting this value are detailed in the comments for x86DetermineSystemPartition.
  719. DriveName - Physical Drive name of the form \\.\PhysicalDrive#
  720. Compare - A pointer to a storage variable. The type depends on the value of Action
  721. Action - Should be one of the following
  722. WINNT_DONT_MATCH_PARTITION - Once disk signatures match it returns the boot partition number in Compare. Compare should be a PULONG.
  723. WINNT_MATCH_PARTITION_NUMBER - Once disk signatures match it tries to match the boot partition number with the number passed in
  724. through Compare. Compare should be PULONG.
  725. WINNT_MATCH_PARTITION_STARTING_OFFSET - Once disk signatures match it tries to match the boot partition starting offset with the
  726. starting offset number passed in through Compare. Compare should be PLARGE_INTEGER.
  727. Return Value:
  728. Returns TRUE if successful in getting a match.
  729. --*/
  730. {
  731. TCHAR temp[30];
  732. BOOL b,Found = FALSE;
  733. PLARGE_INTEGER Starting_Off;
  734. PPARTITION_INFORMATION Start, i;
  735. HANDLE hDisk;
  736. PDRIVE_LAYOUT_INFORMATION DriveLayout;
  737. DWORD DriveLayoutSize;
  738. DWORD cnt;
  739. DWORD DataSize;
  740. LPTSTR p;
  741. PULONG Disk_Num;
  742. ULONG Sig;
  743. if(!Compare )
  744. return FALSE;
  745. if ((Action != WINNT_DONT_MATCH_PARTITION) &&
  746. (Action != WINNT_MATCH_PARTITION_NUMBER) &&
  747. (Action != WINNT_MATCH_PARTITION_STARTING_OFFSET))
  748. return FALSE;
  749. if( (Action==WINNT_MATCH_PARTITION_STARTING_OFFSET) && Compare )
  750. Starting_Off = (PLARGE_INTEGER) Compare;
  751. else
  752. Disk_Num = (PULONG) Compare;
  753. // On any failure return FALSE
  754. //
  755. // Get drive layout info for this physical disk.
  756. // If we can't do this something is very wrong.
  757. //
  758. hDisk = CreateFile(
  759. DriveName,
  760. FILE_READ_ATTRIBUTES | FILE_READ_DATA,
  761. FILE_SHARE_READ | FILE_SHARE_WRITE,
  762. NULL,
  763. OPEN_EXISTING,
  764. 0,
  765. NULL
  766. );
  767. if(hDisk == INVALID_HANDLE_VALUE) {
  768. return FALSE;
  769. }
  770. //
  771. // Get partition information.
  772. //
  773. DriveLayout = MALLOC(1024);
  774. DriveLayoutSize = 1024;
  775. if(!DriveLayout) {
  776. goto cleanexit;
  777. }
  778. retry:
  779. b = DeviceIoControl(
  780. hDisk,
  781. IOCTL_DISK_GET_DRIVE_LAYOUT,
  782. NULL,
  783. 0,
  784. (PVOID)DriveLayout,
  785. DriveLayoutSize,
  786. &DataSize,
  787. NULL
  788. );
  789. if(!b) {
  790. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  791. DriveLayoutSize += 1024;
  792. if(p = REALLOC((PVOID)DriveLayout,DriveLayoutSize)) {
  793. (PVOID)DriveLayout = p;
  794. } else {
  795. goto cleanexit;
  796. }
  797. goto retry;
  798. } else {
  799. goto cleanexit;
  800. }
  801. }else{
  802. // Now walk the Drive_Layout to find the boot partition
  803. Start = DriveLayout->PartitionEntry;
  804. cnt = 0;
  805. /*
  806. _ultot( DriveLayout->Signature, temp, 16 );
  807. if( lstrcmpi( temp, Signature ) )
  808. goto cleanexit;
  809. */
  810. Sig = _tcstoul( Signature, NULL, 16 );
  811. if( Sig != DriveLayout->Signature )
  812. goto cleanexit;
  813. for( i = Start; cnt < DriveLayout->PartitionCount; i++ ){
  814. cnt++;
  815. if( i->BootIndicator == TRUE ){
  816. if( Action == WINNT_DONT_MATCH_PARTITION ){
  817. *Disk_Num = i->PartitionNumber;
  818. Found = TRUE;
  819. goto cleanexit;
  820. }
  821. if( Action == WINNT_MATCH_PARTITION_NUMBER ){
  822. if( *Disk_Num == i->PartitionNumber ){
  823. Found = TRUE;
  824. goto cleanexit;
  825. }
  826. }else{
  827. if( Starting_Off->QuadPart == i->StartingOffset.QuadPart ){
  828. Found = TRUE;
  829. goto cleanexit;
  830. }
  831. }
  832. break;
  833. }
  834. }
  835. }
  836. cleanexit:
  837. if( hDisk != INVALID_HANDLE_VALUE )
  838. CloseHandle( hDisk );
  839. return Found;
  840. }
  841. DWORD
  842. FindSystemPartitionSignature(
  843. IN LPCTSTR AdapterKeyName,
  844. OUT LPTSTR Signature
  845. )
  846. /*++
  847. Routine Description:
  848. This routine fetches the disk signature for the first disk that the BIOS sees. This has to be the disk that we boot from on x86s.
  849. It is at location <AdapterKeyName>\<some Bus No.>\DiskController\0\DiskPeripheral\0\Identifier
  850. Arguments:
  851. Signature - If successful will contain the signature of the disk we boot off from in Hex.
  852. Return Value:
  853. Returns ERROR_SUCCESS if successful, otherwise it contains the error code.
  854. --*/
  855. {
  856. DWORD Err, dwSize;
  857. HKEY hkey, BusKey, Controller, SystemDiskKey;
  858. int busnumber;
  859. TCHAR BusString[20], Identifier[100];
  860. Err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  861. AdapterKeyName,
  862. 0,
  863. KEY_READ,
  864. &hkey );
  865. if( Err != ERROR_SUCCESS )
  866. return Err;
  867. // Start enumerating the buses
  868. for( busnumber=0; ;busnumber++){
  869. wsprintf( BusString, TEXT("%d"), busnumber );
  870. Err = RegOpenKeyEx( hkey,
  871. BusString,
  872. 0,
  873. KEY_READ,
  874. &BusKey );
  875. if( Err != ERROR_SUCCESS ){
  876. RegCloseKey( hkey );
  877. return Err;
  878. }
  879. Err = RegOpenKeyEx( BusKey,
  880. TEXT("DiskController"),
  881. 0,
  882. KEY_READ,
  883. &Controller );
  884. RegCloseKey(BusKey); // Not needed anymore
  885. if( Err != ERROR_SUCCESS ) // Move on to next bus
  886. continue;
  887. RegCloseKey( hkey ); // Not needed anymore
  888. Err = RegOpenKeyEx( Controller,
  889. TEXT("0\\DiskPeripheral\\0"),
  890. 0,
  891. KEY_READ,
  892. &SystemDiskKey );
  893. if( Err != ERROR_SUCCESS ){
  894. RegCloseKey( Controller );
  895. return Err;
  896. }
  897. RegCloseKey( Controller ); // Not needed anymore
  898. dwSize = sizeof(Identifier);
  899. Err = RegQueryValueEx( SystemDiskKey,
  900. TEXT("Identifier"),
  901. NULL,
  902. NULL,
  903. (PBYTE) Identifier,
  904. &dwSize);
  905. if( Err != ERROR_SUCCESS ){
  906. RegCloseKey( SystemDiskKey );
  907. return Err;
  908. }
  909. if( Identifier && (lstrlen(Identifier) > 9 ) ){
  910. lstrcpy( Signature,Identifier+9);
  911. *_tcsrchr( Signature,TEXT('-') ) = 0;
  912. RegCloseKey( SystemDiskKey );
  913. return ERROR_SUCCESS;
  914. }
  915. else{
  916. RegCloseKey( SystemDiskKey );
  917. return Err;
  918. }
  919. }
  920. // Should never get here
  921. RegCloseKey( hkey );
  922. return ERROR_PATH_NOT_FOUND;
  923. }
  924. BOOL
  925. InitializeArcStuff(
  926. IN HWND Parent
  927. )
  928. {
  929. HMODULE NtdllLib, Kernel32Lib;
  930. if(ISNT()) {
  931. //
  932. // On NT ntdll.dll had better be already loaded.
  933. //
  934. NtdllLib = LoadLibrary(TEXT("NTDLL"));
  935. if(!NtdllLib) {
  936. MessageBoxFromMessage(
  937. Parent,
  938. MSG_UNKNOWN_SYSTEM_ERROR,
  939. FALSE,
  940. AppTitleStringId,
  941. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  942. GetLastError()
  943. );
  944. return(FALSE);
  945. }
  946. (FARPROC)NtOpenSymLinkRoutine = GetProcAddress(NtdllLib,"NtOpenSymbolicLinkObject");
  947. (FARPROC)NtQuerSymLinkRoutine = GetProcAddress(NtdllLib,"NtQuerySymbolicLinkObject");
  948. (FARPROC)NtOpenDirRoutine = GetProcAddress(NtdllLib,"NtOpenDirectoryObject");
  949. (FARPROC)NtQuerDirRoutine = GetProcAddress(NtdllLib,"NtQueryDirectoryObject");
  950. if(!NtOpenSymLinkRoutine || !NtQuerSymLinkRoutine || !NtOpenDirRoutine || !NtQuerDirRoutine) {
  951. MessageBoxFromMessage(
  952. Parent,
  953. MSG_UNKNOWN_SYSTEM_ERROR,
  954. FALSE,
  955. AppTitleStringId,
  956. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  957. GetLastError()
  958. );
  959. FreeLibrary(NtdllLib);
  960. return(FALSE);
  961. }
  962. //
  963. // We don't need the extraneous handle any more.
  964. //
  965. FreeLibrary(NtdllLib);
  966. if(BUILDNUM() >= 1877){
  967. //Load the kernel32.dll stuff too
  968. Kernel32Lib = LoadLibrary(TEXT("KERNEL32"));
  969. if(!Kernel32Lib) {
  970. MessageBoxFromMessage(
  971. Parent,
  972. MSG_UNKNOWN_SYSTEM_ERROR,
  973. FALSE,
  974. AppTitleStringId,
  975. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  976. GetLastError()
  977. );
  978. return(FALSE);
  979. }
  980. (FARPROC)pFindFirstVolume = GetProcAddress(Kernel32Lib,"FindFirstVolumeW");
  981. (FARPROC)pFindNextVolume = GetProcAddress(Kernel32Lib,"FindNextVolumeW");
  982. (FARPROC)pFindVolumeClose = GetProcAddress(Kernel32Lib,"FindVolumeClose");
  983. (FARPROC)pGetVolumeNameForVolumeMountPoint = GetProcAddress(Kernel32Lib,"GetVolumeNameForVolumeMountPointW");
  984. if(!pFindFirstVolume || !pFindNextVolume ) {
  985. MessageBoxFromMessage(
  986. Parent,
  987. MSG_UNKNOWN_SYSTEM_ERROR,
  988. FALSE,
  989. AppTitleStringId,
  990. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  991. GetLastError()
  992. );
  993. FreeLibrary(Kernel32Lib);
  994. return(FALSE);
  995. }
  996. FreeLibrary(Kernel32Lib);
  997. }
  998. }
  999. if(!x86DetermineSystemPartition(Parent,&SystemPartitionDriveLetter)) {
  1000. MessageBoxFromMessage(
  1001. Parent,
  1002. MSG_SYSTEM_PARTITION_INVALID,
  1003. FALSE,
  1004. AppTitleStringId,
  1005. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1006. );
  1007. return(FALSE);
  1008. }
  1009. SystemPartitionDriveLetters[0] = SystemPartitionDriveLetter;
  1010. SystemPartitionDriveLetters[1] = 0;
  1011. LocalBootDirectory[0] = SystemPartitionDriveLetter;
  1012. LocalBootDirectory[1] = TEXT(':');
  1013. LocalBootDirectory[2] = TEXT('\\');
  1014. lstrcpy(LocalBootDirectory+3,LOCAL_BOOT_DIR);
  1015. if(IsNEC98()) {
  1016. LocalBackupDirectory[0] = SystemPartitionDriveLetter;
  1017. LocalBackupDirectory[1] = TEXT(':');
  1018. LocalBackupDirectory[2] = TEXT('\\');
  1019. lstrcpy(LocalBackupDirectory+3,LOCAL_BACKUP_DIR);
  1020. }
  1021. return(TRUE);
  1022. }
  1023. DWORD
  1024. GetNT4SystemPartition(
  1025. IN LPTSTR Signature,
  1026. OUT LPTSTR SysPart
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. This routine enumerates all the volumes and if successful returns the \Device\Harddisk#\Partition# name of the system partition
  1031. on systems prior to NT 5 Beta 2.
  1032. Arguments:
  1033. Signature - supplies a disk signature of the Boot disk so that it can be compared against. The details
  1034. to getting this value are detailed in the comments for x86DetermineSystemPartition.
  1035. SysPart - If successful, will contain a name of form \Device\Harddisk#\Partition# for the System Partition (the one we use to boot)
  1036. Return Value:
  1037. Returns NO_ERROR if successful, otherwise it contains the error code.
  1038. --*/
  1039. {
  1040. NTSTATUS Status;
  1041. UNICODE_STRING UnicodeString;
  1042. OBJECT_ATTRIBUTES Attributes;
  1043. HANDLE DirectoryHandle;
  1044. POBJECT_DIRECTORY_INFORMATION DirInfo;
  1045. UCHAR DirInfoBuffer[ BUFFERSIZE ];
  1046. TCHAR DirName[20];
  1047. TCHAR ObjName[1024];
  1048. TCHAR Buffer[1024];
  1049. WCHAR pSignature[512];
  1050. ULONG Context = 0;
  1051. ULONG ReturnedLength, PartNum;
  1052. LPTSTR Num_Str;
  1053. RtlZeroMemory( DirInfoBuffer, BUFFERSIZE );
  1054. #ifdef UNICODE
  1055. lstrcpyW( pSignature,Signature);
  1056. #else
  1057. MultiByteToWideChar(
  1058. CP_ACP,
  1059. 0,
  1060. Signature,
  1061. -1,
  1062. pSignature,
  1063. (sizeof(pSignature)/sizeof(WCHAR))
  1064. );
  1065. #endif
  1066. //We open the \?? Directory
  1067. lstrcpy( DirName, TEXT("\\DosDevices") );
  1068. UnicodeString.Buffer = (PWSTR)DirName;
  1069. UnicodeString.Length = lstrlenW(UnicodeString.Buffer)*sizeof(WCHAR);
  1070. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  1071. InitializeObjectAttributes( &Attributes,
  1072. &UnicodeString,
  1073. OBJ_CASE_INSENSITIVE,
  1074. NULL,
  1075. NULL
  1076. );
  1077. Status = (*NtOpenDirRoutine)( &DirectoryHandle,
  1078. DIRECTORY_QUERY,
  1079. &Attributes
  1080. );
  1081. if (!NT_SUCCESS( Status ))
  1082. return(Status);
  1083. DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer;
  1084. // Go through the directory looking for all instances beginning with PhysicalDrive#
  1085. for (Status = (*NtQuerDirRoutine)( DirectoryHandle,
  1086. DirInfoBuffer,
  1087. BUFFERSIZE,
  1088. FALSE,
  1089. TRUE,
  1090. &Context,
  1091. &ReturnedLength );
  1092. NT_SUCCESS( Status );
  1093. Status = (*NtQuerDirRoutine)( DirectoryHandle,
  1094. DirInfoBuffer,
  1095. BUFFERSIZE,
  1096. FALSE,
  1097. FALSE,
  1098. &Context,
  1099. &ReturnedLength ) ) {
  1100. //
  1101. // Check the status of the operation.
  1102. //
  1103. if (!NT_SUCCESS( Status ) && (Status != STATUS_NO_MORE_ENTRIES))
  1104. break;
  1105. DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer[0];
  1106. while( TRUE ){
  1107. //
  1108. // Check if there is another record. If there isn't, then get out
  1109. // of the loop now
  1110. //
  1111. if (DirInfo->Name.Length == 0) {
  1112. break;
  1113. }
  1114. memmove( ObjName, DirInfo->Name.Buffer, DirInfo->Name.Length );
  1115. ObjName[DirInfo->Name.Length/(sizeof(WCHAR))] = 0;
  1116. if( _tcsstr(ObjName, TEXT("PhysicalDrive") )){
  1117. Num_Str = ObjName+13;
  1118. wsprintf(Buffer,TEXT("\\\\.\\%s"),ObjName);
  1119. if( DoDiskSignaturesCompare( (LPCTSTR)pSignature, Buffer, &PartNum, WINNT_DONT_MATCH_PARTITION ) ){
  1120. wsprintf(SysPart,TEXT("\\Device\\Harddisk%s\\Partition%lu"),Num_Str, PartNum);
  1121. Status = ERROR_SUCCESS;
  1122. goto cleanup;
  1123. }
  1124. }
  1125. //
  1126. // There is another record so advance DirInfo to the next entry
  1127. //
  1128. DirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) DirInfo) +
  1129. sizeof( OBJECT_DIRECTORY_INFORMATION ) );
  1130. }
  1131. RtlZeroMemory( DirInfoBuffer, BUFFERSIZE );
  1132. }
  1133. cleanup:
  1134. CloseHandle( DirectoryHandle );
  1135. return( Status );
  1136. }
  1137. #if defined(UNICODE)
  1138. #define EMPTY_STRING L""
  1139. #define DEF_INF_BUFFER_SIZE 1024
  1140. #define MULTI_SZ_NEXT_STRING(x) ((x) + wcslen(x) + 1)
  1141. #ifndef ARRAYSIZE
  1142. #define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
  1143. #endif
  1144. BOOL
  1145. GetSystemRootNtPath(
  1146. OUT LPWSTR NtPath,
  1147. IN USHORT NtPathBufferLen
  1148. )
  1149. {
  1150. UNICODE_STRING UnicodeString;
  1151. OBJECT_ATTRIBUTES Obja;
  1152. HANDLE ObjectHandle;
  1153. NTSTATUS Status;
  1154. WCHAR Buffer[512];
  1155. PWSTR ntPath;
  1156. #define SYSTEM_ROOT_NAME L"\\SystemRoot"
  1157. UnicodeString.Buffer = SYSTEM_ROOT_NAME;
  1158. UnicodeString.Length = (ARRAYSIZE(SYSTEM_ROOT_NAME) - 1) * sizeof(WCHAR);
  1159. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  1160. InitializeObjectAttributes(
  1161. &Obja,
  1162. &UnicodeString,
  1163. OBJ_CASE_INSENSITIVE,
  1164. NULL,
  1165. NULL
  1166. );
  1167. Status = (*NtOpenSymLinkRoutine)(
  1168. &ObjectHandle,
  1169. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  1170. &Obja
  1171. );
  1172. if(NT_SUCCESS(Status)) {
  1173. //
  1174. // Query the object to get the link target.
  1175. //
  1176. UnicodeString.Buffer = NtPath;
  1177. UnicodeString.Length = 0;
  1178. UnicodeString.MaximumLength = NtPathBufferLen;
  1179. Status = (*NtQuerSymLinkRoutine)(ObjectHandle,&UnicodeString,NULL);
  1180. CloseHandle(ObjectHandle);
  1181. if(NT_SUCCESS(Status)) {
  1182. UnicodeString.Buffer[UnicodeString.Length/sizeof(WCHAR)] = 0;
  1183. return TRUE;
  1184. }
  1185. }
  1186. return FALSE;
  1187. }
  1188. BOOL
  1189. DoesCurrentSystemHasThirdPartyKernel(
  1190. VOID
  1191. )
  1192. {
  1193. WCHAR BootIniName[16];
  1194. PWSTR pSectionsBuffer = NULL;
  1195. PWSTR pKeysBuffer = NULL;
  1196. PWSTR pString = NULL;
  1197. PWSTR pNtPathString = NULL;
  1198. PWSTR pNtPathSystemRoot = NULL;
  1199. PWSTR pKey = NULL;
  1200. PWSTR pDirectory;
  1201. UINT sizeOfSectionBuffer = 0;
  1202. UINT sizeOfBuffer = 0;
  1203. UINT directoryNameSize;
  1204. BOOL bResult = FALSE;
  1205. wsprintfW(BootIniName, L"%c:\\BOOT.INI", SystemPartitionDriveLetter);
  1206. __try{
  1207. do{
  1208. if(pKeysBuffer){
  1209. FREE(pKeysBuffer);
  1210. }
  1211. sizeOfSectionBuffer += DEF_INF_BUFFER_SIZE;
  1212. pKeysBuffer = (PWSTR)MALLOC(sizeOfSectionBuffer * sizeof (WCHAR));
  1213. if(!pKeysBuffer){
  1214. __leave;
  1215. }
  1216. pKeysBuffer[0] = '\0';
  1217. }while((sizeOfSectionBuffer - 2) ==
  1218. GetPrivateProfileStringW(L"operating systems",
  1219. NULL,
  1220. EMPTY_STRING,
  1221. pKeysBuffer,
  1222. sizeOfSectionBuffer,
  1223. BootIniName));
  1224. if(!pKeysBuffer[0]){
  1225. __leave;
  1226. }
  1227. sizeOfBuffer = DEF_INF_BUFFER_SIZE;
  1228. pString = (PWSTR)MALLOC(sizeOfBuffer * sizeof (WCHAR));
  1229. if(!pString){
  1230. __leave;
  1231. }
  1232. pNtPathString = (PWSTR)MALLOC(sizeOfBuffer * sizeof (WCHAR));
  1233. if(!pNtPathString){
  1234. __leave;
  1235. }
  1236. for(pKey = pKeysBuffer; pKey[0]; pKey = MULTI_SZ_NEXT_STRING(pKey))
  1237. {
  1238. GetPrivateProfileStringW(L"operating systems",
  1239. pKey,
  1240. EMPTY_STRING,
  1241. pString,
  1242. sizeOfBuffer,
  1243. BootIniName);
  1244. _wcslwr(pString);
  1245. if(!wcsstr(pString, L"/kernel")){
  1246. continue;
  1247. }
  1248. pDirectory = wcschr(pKey, '\\');
  1249. MYASSERT(pDirectory);
  1250. if(pDirectory){
  1251. directoryNameSize = wcslen(pDirectory) * sizeof(WCHAR);
  1252. pDirectory[0] = '\0';
  1253. }
  1254. else{
  1255. directoryNameSize = 0;
  1256. }
  1257. if(!ArcPathToNtPath(pKey, pNtPathString, sizeOfBuffer - directoryNameSize)){
  1258. MYASSERT(FALSE);
  1259. continue;
  1260. }
  1261. if(pDirectory){
  1262. pDirectory[0] = '\\';
  1263. wcscat(pNtPathString, pDirectory);
  1264. }
  1265. if(!pNtPathSystemRoot){
  1266. pNtPathSystemRoot = (PWSTR)MALLOC(sizeOfBuffer * sizeof (WCHAR));
  1267. if(!pNtPathSystemRoot){
  1268. __leave;
  1269. }
  1270. if(!GetSystemRootNtPath(pNtPathSystemRoot, sizeOfBuffer * sizeof (WCHAR))){
  1271. MYASSERT(FALSE);
  1272. }
  1273. }
  1274. if(!_wcsicmp(pNtPathString, pNtPathSystemRoot)){
  1275. bResult = TRUE;
  1276. __leave;
  1277. }
  1278. }
  1279. }
  1280. __finally{
  1281. DWORD rc = GetLastError();
  1282. if(pKeysBuffer){
  1283. FREE(pKeysBuffer);
  1284. }
  1285. if(pString){
  1286. FREE(pString);
  1287. }
  1288. if(pNtPathString){
  1289. FREE(pNtPathString);
  1290. }
  1291. if(pNtPathSystemRoot){
  1292. FREE(pNtPathSystemRoot);
  1293. }
  1294. SetLastError (rc);
  1295. }
  1296. return bResult;
  1297. }
  1298. #endif
  1299. BOOL
  1300. SystemKernelCheck(
  1301. PCOMPAIBILITYCALLBACK CompatibilityCallback,
  1302. LPVOID Context
  1303. )
  1304. {
  1305. BOOL bResult = TRUE;
  1306. PWSTR Buffer;
  1307. #if defined(UNICODE) && defined(_X86_)
  1308. COMPATIBILITY_ENTRY CompEntry;
  1309. if(!DoesCurrentSystemHasThirdPartyKernel()){
  1310. return FALSE;
  1311. }
  1312. FormatMessageW(
  1313. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1314. hInst,
  1315. MSG_SYSTEM_HAS_THIRD_PARTY_KERNEL,
  1316. 0,
  1317. (PWSTR)&Buffer,
  1318. 0,
  1319. NULL
  1320. );
  1321. CompEntry.Description = Buffer;
  1322. CompEntry.HtmlName = TEXT("compdata\\krnlchk.htm");
  1323. CompEntry.TextName = TEXT("compdata\\krnlchk.htm");
  1324. CompEntry.RegKeyName = NULL;
  1325. CompEntry.RegValName = NULL;
  1326. CompEntry.RegValDataSize = 0;
  1327. CompEntry.RegValData = NULL;
  1328. CompEntry.SaveValue = NULL;
  1329. CompEntry.Flags = 0;
  1330. CompEntry.InfName = NULL;
  1331. CompEntry.InfSection = NULL;
  1332. bResult = CompatibilityCallback(&CompEntry, Context);
  1333. LocalFree(Buffer);
  1334. #endif
  1335. return bResult;
  1336. }