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.

1419 lines
40 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. #ifdef _X86_
  313. BOOLEAN Matched = FALSE;
  314. enum {
  315. NoEZDisk,
  316. EZDiskDetected,
  317. NeedToMark
  318. };
  319. CHAR EZDiskStatus = NoEZDisk;
  320. #endif
  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. Status = ZwDeviceIoControlFile( hPartition,
  337. NULL,
  338. NULL,
  339. NULL,
  340. &StatusBlock,
  341. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  342. NULL,
  343. 0,
  344. Buffer,
  345. BufferSize );
  346. if (Status==STATUS_BUFFER_TOO_SMALL) {
  347. //
  348. // Double buffer size and try again.
  349. //
  350. BufferSize = BufferSize * 2;
  351. ASSERT(BufferSize <= sizeof(TemporaryBuffer));
  352. goto retrydevctrl;
  353. }
  354. if (!NT_SUCCESS(Status)) {
  355. //
  356. // Skip this disk
  357. //
  358. goto errSkipDisk;
  359. }
  360. //
  361. // Read the first two sectors off the drive.
  362. //
  363. Geometry = (PDISK_GEOMETRY)Buffer;
  364. BufferSize = Geometry->BytesPerSector;
  365. Buffer = ALIGN(Buffer, BufferSize);
  366. Offset.QuadPart = 0;
  367. Status = ZwReadFile(hPartition,
  368. NULL,
  369. NULL,
  370. NULL,
  371. &StatusBlock,
  372. Buffer,
  373. BufferSize * 2,
  374. &Offset,
  375. NULL);
  376. if (!NT_SUCCESS(Status)) {
  377. //
  378. // Skip this disk
  379. //
  380. goto errSkipDisk;
  381. }
  382. #ifdef _X86_
  383. //
  384. // Check for EZDrive disk. If we have one, use sector 1
  385. // instead of sector 0.
  386. //
  387. // We do this only on x86 because the firmware doesn't know
  388. // about EZDrive, and so we must use sector 0 to match what
  389. // the firmware did.
  390. //
  391. if((BufferSize >= 512)
  392. && (((PUSHORT)Buffer)[510 / 2] == 0xaa55)
  393. && ((((PUCHAR)Buffer)[0x1c2] == 0x54) || (((PUCHAR)Buffer)[0x1c2] == 0x55))) {
  394. EZDiskStatus = EZDiskDetected;
  395. ezdisk:
  396. //
  397. // we need to try sector 1
  398. //
  399. Buffer = (PUCHAR) Buffer + BufferSize;
  400. }
  401. #endif
  402. //
  403. // Now we have the sector, we can compute the signature,
  404. // the valid partition indicator, and the checksum.
  405. //
  406. if (!IsNEC_98) { //NEC98
  407. Signature = ((PULONG)Buffer)[PARTITION_TABLE_OFFSET/2-1];
  408. } //NEC98
  409. if ((!IsNEC_98) ? (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) :
  410. ((((PUSHORT)Buffer)[BufferSize/2 - 1 ] != BOOT_RECORD_SIGNATURE) ||
  411. (BufferSize == 256))) { //NEC98
  412. ValidPartitionTable = FALSE;
  413. } else {
  414. ValidPartitionTable = TRUE;
  415. }
  416. Checksum = 0;
  417. for (i=0;i<128;i++) {
  418. Checksum += ((PULONG)Buffer)[i];
  419. }
  420. Checksum = 0-Checksum;
  421. //
  422. // Scan the list of arc disk information attempting to match
  423. // signatures
  424. //
  425. //
  426. // Dump the signature info:
  427. //
  428. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SppInitializeHardDiskArcNames : About to start searching for disk with signature: 0x%08lx\n", Signature));
  429. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SppInitializeHardDiskArcNames : About to start searching for disk with checksum: 0x%08lx\n", Checksum));
  430. DiskSignature = DiskSignatureInformation;
  431. i = 0;
  432. while( DiskSignature != NULL ) {
  433. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SppInitializeHardDiskArcNames : Signature Info %d\n================================================\n", i ));
  434. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " Signature: 0x%08lx\n", DiskSignature->Signature ));
  435. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " CheckSum: 0x%08lx\n", DiskSignature->CheckSum ));
  436. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " ArcPath: %ws\n", DiskSignature->ArcPath ));
  437. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " xInt13: %ws\n\n", DiskSignature->xInt13 ? L"yes" : L"no" ));
  438. i++;
  439. DiskSignature = DiskSignature->Next;
  440. }
  441. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "\n\n"));
  442. DiskSignature = DiskSignatureInformation;
  443. while (DiskSignature != NULL) {
  444. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current signature: 0x%08lx\n", DiskSignature->Signature));
  445. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current checksum: 0x%08lx\n", DiskSignature->CheckSum));
  446. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current ArcPath: %ws\n", DiskSignature->ArcPath));
  447. if( DiskSignature->Signature == Signature ) {
  448. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We matched signatures.\n"));
  449. if( DiskSignature->ValidPartitionTable == ValidPartitionTable ) {
  450. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : The partition is valid.\n"));
  451. if( DiskSignature->CheckSum == Checksum ) {
  452. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We matched the checksum.\n"));
  453. //
  454. // Found the first match, check for another match
  455. //
  456. DupSignature = DiskSignature->Next;
  457. while (DupSignature != NULL) {
  458. if ((DupSignature->Signature == Signature) &&
  459. (DupSignature->ValidPartitionTable == ValidPartitionTable) &&
  460. (DupSignature->CheckSum == Checksum)) {
  461. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We found a second match!\n"));
  462. //
  463. // Found a second match.
  464. // For x86, we assume that \Device\HardDisk<n> will usually
  465. // correspond to multi(0)disk(0)rdisk(<n>). On ARC, we will rely on
  466. // setupldr to guarantee uniqueness (since we can't install to anything
  467. // ARC firmware can't see, this is OK).
  468. //
  469. #ifdef _X86_
  470. if (!IsNEC_98) { //NEC98
  471. PWSTR DupArcName;
  472. ULONG MatchLen;
  473. DupArcName = SpMemAlloc(64 * sizeof(WCHAR));
  474. MatchLen = swprintf(DupArcName, L"multi(0)disk(0)rdisk(%u)", disk);
  475. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : 2nd match's arcname: %ws\n", DupArcName));
  476. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current arcpath: %ws\n", DiskSignature->ArcPath));
  477. if(_wcsnicmp(DupArcName, DiskSignature->ArcPath, MatchLen)) {
  478. //
  479. // If our first match isn't the right one, continue searching.
  480. //
  481. DiskSignature = NULL;
  482. while(DupSignature) {
  483. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : Current arcname: %ws\n", DupSignature->ArcPath));
  484. if(!_wcsnicmp(DupArcName, DupSignature->ArcPath, MatchLen)) {
  485. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We matched the ArcPath.\n"));
  486. DiskSignature = DupSignature;
  487. break;
  488. } else {
  489. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We didn't match the ArcPath.\n"));
  490. }
  491. DupSignature = DupSignature->Next;
  492. }
  493. if(!DiskSignature) {
  494. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SppInitializeHardDiskArcNames : We have 2 matching signatures and checksums, but couldn't find any matching ArcPaths.\n"));
  495. SpBugCheck(SETUP_BUGCHECK_BOOTPATH, 1, 0, 0);
  496. }
  497. }
  498. SpMemFree(DupArcName);
  499. break;
  500. } else {
  501. SpBugCheck(SETUP_BUGCHECK_BOOTPATH, 1, 0, 0); //NEC98
  502. }
  503. #else
  504. SpBugCheck(SETUP_BUGCHECK_BOOTPATH, 1, 0, 0);
  505. #endif
  506. }
  507. DupSignature = DupSignature->Next;
  508. }
  509. //
  510. // We have the match
  511. //
  512. #ifdef _X86_
  513. Matched = TRUE;
  514. Status = STATUS_SUCCESS;
  515. //
  516. // try to mark the EZDisk if needed; if this fails, we won't create the translation
  517. //
  518. if(NeedToMark == EZDiskStatus) {
  519. //
  520. // Need to stamp 0x55 to make this type of EZDisk detectable by other components.
  521. //
  522. Buffer = (PUCHAR) Buffer - BufferSize;
  523. ((PUCHAR) Buffer)[0x1c2] = 0x55;
  524. Offset.QuadPart = 0;
  525. Status = ZwWriteFile(hPartition, NULL, NULL, NULL, &StatusBlock, Buffer, BufferSize, &Offset, NULL);
  526. if(NT_SUCCESS(Status)) {
  527. //
  528. // Shutdown now to give the user a chance to reboot textmode from harddisk.
  529. // Cannot wait here since the keyboard is not yet functional.
  530. //
  531. SpDone(SP_SCRN_AUTOCHK_REQUIRES_REBOOT, TRUE, FALSE);
  532. }
  533. }
  534. if(NT_SUCCESS(Status))
  535. #endif
  536. {
  537. //
  538. // create the translation
  539. //
  540. Translation = SpMemAlloc(sizeof(ARCNAME_TRANSLATION));
  541. Translation->Next = ArcNameTranslations;
  542. ArcNameTranslations = Translation;
  543. Translation->ArcPath = SpDupStringW(DiskSignature->ArcPath);
  544. Translation->NtPath = SpDupStringW(DiskName);
  545. }
  546. break;
  547. } else {
  548. //
  549. // checksum test.
  550. //
  551. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We didn't match the checksum.\n"));
  552. }
  553. } else {
  554. //
  555. // validity test.
  556. //
  557. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : The partition isn't valid.\n"));
  558. }
  559. } else {
  560. //
  561. // Signature test.
  562. //
  563. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " SppInitializeHardDiskArcNames : We didn't match signatures.\n"));
  564. }
  565. DiskSignature = DiskSignature->Next;
  566. }
  567. #ifdef _X86_
  568. if(!Matched && NoEZDisk == EZDiskStatus) {
  569. //
  570. // no match; there may be an undetected variant of EZDisk that we may need to mark
  571. //
  572. EZDiskStatus = NeedToMark;
  573. goto ezdisk;
  574. }
  575. #endif
  576. errSkipDisk:
  577. ZwClose(hPartition);
  578. }
  579. }
  580. SpMemFree(DiskName);
  581. }
  582. PWSTR
  583. pSpArcToNtWorker(
  584. IN PWSTR CompleteArcPath,
  585. IN PWSTR ArcPathPrefix,
  586. IN PWSTR NtPathPrefix
  587. )
  588. {
  589. ULONG matchLen;
  590. PWSTR translatedPath;
  591. PWSTR q,RestOfPath;
  592. translatedPath = NULL;
  593. matchLen = wcslen(ArcPathPrefix);
  594. //
  595. // We must take care the case that ArcPathPrefix has no value.
  596. // _wcsnicmp() will return zero, when matchLen is zero.
  597. //
  598. if(matchLen && !_wcsnicmp(ArcPathPrefix,CompleteArcPath,matchLen)) {
  599. translatedPath = SpMemAlloc(2048);
  600. wcscpy(translatedPath,NtPathPrefix);
  601. RestOfPath = CompleteArcPath + matchLen;
  602. //
  603. // If the next component is partition(n), convert that to partitionn.
  604. //
  605. if(!_wcsnicmp(RestOfPath,L"partition(",10)) {
  606. if(q = wcschr(RestOfPath+10,L')')) {
  607. *q = 0;
  608. SpConcatenatePaths(translatedPath,L"partition");
  609. wcscat(translatedPath,RestOfPath+10);
  610. *q = ')';
  611. RestOfPath = q+1;
  612. }
  613. }
  614. if(*RestOfPath) { // avoid trailing backslash.
  615. SpConcatenatePaths(translatedPath,RestOfPath);
  616. }
  617. q = translatedPath;
  618. translatedPath = SpDupStringW(q);
  619. SpMemFree(q);
  620. }
  621. return(translatedPath);
  622. }
  623. PWSTR
  624. pSpNtToArcWorker(
  625. IN PWSTR CompleteNtPath,
  626. IN PWSTR NtPathPrefix,
  627. IN PWSTR ArcPathPrefix
  628. )
  629. {
  630. ULONG matchLen;
  631. PWSTR translatedPath;
  632. PWSTR p,RestOfPath;
  633. translatedPath = NULL;
  634. matchLen = wcslen(NtPathPrefix);
  635. //
  636. // We must take care the case that NtPathPrefix has no value.
  637. // _wcsnicmp() will return zero, when matchLen is zero.
  638. //
  639. if(matchLen && !_wcsnicmp(NtPathPrefix,CompleteNtPath,matchLen) && ((*(CompleteNtPath + matchLen) == L'\\') || (*(CompleteNtPath + matchLen) == L'\0'))) {
  640. translatedPath = SpMemAlloc(2048);
  641. wcscpy(translatedPath,ArcPathPrefix);
  642. RestOfPath = CompleteNtPath + matchLen;
  643. //
  644. // If the next component is partitionn, convert that to partition(n).
  645. //
  646. if(!_wcsnicmp(RestOfPath,L"\\partition",10)) {
  647. WCHAR c;
  648. //
  649. // Figure out where the partition ordinal ends.
  650. //
  651. SpStringToLong(RestOfPath+10,&p,10);
  652. c = *p;
  653. *p = 0;
  654. wcscat(translatedPath,L"partition(");
  655. wcscat(translatedPath,RestOfPath+10);
  656. wcscat(translatedPath,L")");
  657. *p = c;
  658. RestOfPath = p;
  659. }
  660. if(*RestOfPath) { // avoid trailing backslash.
  661. SpConcatenatePaths(translatedPath,RestOfPath);
  662. }
  663. p = translatedPath;
  664. translatedPath = SpDupStringW(p);
  665. SpMemFree(p);
  666. }
  667. return(translatedPath);
  668. }
  669. PWSTR
  670. SpArcToNt(
  671. IN PWSTR ArcPath
  672. )
  673. {
  674. PARCNAME_TRANSLATION Translation;
  675. PWSTR NormalizedArcPath;
  676. PWSTR Result;
  677. NormalizedArcPath = SpNormalizeArcPath(ArcPath);
  678. Result = NULL;
  679. for(Translation=ArcNameTranslations; Translation; Translation=Translation->Next) {
  680. Result = pSpArcToNtWorker(
  681. NormalizedArcPath,
  682. Translation->ArcPath,
  683. Translation->NtPath
  684. );
  685. if(Result) {
  686. break;
  687. }
  688. }
  689. #ifdef _X86_
  690. if(!Result && HardDisksDetermined) {
  691. ULONG i;
  692. for(i=0; i<HardDiskCount; i++) {
  693. //
  694. // The disk may not have an equivalent nt path.
  695. //
  696. if(HardDisks[i].DevicePath[0]) {
  697. Result = pSpArcToNtWorker(
  698. NormalizedArcPath,
  699. HardDisks[i].ArcPath,
  700. HardDisks[i].DevicePath
  701. );
  702. }
  703. if(Result) {
  704. break;
  705. }
  706. }
  707. }
  708. #endif
  709. SpMemFree(NormalizedArcPath);
  710. return(Result);
  711. }
  712. PWSTR
  713. SpNtToArc(
  714. IN PWSTR NtPath,
  715. IN ENUMARCPATHTYPE ArcPathType
  716. )
  717. /*++
  718. Routine Description:
  719. Given a pathname n the NT-namespace, return an equivalent path
  720. in the ARC namespace.
  721. On x86, we can have disks attached to scsi adapters with BIOSes.
  722. Those disks are accessible both via multi()-style arc names and
  723. scsi()-style names. The above search returns the mutli()-style
  724. one first, which is fine. But sometimes we want to find the scsi
  725. one. That one is referred to as the 'secondary' arc path.
  726. We declare that this concept is x86-specific.
  727. Arguments:
  728. NtPath - supplies NT path to translate into ARC.
  729. ArcPathType - see above. This parameter is ignored
  730. on non-x86 platforms.
  731. Return Value:
  732. Pointer to wide-character string containing arc path, or NULL
  733. if there is no equivalent arc path for the given nt path.
  734. --*/
  735. {
  736. PARCNAME_TRANSLATION Translation;
  737. PWSTR Result;
  738. Result = NULL;
  739. for(Translation=ArcNameTranslations; Translation; Translation=Translation->Next) {
  740. Result = pSpNtToArcWorker(
  741. NtPath,
  742. Translation->NtPath,
  743. Translation->ArcPath
  744. );
  745. if(Result) {
  746. break;
  747. }
  748. }
  749. #ifdef _X86_
  750. //
  751. // If we are supposed to find a secondary arc path and we already
  752. // found a primary one, forget the primary one we found.
  753. //
  754. if((ArcPathType != PrimaryArcPath) && Result) {
  755. SpMemFree(Result);
  756. Result = NULL;
  757. }
  758. if(!Result && HardDisksDetermined) {
  759. ULONG i;
  760. for(i=0; i<HardDiskCount; i++) {
  761. //
  762. // The disk may not have an equivalent arc path.
  763. //
  764. if(HardDisks[i].ArcPath[0]) {
  765. Result = pSpNtToArcWorker(
  766. NtPath,
  767. HardDisks[i].DevicePath,
  768. HardDisks[i].ArcPath
  769. );
  770. }
  771. if(Result) {
  772. break;
  773. }
  774. }
  775. }
  776. #else
  777. UNREFERENCED_PARAMETER(ArcPathType);
  778. #endif
  779. return(Result);
  780. }
  781. PWSTR
  782. SpScsiArcToMultiArc(
  783. IN PWSTR ArcPath
  784. )
  785. /*
  786. Convert a "scsi(..." arcpath into a "multi(..." arcpath, if possible.
  787. */
  788. {
  789. PWSTR p = NULL;
  790. PWSTR q = NULL;
  791. //
  792. // First convert the path into the device path
  793. //
  794. p = SpArcToNt( ArcPath );
  795. if( p ) {
  796. //
  797. // Now convert that device path into an arcpath.
  798. //
  799. q = SpNtToArc( p,
  800. PrimaryArcPath );
  801. SpMemFree(p);
  802. }
  803. return q;
  804. }
  805. PWSTR
  806. SpMultiArcToScsiArc(
  807. IN PWSTR ArcPath
  808. )
  809. /*
  810. Convert a "multi(..." arcpath into a "scsi(..." arcpath, if possible.
  811. */
  812. {
  813. PWSTR p = NULL;
  814. PWSTR q = NULL;
  815. //
  816. // First convert the path into the device path
  817. //
  818. p = SpArcToNt( ArcPath );
  819. if( p ) {
  820. //
  821. // Now convert that device path into an arcpath.
  822. //
  823. q = SpNtToArc( p,
  824. SecondaryArcPath );
  825. SpMemFree(p);
  826. }
  827. return q;
  828. }
  829. VOID
  830. SpGetEnvVarComponents(
  831. IN PCHAR EnvValue,
  832. OUT PCHAR **EnvVarComponents,
  833. OUT PULONG PNumComponents
  834. )
  835. /*++
  836. Routine Description:
  837. This routine takes an environment variable string and turns it into
  838. the constituent value strings:
  839. Example EnvValue = "Value1;Value2;Value3" is turned into:
  840. "Value1", "Value2", "Value3"
  841. The following are valid value strings:
  842. 1. " " :one null value is found
  843. 2. ";;;; " :five null values are found
  844. 3. " ;Value1 ; Value2;Value3;;;;;;; ;" :12 value strings are found,
  845. :9 of which are null
  846. The value strings returned suppress all whitespace before and after the
  847. value. Embedded whitespaces are treated as valid.
  848. Arguments:
  849. EnvValue: ptr to zero terminated environment value string
  850. EnvVarComponents: ptr to a PCHAR * variable to receive the buffer of
  851. ptrs to the constituent value strings.
  852. PNumComponents: ptr to a ULONG to receive the number of value strings found
  853. Return Value:
  854. None.
  855. - *PNumComponent field gets the number of value strings found
  856. - if the number is non zero the *EnvVarComponents field gets the
  857. ptr to the buffer containing ptrs to value strings
  858. --*/
  859. {
  860. PCHAR pchStart, pchEnd, pchNext;
  861. PCHAR pchComponents[MAX_COMPONENTS + 1];
  862. ULONG NumComponents, i;
  863. PCHAR pch;
  864. PCHAR *ppch;
  865. ULONG size;
  866. ASSERT(EnvValue);
  867. //
  868. // Initialise the ptr array with nulls
  869. //
  870. for (i = 0; i < (MAX_COMPONENTS+1); i++) {
  871. pchComponents[i] = NULL;
  872. }
  873. *EnvVarComponents = NULL;
  874. //
  875. // Initialise ptrs to search components
  876. //
  877. pchStart = EnvValue;
  878. NumComponents = 0;
  879. //
  880. // search till either pchStart reaches the end or till max components
  881. // is reached.
  882. //
  883. while (*pchStart && NumComponents < MAX_COMPONENTS) {
  884. //
  885. // find the beginning of next variable value
  886. //
  887. while (*pchStart!=0 && isspace(*pchStart)) {
  888. pchStart++;
  889. }
  890. if (*pchStart == 0) {
  891. break;
  892. }
  893. //
  894. // In the midst of a value
  895. //
  896. pchEnd = pchStart;
  897. while (*pchEnd!=0 && *pchEnd!=';') {
  898. pchEnd++;
  899. }
  900. //
  901. // Process the value found, remove any spaces at the end
  902. //
  903. while((pchEnd > pchStart) && isspace(*(pchEnd-1))) {
  904. pchEnd--;
  905. }
  906. //
  907. // spit out the value found
  908. //
  909. size = (ULONG)(pchEnd - pchStart);
  910. pch = SpMemAlloc(size+1);
  911. ASSERT(pch);
  912. strncpy (pch, pchStart, size);
  913. pch[size]=0;
  914. pchComponents[NumComponents++]=pch;
  915. //
  916. // variable value end has been reached, find the beginning
  917. // of the next value
  918. //
  919. if ((pchNext = strchr(pchEnd, ';')) == NULL) {
  920. break; // out of the big while loop because we are done
  921. }
  922. //
  923. // reinitialise
  924. //
  925. pchStart = pchNext + 1;
  926. } // end while.
  927. //
  928. // Get memory to hold an environment pointer and return that
  929. //
  930. ppch = (PCHAR *)SpMemAlloc((NumComponents+1)*sizeof(PCHAR));
  931. //
  932. // the last one is NULL because we initialised the array with NULLs
  933. //
  934. for(i = 0; i <= NumComponents; i++) {
  935. ppch[i] = pchComponents[i];
  936. }
  937. *EnvVarComponents = ppch;
  938. //
  939. // Update the number of elements field and return.
  940. //
  941. *PNumComponents = NumComponents;
  942. }
  943. VOID
  944. SpGetEnvVarWComponents(
  945. IN PCHAR EnvValue,
  946. OUT PWSTR **EnvVarComponents,
  947. OUT PULONG PNumComponents
  948. )
  949. /*++
  950. Routine Description:
  951. This routine takes an environment variable string and turns it into
  952. the constituent value strings:
  953. Example EnvValue = "Value1;Value2;Value3" is turned into:
  954. "Value1", "Value2", "Value3"
  955. The following are valid value strings:
  956. 1. " " :one null value is found
  957. 2. ";;;; " :five null values are found
  958. 3. " ;Value1 ; Value2;Value3;;;;;;; ;" :12 value strings are found,
  959. :9 of which are null
  960. If an invalid component (contains embedded white space) is found in the
  961. string then this routine attempts to resynch to the next value, no error
  962. is returned, and a the first part of the invalid value is returned for the
  963. bad component.
  964. 1. " Value1;Bad Value2; Value3" : 2 value strings are found
  965. The value strings returned suppress all whitespace before and after the
  966. value.
  967. Arguments:
  968. EnvValue: ptr to zero terminated environment value string
  969. EnvVarComponents: ptr to a PWSTR * variable to receive the buffer of
  970. ptrs to the constituent value strings.
  971. PNumComponents: ptr to a ULONG to receive the number of value strings found
  972. Return Value:
  973. None.
  974. - *PNumComponent field gets the number of value strings found
  975. - if the number is non zero the *EnvVarComponents field gets the
  976. ptr to the buffer containing ptrs to value strings
  977. --*/
  978. {
  979. PCHAR *Components;
  980. ULONG Count,i;
  981. PWSTR *ppwstr;
  982. //
  983. // Get components.
  984. //
  985. SpGetEnvVarComponents(EnvValue,&Components,&Count);
  986. ppwstr = SpMemAlloc((Count+1)*sizeof(PWCHAR));
  987. ASSERT(ppwstr);
  988. for(i=0; i<Count; i++) {
  989. ppwstr[i] = SpToUnicode(Components[i]);
  990. ASSERT(ppwstr[i]);
  991. }
  992. ppwstr[Count] = NULL;
  993. SpFreeEnvVarComponents(Components);
  994. *PNumComponents = Count;
  995. *EnvVarComponents = ppwstr;
  996. }
  997. VOID
  998. SpFreeEnvVarComponents (
  999. IN PVOID *EnvVarComponents
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. This routine frees up all the components in the ptr array and frees
  1004. up the storage for the ptr array itself too
  1005. Arguments:
  1006. EnvVarComponents: the ptr to the PCHAR * or PWSTR * Buffer
  1007. Return Value:
  1008. None.
  1009. --*/
  1010. {
  1011. ASSERT(EnvVarComponents);
  1012. SppFreeComponents(EnvVarComponents);
  1013. SpMemFree(EnvVarComponents);
  1014. }
  1015. VOID
  1016. SppFreeComponents(
  1017. IN PVOID *EnvVarComponents
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This routine frees up only the components in the ptr array, but doesn't
  1022. free the ptr array storage itself.
  1023. Arguments:
  1024. EnvVarComponents: the ptr to the PCHAR * or PWSTR * Buffer
  1025. Return Value:
  1026. None.
  1027. --*/
  1028. {
  1029. //
  1030. // get all the components and free them
  1031. //
  1032. while(*EnvVarComponents) {
  1033. SpMemFree(*EnvVarComponents++);
  1034. }
  1035. }
  1036. PWSTR
  1037. SpNormalizeArcPath(
  1038. IN PWSTR Path
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. Transform an ARC path into one with no sets of empty parenthesis
  1043. (ie, transforom all instances of () to (0).).
  1044. The returned path will be all lowercase.
  1045. Arguments:
  1046. Path - ARC path to be normalized.
  1047. Return Value:
  1048. Pointer to buffer containing normalized path.
  1049. Caller must free this buffer with SpMemFree.
  1050. --*/
  1051. {
  1052. PWSTR p,q,r;
  1053. PWSTR NormalizedPath;
  1054. NormalizedPath = SpMemAlloc((wcslen(Path)+100)*sizeof(WCHAR));
  1055. ASSERT(NormalizedPath);
  1056. RtlZeroMemory(NormalizedPath,(wcslen(Path)+100)*sizeof(WCHAR));
  1057. for(p=Path; q=wcsstr(p,L"()"); p=q+2) {
  1058. r = NormalizedPath + wcslen(NormalizedPath);
  1059. wcsncpy(r,p,(size_t)(q-p));
  1060. wcscat(NormalizedPath,L"(0)");
  1061. }
  1062. wcscat(NormalizedPath,p);
  1063. NormalizedPath = SpMemRealloc(NormalizedPath,(wcslen(NormalizedPath)+1)*sizeof(WCHAR));
  1064. SpStringToLower(NormalizedPath);
  1065. return(NormalizedPath);
  1066. }