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.

1422 lines
42 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. sparc.c
  5. Abstract:
  6. Functions to deal with ARC paths and variables.
  7. Author:
  8. Ted Miller (tedm) 22-Sep-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. //
  14. // Define maximum number of components in a semi-colon separated list
  15. // of arc paths.
  16. //
  17. #define MAX_COMPONENTS 20
  18. //
  19. // We maintain a list of all arcnames in the system and their NT equivalents.
  20. // This makes translations very easy.
  21. //
  22. typedef struct _ARCNAME_TRANSLATION {
  23. struct _ARCNAME_TRANSLATION *Next;
  24. PWSTR ArcPath;
  25. PWSTR NtPath;
  26. } ARCNAME_TRANSLATION, *PARCNAME_TRANSLATION;
  27. PARCNAME_TRANSLATION ArcNameTranslations;
  28. //
  29. // Function prototypes.
  30. //
  31. VOID
  32. SppFreeComponents(
  33. IN PVOID *EnvVarComponents
  34. );
  35. VOID
  36. SppInitializeHardDiskArcNames(
  37. VOID
  38. );
  39. extern PSETUP_COMMUNICATION CommunicationParams;
  40. VOID
  41. SpInitializeArcNames(
  42. PVIRTUAL_OEM_SOURCE_DEVICE OemDevices
  43. )
  44. {
  45. UNICODE_STRING UnicodeString;
  46. HANDLE DirectoryHandle;
  47. HANDLE ObjectHandle;
  48. OBJECT_ATTRIBUTES Obja;
  49. NTSTATUS Status;
  50. BOOLEAN RestartScan;
  51. ULONG Context;
  52. BOOLEAN MoreEntries;
  53. PWSTR ArcName;
  54. POBJECT_DIRECTORY_INFORMATION DirInfo;
  55. WCHAR ArcNameDirectory[] = L"\\ArcName";
  56. PARCNAME_TRANSLATION Translation;
  57. //
  58. // Only call this routine once.
  59. //
  60. ASSERT(ArcNameTranslations == NULL);
  61. //
  62. // First, do hard disks specially. For each hard disk in the system,
  63. // open it and check its signature against those in the firmware
  64. // disk information.
  65. //
  66. SppInitializeHardDiskArcNames();
  67. //
  68. // Open the \ArcName directory.
  69. //
  70. INIT_OBJA(&Obja,&UnicodeString,ArcNameDirectory);
  71. Status = ZwOpenDirectoryObject(&DirectoryHandle,DIRECTORY_ALL_ACCESS,&Obja);
  72. if(NT_SUCCESS(Status)) {
  73. RestartScan = TRUE;
  74. Context = 0;
  75. MoreEntries = TRUE;
  76. do {
  77. Status = SpQueryDirectoryObject(
  78. DirectoryHandle,
  79. RestartScan,
  80. &Context
  81. );
  82. if(NT_SUCCESS(Status)) {
  83. DirInfo = (POBJECT_DIRECTORY_INFORMATION)
  84. ((PSERVICE_QUERY_DIRECTORY_OBJECT)&CommunicationParams->Buffer)->Buffer;
  85. SpStringToLower(DirInfo->Name.Buffer);
  86. //
  87. // Make sure this name is a symbolic link.
  88. //
  89. if(DirInfo->Name.Length
  90. && (DirInfo->TypeName.Length >= (sizeof(L"SymbolicLink") - sizeof(WCHAR)))
  91. && !_wcsnicmp(DirInfo->TypeName.Buffer,L"SymbolicLink",12))
  92. {
  93. ArcName = SpMemAlloc(DirInfo->Name.Length + sizeof(ArcNameDirectory) + sizeof(WCHAR));
  94. wcscpy(ArcName,ArcNameDirectory);
  95. SpConcatenatePaths(ArcName,DirInfo->Name.Buffer);
  96. //
  97. // We have the entire arc name in ArcName. Now open it as a symbolic link.
  98. //
  99. INIT_OBJA(&Obja,&UnicodeString,ArcName);
  100. Status = ZwOpenSymbolicLinkObject(
  101. &ObjectHandle,
  102. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  103. &Obja
  104. );
  105. if(NT_SUCCESS(Status)) {
  106. //
  107. // Finally, query the object to get the link target.
  108. //
  109. UnicodeString.Buffer = TemporaryBuffer;
  110. UnicodeString.Length = 0;
  111. UnicodeString.MaximumLength = sizeof(TemporaryBuffer);
  112. Status = ZwQuerySymbolicLinkObject(
  113. ObjectHandle,
  114. &UnicodeString,
  115. NULL
  116. );
  117. if(NT_SUCCESS(Status)) {
  118. //
  119. // nul-terminate the returned string
  120. //
  121. UnicodeString.Buffer[UnicodeString.Length/sizeof(WCHAR)] = 0;
  122. //
  123. // Ignore this entry if it's a hard disk or hard disk partition.
  124. //
  125. if(_wcsnicmp(UnicodeString.Buffer,L"\\Device\\Harddisk",16)) {
  126. //
  127. // Create an arcname translation entry.
  128. //
  129. Translation = SpMemAlloc(sizeof(ARCNAME_TRANSLATION));
  130. Translation->Next = ArcNameTranslations;
  131. ArcNameTranslations = Translation;
  132. //
  133. // Leave out the \ArcName\ part.
  134. //
  135. Translation->ArcPath = SpNormalizeArcPath(
  136. ArcName
  137. + (sizeof(ArcNameDirectory)/sizeof(WCHAR))
  138. );
  139. Translation->NtPath = SpDupStringW(UnicodeString.Buffer);
  140. }
  141. } else {
  142. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to query symbolic link %ws (%lx)\n",ArcName,Status));
  143. }
  144. ZwClose(ObjectHandle);
  145. } else {
  146. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open symbolic link %ws (%lx)\n",ArcName,Status));
  147. }
  148. SpMemFree(ArcName);
  149. }
  150. } else {
  151. MoreEntries = FALSE;
  152. if(Status == STATUS_NO_MORE_ENTRIES) {
  153. Status = STATUS_SUCCESS;
  154. }
  155. }
  156. RestartScan = FALSE;
  157. } while(MoreEntries);
  158. ZwClose(DirectoryHandle);
  159. } else {
  160. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open \\ArcName directory (%lx)\n",Status));
  161. }
  162. //
  163. // Add OEM virtual device arc name translations if any at
  164. // the front of the list
  165. //
  166. if (NT_SUCCESS(Status) && OemDevices) {
  167. PVIRTUAL_OEM_SOURCE_DEVICE CurrDevice = OemDevices;
  168. WCHAR RamDeviceName[MAX_PATH];
  169. while (CurrDevice) {
  170. PARCNAME_TRANSLATION NewTranslation;
  171. NewTranslation = SpMemAlloc(sizeof(ARCNAME_TRANSLATION));
  172. if (!NewTranslation) {
  173. Status = STATUS_NO_MEMORY;
  174. break;
  175. }
  176. //
  177. // create the new translation
  178. //
  179. RamDeviceName[0] = UNICODE_NULL;
  180. RtlZeroMemory(NewTranslation, sizeof(ARCNAME_TRANSLATION));
  181. NewTranslation->ArcPath = SpDupStringW(CurrDevice->ArcDeviceName);
  182. swprintf(RamDeviceName, L"%ws%d", RAMDISK_DEVICE_NAME, CurrDevice->DeviceId);
  183. NewTranslation->NtPath = SpDupStringW(RamDeviceName);
  184. //
  185. // add the new translation at the start of the linked list
  186. //
  187. NewTranslation->Next = ArcNameTranslations;
  188. ArcNameTranslations = NewTranslation;
  189. //
  190. // process the next device
  191. //
  192. CurrDevice = CurrDevice->Next;
  193. }
  194. }
  195. //
  196. // If we couldn't gather arcname translations, something is
  197. // really wrong with the system.
  198. //
  199. if(!NT_SUCCESS(Status)) {
  200. SpStartScreen(
  201. SP_SCRN_COULDNT_INIT_ARCNAMES,
  202. 3,
  203. HEADER_HEIGHT+1,
  204. FALSE,
  205. FALSE,
  206. DEFAULT_ATTRIBUTE
  207. );
  208. if(KbdLayoutInitialized) {
  209. SpContinueScreen(
  210. SP_SCRN_F3_TO_REBOOT,
  211. 3,
  212. 1,
  213. FALSE,
  214. DEFAULT_ATTRIBUTE
  215. );
  216. SpDisplayStatusText(SP_STAT_F3_EQUALS_EXIT, DEFAULT_STATUS_ATTRIBUTE);
  217. SpInputDrain();
  218. while(SpInputGetKeypress() != KEY_F3);
  219. SpDone(0, FALSE, TRUE);
  220. } else {
  221. //
  222. // we haven't loaded the layout dll yet, so we can't prompt for a keypress to reboot
  223. //
  224. SpContinueScreen(
  225. SP_SCRN_POWER_DOWN,
  226. 3,
  227. 1,
  228. FALSE,
  229. DEFAULT_ATTRIBUTE
  230. );
  231. SpDisplayStatusText(SP_STAT_KBD_HARD_REBOOT, DEFAULT_STATUS_ATTRIBUTE);
  232. while(TRUE); // Loop forever
  233. }
  234. }
  235. }
  236. VOID
  237. SpFreeArcNames(
  238. VOID
  239. )
  240. {
  241. PARCNAME_TRANSLATION pTrans,pNext;
  242. for(pTrans=ArcNameTranslations; pTrans; pTrans=pNext) {
  243. pNext = pTrans->Next;
  244. SpMemFree(pTrans->ArcPath);
  245. SpMemFree(pTrans->NtPath);
  246. SpMemFree(pTrans);
  247. }
  248. ArcNameTranslations = NULL;
  249. }
  250. VOID
  251. SppInitializeHardDiskArcNames(
  252. VOID
  253. )
  254. /*++
  255. Routine Description:
  256. This routine attempts to match NT-visible hard disks to their
  257. firmware-visible ARC equivalents. The basic algorithm is as
  258. follows:
  259. A match occurs when the disk's signature, checksum, and
  260. valid partition indicator match the values passed by
  261. setupldr in the ARC_DISK_INFORMATION structure.
  262. If no match for the NT disk is found, no arcname is
  263. created. Thus, the user may not install NT onto this
  264. drive. (the case where the disk will be made visible
  265. to NTLDR through the installation of NTBOOTDD.SYS is
  266. a special case that is handled separately)
  267. If a single match is found, we have found a simple
  268. ARC<->NT translation. The arcname is created.
  269. If more than one match is found, we have a complicated
  270. ARC<->NT translation. We assume that there is only one
  271. valid arcname for any disk. (This is a safe assumption
  272. only when we booted via SETUPLDR, since NTLDR may load
  273. NTBOOTDD.SYS and cause SCSI disks that have the BIOS
  274. enabled to be visible through both a scsi()... name and
  275. a multi()... name.) Thus this means we have two disks
  276. in the system whose first sector is identical. In this
  277. case we do some heuristic comparisons between the ARC
  278. name and the NT name to attempt to resolve this.
  279. Arguments:
  280. None. All ARC name translations will be added to the global
  281. ArcNameTranslations list.
  282. Return Value:
  283. None.
  284. --*/
  285. {
  286. PWSTR DiskName;
  287. ULONG disk;
  288. ULONG DiskCount;
  289. PARCNAME_TRANSLATION Translation;
  290. HANDLE hPartition;
  291. NTSTATUS Status;
  292. PVOID Buffer;
  293. IO_STATUS_BLOCK StatusBlock;
  294. ULONG BufferSize;
  295. PDISK_GEOMETRY Geometry;
  296. LARGE_INTEGER Offset;
  297. BOOLEAN ValidPartitionTable;
  298. ULONG Signature;
  299. ULONG i;
  300. ULONG Checksum;
  301. PDISK_SIGNATURE_INFORMATION DiskSignature;
  302. PDISK_SIGNATURE_INFORMATION DupSignature;
  303. //
  304. // Allocate buffer for disk name.
  305. //
  306. DiskName = SpMemAlloc(64 * sizeof(WCHAR));
  307. DiskCount = IoGetConfigurationInformation()->DiskCount;
  308. //
  309. // For each hard disk in the system, open partition 0 and read sector 0.
  310. //
  311. for(disk=0; disk<DiskCount; disk++) {
  312. #if defined(_AMD64_) || defined(_X86_)
  313. BOOLEAN Matched = FALSE;
  314. enum {
  315. NoEZDisk,
  316. EZDiskDetected,
  317. NeedToMark
  318. };
  319. CHAR EZDiskStatus = NoEZDisk;
  320. #endif // defined(_AMD64_) || defined(_X86_)
  321. swprintf(DiskName, L"\\Device\\HardDisk%u", disk);
  322. //
  323. // open the partition read-write since we may need to mark EZDISKs
  324. //
  325. Status = SpOpenPartition(DiskName,0,&hPartition,TRUE);
  326. if(NT_SUCCESS(Status)) {
  327. //
  328. // Initially use a 1k buffer to read partition information.
  329. //
  330. BufferSize = 1024;
  331. Buffer = TemporaryBuffer;
  332. //
  333. // Issue device control to get partition information.
  334. //
  335. retrydevctrl:
  336. RtlZeroMemory(Buffer, BufferSize);
  337. Status = ZwDeviceIoControlFile( hPartition,
  338. NULL,
  339. NULL,
  340. NULL,
  341. &StatusBlock,
  342. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  343. NULL,
  344. 0,
  345. Buffer,
  346. BufferSize );
  347. if (Status==STATUS_BUFFER_TOO_SMALL) {
  348. //
  349. // Double buffer size and try again.
  350. //
  351. BufferSize = BufferSize * 2;
  352. ASSERT(BufferSize <= sizeof(TemporaryBuffer));
  353. goto retrydevctrl;
  354. }
  355. Geometry = (PDISK_GEOMETRY)Buffer;
  356. if (!NT_SUCCESS(Status) || (0 == Geometry->BytesPerSector)) {
  357. //
  358. // Skip this disk
  359. //
  360. goto errSkipDisk;
  361. }
  362. //
  363. // Read the first two sectors off the drive.
  364. //
  365. BufferSize = Geometry->BytesPerSector;
  366. Buffer = ALIGN(Buffer, BufferSize);
  367. Offset.QuadPart = 0;
  368. Status = ZwReadFile(hPartition,
  369. NULL,
  370. NULL,
  371. NULL,
  372. &StatusBlock,
  373. Buffer,
  374. BufferSize * 2,
  375. &Offset,
  376. NULL);
  377. if (!NT_SUCCESS(Status)) {
  378. //
  379. // Skip this disk
  380. //
  381. goto errSkipDisk;
  382. }
  383. #if defined(_AMD64_) || defined(_X86_)
  384. //
  385. // Check for EZDrive disk. If we have one, use sector 1
  386. // instead of sector 0.
  387. //
  388. // We do this only on amd64/x86 because the firmware doesn't
  389. // know about EZDrive, and so we must use sector 0 to match what
  390. // the firmware did.
  391. //
  392. if((BufferSize >= 512)
  393. && (((PUSHORT)Buffer)[510 / 2] == 0xaa55)
  394. && ((((PUCHAR)Buffer)[0x1c2] == 0x54) || (((PUCHAR)Buffer)[0x1c2] == 0x55))) {
  395. EZDiskStatus = EZDiskDetected;
  396. ezdisk:
  397. //
  398. // we need to try sector 1
  399. //
  400. Buffer = (PUCHAR) Buffer + BufferSize;
  401. }
  402. #endif // defined(_AMD64_) || defined(_X86_)
  403. //
  404. // Now we have the sector, we can compute the signature,
  405. // the valid partition indicator, and the checksum.
  406. //
  407. if (!IsNEC_98) { //NEC98
  408. Signature = ((PULONG)Buffer)[PARTITION_TABLE_OFFSET/2-1];
  409. } //NEC98
  410. if ((!IsNEC_98) ? (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) :
  411. ((((PUSHORT)Buffer)[BufferSize/2 - 1 ] != BOOT_RECORD_SIGNATURE) ||
  412. (BufferSize == 256))) { //NEC98
  413. ValidPartitionTable = FALSE;
  414. } else {
  415. ValidPartitionTable = TRUE;
  416. }
  417. Checksum = 0;
  418. for (i=0;i<128;i++) {
  419. Checksum += ((PULONG)Buffer)[i];
  420. }
  421. Checksum = 0-Checksum;
  422. //
  423. // Scan the list of arc disk information attempting to match
  424. // signatures
  425. //
  426. //
  427. // Dump the signature info:
  428. //
  429. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SppInitializeHardDiskArcNames : About to start searching for disk with signature: 0x%08lx\n", Signature));
  430. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SppInitializeHardDiskArcNames : About to start searching for disk with checksum: 0x%08lx\n", Checksum));
  431. DiskSignature = DiskSignatureInformation;
  432. i = 0;
  433. while( DiskSignature != NULL ) {
  434. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SppInitializeHardDiskArcNames : Signature Info %d\n================================================\n", i ));
  435. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " Signature: 0x%08lx\n", DiskSignature->Signature ));
  436. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " CheckSum: 0x%08lx\n", DiskSignature->CheckSum ));
  437. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " ArcPath: %ws\n", DiskSignature->ArcPath ));
  438. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " xInt13: %ws\n\n", DiskSignature->xInt13 ? L"yes" : L"no" ));
  439. i++;
  440. DiskSignature = DiskSignature->Next;
  441. }
  442. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "\n\n"));
  443. DiskSignature = DiskSignatureInformation;
  444. while (DiskSignature != NULL) {
  445. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current signature: 0x%08lx\n", DiskSignature->Signature));
  446. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current checksum: 0x%08lx\n", DiskSignature->CheckSum));
  447. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current ArcPath: %ws\n", DiskSignature->ArcPath));
  448. if( DiskSignature->Signature == Signature ) {
  449. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We matched signatures.\n"));
  450. if( DiskSignature->ValidPartitionTable == ValidPartitionTable ) {
  451. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : The partition is valid.\n"));
  452. //
  453. // Match the checksum only on non-GPT disks since the protective MBR may have been modified
  454. //
  455. if( DiskSignature->IsGPTDisk || DiskSignature->CheckSum == Checksum ) {
  456. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We matched the checksum.\n"));
  457. //
  458. // Found the first match, check for another match
  459. //
  460. DupSignature = DiskSignature->Next;
  461. while (DupSignature != NULL) {
  462. if ((DupSignature->Signature == Signature) &&
  463. (DupSignature->ValidPartitionTable == ValidPartitionTable) &&
  464. (DiskSignature->IsGPTDisk || DupSignature->CheckSum == Checksum)) {
  465. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We found a second match!\n"));
  466. //
  467. // Found a second match.
  468. // For amd64/x86, we assume that \Device\HardDisk<n> will usually
  469. // correspond to multi(0)disk(0)rdisk(<n>). On ARC, we will rely on
  470. // setupldr to guarantee uniqueness (since we can't install to anything
  471. // ARC firmware can't see, this is OK).
  472. //
  473. #if defined(_AMD64_) || defined(_X86_)
  474. if (!IsNEC_98) { //NEC98
  475. PWSTR DupArcName;
  476. ULONG MatchLen;
  477. DupArcName = SpMemAlloc(64 * sizeof(WCHAR));
  478. MatchLen = swprintf(DupArcName, L"multi(0)disk(0)rdisk(%u)", disk);
  479. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : 2nd match's arcname: %ws\n", DupArcName));
  480. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current arcpath: %ws\n", DiskSignature->ArcPath));
  481. if(_wcsnicmp(DupArcName, DiskSignature->ArcPath, MatchLen)) {
  482. //
  483. // If our first match isn't the right one, continue searching.
  484. //
  485. DiskSignature = NULL;
  486. while(DupSignature) {
  487. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current arcname: %ws\n", DupSignature->ArcPath));
  488. if(!_wcsnicmp(DupArcName, DupSignature->ArcPath, MatchLen)) {
  489. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We matched the ArcPath.\n"));
  490. DiskSignature = DupSignature;
  491. break;
  492. } else {
  493. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We didn't match the ArcPath.\n"));
  494. }
  495. DupSignature = DupSignature->Next;
  496. }
  497. if(!DiskSignature) {
  498. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SppInitializeHardDiskArcNames : We have 2 matching signatures and checksums, but couldn't find any matching ArcPaths.\n"));
  499. SpBugCheck(SETUP_BUGCHECK_BOOTPATH, 1, 0, 0);
  500. }
  501. }
  502. SpMemFree(DupArcName);
  503. break;
  504. } else {
  505. SpBugCheck(SETUP_BUGCHECK_BOOTPATH, 1, 0, 0); //NEC98
  506. }
  507. #else
  508. SpBugCheck(SETUP_BUGCHECK_BOOTPATH, 1, 0, 0);
  509. #endif // defined(_AMD64_) || defined(_X86_)
  510. }
  511. DupSignature = DupSignature->Next;
  512. }
  513. //
  514. // We have the match
  515. //
  516. #if defined(_AMD64_) || defined(_X86_)
  517. Matched = TRUE;
  518. Status = STATUS_SUCCESS;
  519. //
  520. // try to mark the EZDisk if needed; if this fails, we won't create the translation
  521. //
  522. if(NeedToMark == EZDiskStatus) {
  523. //
  524. // Need to stamp 0x55 to make this type of EZDisk detectable by other components.
  525. //
  526. Buffer = (PUCHAR) Buffer - BufferSize;
  527. ((PUCHAR) Buffer)[0x1c2] = 0x55;
  528. Offset.QuadPart = 0;
  529. Status = ZwWriteFile(hPartition, NULL, NULL, NULL, &StatusBlock, Buffer, BufferSize, &Offset, NULL);
  530. if(NT_SUCCESS(Status)) {
  531. //
  532. // Shutdown now to give the user a chance to reboot textmode from harddisk.
  533. // Cannot wait here since the keyboard is not yet functional.
  534. //
  535. SpDone(SP_SCRN_AUTOCHK_REQUIRES_REBOOT, TRUE, FALSE);
  536. }
  537. }
  538. if(NT_SUCCESS(Status))
  539. #endif // defined(_AMD64_) || defined(_X86_)
  540. {
  541. //
  542. // create the translation
  543. //
  544. Translation = SpMemAlloc(sizeof(ARCNAME_TRANSLATION));
  545. Translation->Next = ArcNameTranslations;
  546. ArcNameTranslations = Translation;
  547. Translation->ArcPath = SpDupStringW(DiskSignature->ArcPath);
  548. Translation->NtPath = SpDupStringW(DiskName);
  549. }
  550. break;
  551. } else {
  552. //
  553. // checksum test.
  554. //
  555. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We didn't match the checksum.\n"));
  556. }
  557. } else {
  558. //
  559. // validity test.
  560. //
  561. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : The partition isn't valid.\n"));
  562. }
  563. } else {
  564. //
  565. // Signature test.
  566. //
  567. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We didn't match signatures.\n"));
  568. }
  569. DiskSignature = DiskSignature->Next;
  570. }
  571. #if defined(_AMD64_) || defined(_X86_)
  572. if(!Matched && NoEZDisk == EZDiskStatus) {
  573. //
  574. // no match; there may be an undetected variant of EZDisk that we may need to mark
  575. //
  576. EZDiskStatus = NeedToMark;
  577. goto ezdisk;
  578. }
  579. #endif // defined(_AMD64_) || defined(_X86_)
  580. errSkipDisk:
  581. ZwClose(hPartition);
  582. }
  583. }
  584. SpMemFree(DiskName);
  585. }
  586. PWSTR
  587. pSpArcToNtWorker(
  588. IN PWSTR CompleteArcPath,
  589. IN PWSTR ArcPathPrefix,
  590. IN PWSTR NtPathPrefix
  591. )
  592. {
  593. ULONG matchLen;
  594. PWSTR translatedPath;
  595. PWSTR q,RestOfPath;
  596. translatedPath = NULL;
  597. matchLen = wcslen(ArcPathPrefix);
  598. //
  599. // We must take care the case that ArcPathPrefix has no value.
  600. // _wcsnicmp() will return zero, when matchLen is zero.
  601. //
  602. if(matchLen && !_wcsnicmp(ArcPathPrefix,CompleteArcPath,matchLen)) {
  603. translatedPath = SpMemAlloc(2048);
  604. wcscpy(translatedPath,NtPathPrefix);
  605. RestOfPath = CompleteArcPath + matchLen;
  606. //
  607. // If the next component is partition(n), convert that to partitionn.
  608. //
  609. if(!_wcsnicmp(RestOfPath,L"partition(",10)) {
  610. if(q = wcschr(RestOfPath+10,L')')) {
  611. *q = 0;
  612. SpConcatenatePaths(translatedPath,L"partition");
  613. wcscat(translatedPath,RestOfPath+10);
  614. *q = ')';
  615. RestOfPath = q+1;
  616. }
  617. }
  618. if(*RestOfPath) { // avoid trailing backslash.
  619. SpConcatenatePaths(translatedPath,RestOfPath);
  620. }
  621. q = translatedPath;
  622. translatedPath = SpDupStringW(q);
  623. SpMemFree(q);
  624. }
  625. return(translatedPath);
  626. }
  627. PWSTR
  628. pSpNtToArcWorker(
  629. IN PWSTR CompleteNtPath,
  630. IN PWSTR NtPathPrefix,
  631. IN PWSTR ArcPathPrefix
  632. )
  633. {
  634. ULONG matchLen;
  635. PWSTR translatedPath;
  636. PWSTR p,RestOfPath;
  637. translatedPath = NULL;
  638. matchLen = wcslen(NtPathPrefix);
  639. //
  640. // We must take care the case that NtPathPrefix has no value.
  641. // _wcsnicmp() will return zero, when matchLen is zero.
  642. //
  643. if(matchLen && !_wcsnicmp(NtPathPrefix,CompleteNtPath,matchLen) && ((*(CompleteNtPath + matchLen) == L'\\') || (*(CompleteNtPath + matchLen) == L'\0'))) {
  644. translatedPath = SpMemAlloc(2048);
  645. wcscpy(translatedPath,ArcPathPrefix);
  646. RestOfPath = CompleteNtPath + matchLen;
  647. //
  648. // If the next component is partitionn, convert that to partition(n).
  649. //
  650. if(!_wcsnicmp(RestOfPath,L"\\partition",10)) {
  651. WCHAR c;
  652. //
  653. // Figure out where the partition ordinal ends.
  654. //
  655. SpStringToLong(RestOfPath+10,&p,10);
  656. c = *p;
  657. *p = 0;
  658. wcscat(translatedPath,L"partition(");
  659. wcscat(translatedPath,RestOfPath+10);
  660. wcscat(translatedPath,L")");
  661. *p = c;
  662. RestOfPath = p;
  663. }
  664. if(*RestOfPath) { // avoid trailing backslash.
  665. SpConcatenatePaths(translatedPath,RestOfPath);
  666. }
  667. p = translatedPath;
  668. translatedPath = SpDupStringW(p);
  669. SpMemFree(p);
  670. }
  671. return(translatedPath);
  672. }
  673. PWSTR
  674. SpArcToNt(
  675. IN PWSTR ArcPath
  676. )
  677. {
  678. PARCNAME_TRANSLATION Translation;
  679. PWSTR NormalizedArcPath;
  680. PWSTR Result;
  681. NormalizedArcPath = SpNormalizeArcPath(ArcPath);
  682. Result = NULL;
  683. for(Translation=ArcNameTranslations; Translation; Translation=Translation->Next) {
  684. Result = pSpArcToNtWorker(
  685. NormalizedArcPath,
  686. Translation->ArcPath,
  687. Translation->NtPath
  688. );
  689. if(Result) {
  690. break;
  691. }
  692. }
  693. #if defined(_AMD64_) || defined(_X86_)
  694. if(!Result && HardDisksDetermined) {
  695. ULONG i;
  696. for(i=0; i<HardDiskCount; i++) {
  697. //
  698. // The disk may not have an equivalent nt path.
  699. //
  700. if(HardDisks[i].DevicePath[0]) {
  701. Result = pSpArcToNtWorker(
  702. NormalizedArcPath,
  703. HardDisks[i].ArcPath,
  704. HardDisks[i].DevicePath
  705. );
  706. }
  707. if(Result) {
  708. break;
  709. }
  710. }
  711. }
  712. #endif // defined(_AMD64_) || defined(_X86_)
  713. SpMemFree(NormalizedArcPath);
  714. return(Result);
  715. }
  716. PWSTR
  717. SpNtToArc(
  718. IN PWSTR NtPath,
  719. IN ENUMARCPATHTYPE ArcPathType
  720. )
  721. /*++
  722. Routine Description:
  723. Given a pathname n the NT-namespace, return an equivalent path
  724. in the ARC namespace.
  725. On amd64/x86, we can have disks attached to scsi adapters with
  726. BIOSes. Those disks are accessible both via multi()-style arc names
  727. and scsi()-style names. The above search returns the mutli()-style
  728. one first, which is fine. But sometimes we want to find the scsi
  729. one. That one is referred to as the 'secondary' arc path.
  730. We declare that this concept is amd64/x86-specific.
  731. Arguments:
  732. NtPath - supplies NT path to translate into ARC.
  733. ArcPathType - see above. This parameter is ignored
  734. on non-x86 platforms.
  735. Return Value:
  736. Pointer to wide-character string containing arc path, or NULL
  737. if there is no equivalent arc path for the given nt path.
  738. --*/
  739. {
  740. PARCNAME_TRANSLATION Translation;
  741. PWSTR Result;
  742. Result = NULL;
  743. for(Translation=ArcNameTranslations; Translation; Translation=Translation->Next) {
  744. Result = pSpNtToArcWorker(
  745. NtPath,
  746. Translation->NtPath,
  747. Translation->ArcPath
  748. );
  749. if(Result) {
  750. break;
  751. }
  752. }
  753. #if defined(_AMD64_) || defined(_X86_)
  754. //
  755. // If we are supposed to find a secondary arc path and we already
  756. // found a primary one, forget the primary one we found.
  757. //
  758. if((ArcPathType != PrimaryArcPath) && Result) {
  759. SpMemFree(Result);
  760. Result = NULL;
  761. }
  762. if(!Result && HardDisksDetermined) {
  763. ULONG i;
  764. for(i=0; i<HardDiskCount; i++) {
  765. //
  766. // The disk may not have an equivalent arc path.
  767. //
  768. if(HardDisks[i].ArcPath[0]) {
  769. Result = pSpNtToArcWorker(
  770. NtPath,
  771. HardDisks[i].DevicePath,
  772. HardDisks[i].ArcPath
  773. );
  774. }
  775. if(Result) {
  776. break;
  777. }
  778. }
  779. }
  780. #else
  781. UNREFERENCED_PARAMETER(ArcPathType);
  782. #endif // defined(_AMD64_) || defined(_X86_)
  783. return(Result);
  784. }
  785. PWSTR
  786. SpScsiArcToMultiArc(
  787. IN PWSTR ArcPath
  788. )
  789. /*
  790. Convert a "scsi(..." arcpath into a "multi(..." arcpath, if possible.
  791. */
  792. {
  793. PWSTR p = NULL;
  794. PWSTR q = NULL;
  795. //
  796. // First convert the path into the device path
  797. //
  798. p = SpArcToNt( ArcPath );
  799. if( p ) {
  800. //
  801. // Now convert that device path into an arcpath.
  802. //
  803. q = SpNtToArc( p,
  804. PrimaryArcPath );
  805. SpMemFree(p);
  806. }
  807. return q;
  808. }
  809. PWSTR
  810. SpMultiArcToScsiArc(
  811. IN PWSTR ArcPath
  812. )
  813. /*
  814. Convert a "multi(..." arcpath into a "scsi(..." arcpath, if possible.
  815. */
  816. {
  817. PWSTR p = NULL;
  818. PWSTR q = NULL;
  819. //
  820. // First convert the path into the device path
  821. //
  822. p = SpArcToNt( ArcPath );
  823. if( p ) {
  824. //
  825. // Now convert that device path into an arcpath.
  826. //
  827. q = SpNtToArc( p,
  828. SecondaryArcPath );
  829. SpMemFree(p);
  830. }
  831. return q;
  832. }
  833. VOID
  834. SpGetEnvVarComponents(
  835. IN PCHAR EnvValue,
  836. OUT PCHAR **EnvVarComponents,
  837. OUT PULONG PNumComponents
  838. )
  839. /*++
  840. Routine Description:
  841. This routine takes an environment variable string and turns it into
  842. the constituent value strings:
  843. Example EnvValue = "Value1;Value2;Value3" is turned into:
  844. "Value1", "Value2", "Value3"
  845. The following are valid value strings:
  846. 1. " " :one null value is found
  847. 2. ";;;; " :five null values are found
  848. 3. " ;Value1 ; Value2;Value3;;;;;;; ;" :12 value strings are found,
  849. :9 of which are null
  850. The value strings returned suppress all whitespace before and after the
  851. value. Embedded whitespaces are treated as valid.
  852. Arguments:
  853. EnvValue: ptr to zero terminated environment value string
  854. EnvVarComponents: ptr to a PCHAR * variable to receive the buffer of
  855. ptrs to the constituent value strings.
  856. PNumComponents: ptr to a ULONG to receive the number of value strings found
  857. Return Value:
  858. None.
  859. - *PNumComponent field gets the number of value strings found
  860. - if the number is non zero the *EnvVarComponents field gets the
  861. ptr to the buffer containing ptrs to value strings
  862. --*/
  863. {
  864. PCHAR pchStart, pchEnd, pchNext;
  865. PCHAR pchComponents[MAX_COMPONENTS + 1];
  866. ULONG NumComponents, i;
  867. PCHAR pch;
  868. PCHAR *ppch;
  869. ULONG size;
  870. ASSERT(EnvValue);
  871. //
  872. // Initialise the ptr array with nulls
  873. //
  874. for (i = 0; i < (MAX_COMPONENTS+1); i++) {
  875. pchComponents[i] = NULL;
  876. }
  877. *EnvVarComponents = NULL;
  878. //
  879. // Initialise ptrs to search components
  880. //
  881. pchStart = EnvValue;
  882. NumComponents = 0;
  883. //
  884. // search till either pchStart reaches the end or till max components
  885. // is reached.
  886. //
  887. while (*pchStart && NumComponents < MAX_COMPONENTS) {
  888. //
  889. // find the beginning of next variable value
  890. //
  891. while (*pchStart!=0 && isspace(*pchStart)) {
  892. pchStart++;
  893. }
  894. if (*pchStart == 0) {
  895. break;
  896. }
  897. //
  898. // In the midst of a value
  899. //
  900. pchEnd = pchStart;
  901. while (*pchEnd!=0 && *pchEnd!=';') {
  902. pchEnd++;
  903. }
  904. //
  905. // Process the value found, remove any spaces at the end
  906. //
  907. while((pchEnd > pchStart) && isspace(*(pchEnd-1))) {
  908. pchEnd--;
  909. }
  910. //
  911. // spit out the value found
  912. //
  913. size = (ULONG)(pchEnd - pchStart);
  914. pch = SpMemAlloc(size+1);
  915. ASSERT(pch);
  916. strncpy (pch, pchStart, size);
  917. pch[size]=0;
  918. pchComponents[NumComponents++]=pch;
  919. //
  920. // variable value end has been reached, find the beginning
  921. // of the next value
  922. //
  923. if ((pchNext = strchr(pchEnd, ';')) == NULL) {
  924. break; // out of the big while loop because we are done
  925. }
  926. //
  927. // reinitialise
  928. //
  929. pchStart = pchNext + 1;
  930. } // end while.
  931. //
  932. // Get memory to hold an environment pointer and return that
  933. //
  934. ppch = (PCHAR *)SpMemAlloc((NumComponents+1)*sizeof(PCHAR));
  935. //
  936. // the last one is NULL because we initialised the array with NULLs
  937. //
  938. for(i = 0; i <= NumComponents; i++) {
  939. ppch[i] = pchComponents[i];
  940. }
  941. *EnvVarComponents = ppch;
  942. //
  943. // Update the number of elements field and return.
  944. //
  945. *PNumComponents = NumComponents;
  946. }
  947. VOID
  948. SpGetEnvVarWComponents(
  949. IN PCHAR EnvValue,
  950. OUT PWSTR **EnvVarComponents,
  951. OUT PULONG PNumComponents
  952. )
  953. /*++
  954. Routine Description:
  955. This routine takes an environment variable string and turns it into
  956. the constituent value strings:
  957. Example EnvValue = "Value1;Value2;Value3" is turned into:
  958. "Value1", "Value2", "Value3"
  959. The following are valid value strings:
  960. 1. " " :one null value is found
  961. 2. ";;;; " :five null values are found
  962. 3. " ;Value1 ; Value2;Value3;;;;;;; ;" :12 value strings are found,
  963. :9 of which are null
  964. If an invalid component (contains embedded white space) is found in the
  965. string then this routine attempts to resynch to the next value, no error
  966. is returned, and a the first part of the invalid value is returned for the
  967. bad component.
  968. 1. " Value1;Bad Value2; Value3" : 2 value strings are found
  969. The value strings returned suppress all whitespace before and after the
  970. value.
  971. Arguments:
  972. EnvValue: ptr to zero terminated environment value string
  973. EnvVarComponents: ptr to a PWSTR * variable to receive the buffer of
  974. ptrs to the constituent value strings.
  975. PNumComponents: ptr to a ULONG to receive the number of value strings found
  976. Return Value:
  977. None.
  978. - *PNumComponent field gets the number of value strings found
  979. - if the number is non zero the *EnvVarComponents field gets the
  980. ptr to the buffer containing ptrs to value strings
  981. --*/
  982. {
  983. PCHAR *Components;
  984. ULONG Count,i;
  985. PWSTR *ppwstr;
  986. //
  987. // Get components.
  988. //
  989. SpGetEnvVarComponents(EnvValue,&Components,&Count);
  990. ppwstr = SpMemAlloc((Count+1)*sizeof(PWCHAR));
  991. ASSERT(ppwstr);
  992. for(i=0; i<Count; i++) {
  993. ppwstr[i] = SpToUnicode(Components[i]);
  994. ASSERT(ppwstr[i]);
  995. }
  996. ppwstr[Count] = NULL;
  997. SpFreeEnvVarComponents(Components);
  998. *PNumComponents = Count;
  999. *EnvVarComponents = ppwstr;
  1000. }
  1001. VOID
  1002. SpFreeEnvVarComponents (
  1003. IN PVOID *EnvVarComponents
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This routine frees up all the components in the ptr array and frees
  1008. up the storage for the ptr array itself too
  1009. Arguments:
  1010. EnvVarComponents: the ptr to the PCHAR * or PWSTR * Buffer
  1011. Return Value:
  1012. None.
  1013. --*/
  1014. {
  1015. ASSERT(EnvVarComponents);
  1016. SppFreeComponents(EnvVarComponents);
  1017. SpMemFree(EnvVarComponents);
  1018. }
  1019. VOID
  1020. SppFreeComponents(
  1021. IN PVOID *EnvVarComponents
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. This routine frees up only the components in the ptr array, but doesn't
  1026. free the ptr array storage itself.
  1027. Arguments:
  1028. EnvVarComponents: the ptr to the PCHAR * or PWSTR * Buffer
  1029. Return Value:
  1030. None.
  1031. --*/
  1032. {
  1033. //
  1034. // get all the components and free them
  1035. //
  1036. while(*EnvVarComponents) {
  1037. SpMemFree(*EnvVarComponents++);
  1038. }
  1039. }
  1040. PWSTR
  1041. SpNormalizeArcPath(
  1042. IN PWSTR Path
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. Transform an ARC path into one with no sets of empty parenthesis
  1047. (ie, transforom all instances of () to (0).).
  1048. The returned path will be all lowercase.
  1049. Arguments:
  1050. Path - ARC path to be normalized.
  1051. Return Value:
  1052. Pointer to buffer containing normalized path.
  1053. Caller must free this buffer with SpMemFree.
  1054. --*/
  1055. {
  1056. PWSTR p,q,r;
  1057. PWSTR NormalizedPath;
  1058. NormalizedPath = SpMemAlloc((wcslen(Path)+100)*sizeof(WCHAR));
  1059. ASSERT(NormalizedPath);
  1060. RtlZeroMemory(NormalizedPath,(wcslen(Path)+100)*sizeof(WCHAR));
  1061. for(p=Path; q=wcsstr(p,L"()"); p=q+2) {
  1062. r = NormalizedPath + wcslen(NormalizedPath);
  1063. wcsncpy(r,p,(size_t)(q-p));
  1064. wcscat(NormalizedPath,L"(0)");
  1065. }
  1066. wcscat(NormalizedPath,p);
  1067. NormalizedPath = SpMemRealloc(NormalizedPath,(wcslen(NormalizedPath)+1)*sizeof(WCHAR));
  1068. SpStringToLower(NormalizedPath);
  1069. return(NormalizedPath);
  1070. }