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.

4639 lines
135 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spsetup.c
  5. Abstract:
  6. Module for supporing installation of SysPrep images from a remote share
  7. Author:
  8. Sean Selitrennikoff (v-seasel) 6-10-1998
  9. --*/
  10. #include "spprecmp.h"
  11. #pragma hdrstop
  12. #include "spcmdcon.h"
  13. #include <remboot.h>
  14. #include <oscpkt.h>
  15. #include <regstr.h>
  16. NET_CARD_INFO RemoteSysPrepNetCardInfo;
  17. PVOID pGlobalResponsePacket = NULL;
  18. ULONG GlobalResponsePacketLength = 0;
  19. #define SYSPREP_PARTITION_SLOP 10 // in percent
  20. VOID
  21. SpInstallSysPrepImage(
  22. IN HANDLE SetupSifHandle,
  23. IN HANDLE WinntSifHandle,
  24. IN PMIRROR_CFG_INFO_FILE pFileData,
  25. IN PMIRROR_CFG_INFO_MEMORY pMemoryData
  26. )
  27. /*++
  28. Routine Description:
  29. Main routine for installing a SysPrep images from a remote share.
  30. Arguments:
  31. WinntSifHandle - Handle to the SIF file.
  32. pFileData - The IMirror.dat data, as saved in the file.
  33. pMemoryData - The IMirror.dat data, as modified to match this computer.
  34. Return Value:
  35. None. Doesn't return on fatal failure.
  36. --*/
  37. {
  38. DWORD cDisk;
  39. NTSTATUS Status;
  40. //
  41. // Right here we should check to see if any patching is going to be needed
  42. // by opening the hive files on the server and checking with the passed in
  43. // PCI ids. If patching is necessary, and the SIF file contains a pointer
  44. // to a CD image that matches the SysPrep image, then we call off to BINL
  45. // to find the appropriate drivers. If BINL does not return an error, then
  46. // we assume that later we will be able to do the patch (after the file copy
  47. // below).
  48. //
  49. // If it looks like the patch will fail, either because there is no pointer
  50. // to a CD image, or BINL returned an error, then we present the user with
  51. // a screen telling them that any hardware differences between their machine
  52. // and the SysPrep image may result in an unbootable system. They may choose
  53. // to continue the setup, or quit.
  54. //
  55. // NOTE: seanse - Put all of the above here.
  56. //
  57. // For each disk, copy all the files to the local store.
  58. //
  59. for (cDisk = 0; cDisk < pFileData->NumberVolumes; cDisk++) {
  60. if (!SpCopyMirrorDisk(pFileData, cDisk)) {
  61. goto CleanUp;
  62. }
  63. }
  64. //
  65. // Patch up the SysPrep image.
  66. //
  67. Status = SpPatchSysPrepImage( SetupSifHandle,
  68. WinntSifHandle,
  69. pFileData,
  70. pMemoryData);
  71. if (!NT_SUCCESS(Status)) {
  72. ULONG ValidKeys[2] = { KEY_F3, 0 };
  73. ULONG Mnemonics[2] = { MnemonicContinueSetup,0 };
  74. while (1) {
  75. if (Status == STATUS_INVALID_PARAMETER) {
  76. SpStartScreen(
  77. SP_SCRN_SYSPREP_PATCH_MISSING_OS,
  78. 3,
  79. HEADER_HEIGHT+1,
  80. FALSE,
  81. FALSE,
  82. DEFAULT_ATTRIBUTE
  83. );
  84. } else {
  85. SpStartScreen(
  86. SP_SCRN_SYSPREP_PATCH_FAILURE,
  87. 3,
  88. HEADER_HEIGHT+1,
  89. FALSE,
  90. FALSE,
  91. DEFAULT_ATTRIBUTE
  92. );
  93. }
  94. SpDisplayStatusOptions(
  95. DEFAULT_STATUS_ATTRIBUTE,
  96. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  97. SP_STAT_F3_EQUALS_EXIT,
  98. 0
  99. );
  100. switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
  101. case KEY_F3:
  102. SpConfirmExit();
  103. break;
  104. default:
  105. //
  106. // must be c=continue
  107. //
  108. goto CleanUp;
  109. }
  110. }
  111. }
  112. CleanUp:
  113. return;
  114. }
  115. NTSTATUS
  116. SpFixupThirdPartyComponents(
  117. IN PVOID SifHandle,
  118. IN PWSTR ThirdPartySourceDevicePath,
  119. IN PDISK_REGION NtPartitionRegion,
  120. IN PWSTR Sysroot,
  121. IN PDISK_REGION SystemPartitionRegion,
  122. IN PWSTR SystemPartitionDirectory
  123. )
  124. /*++
  125. Routine Description:
  126. This routine will take care of installing any 3rd party drivers detected during setupldr.
  127. We have to take care of this here because the normal code path for textmode setup has
  128. been bypassed in lieu of installing a sysprep'd image.
  129. Arguments:
  130. SifHandle - supplies handle to loaded setup information file.
  131. ThirdPartySourceDevicePath - path to 3rd party install files.
  132. NtPartitionRegion - region where installation is located.
  133. Sysroot - string containing %windir% (with no drive).
  134. SystemPartitionRegion - region where system partition is located.
  135. SystemPartitionDirectory - directory on the system partition where
  136. system-specific files are located (should
  137. be NULL for non-ARC machines)
  138. Return Value:
  139. NTSTATUS which will indicate success or failure.
  140. --*/
  141. {
  142. NTSTATUS Status = STATUS_SUCCESS;
  143. PWSTR NtPartition = NULL,
  144. SystemPartition = NULL;
  145. PDISK_FILE_LIST DiskFileLists;
  146. ULONG DiskCount;
  147. HANDLE hKeyControlSetServices;
  148. UNICODE_STRING UnicodeString1;
  149. UNICODE_STRING UnicodeString2;
  150. UNICODE_STRING UnicodeString;
  151. WCHAR Path[MAX_PATH];
  152. HANDLE DstHandle = NULL;
  153. DWORD Size, Number;
  154. PVOID Buffer = NULL;
  155. OBJECT_ATTRIBUTES Obj;
  156. OBJECT_ATTRIBUTES DstObj;
  157. //
  158. // See if there's anything for us to do.
  159. //
  160. if( PreinstallScsiHardware == NULL ) {
  161. return STATUS_SUCCESS;
  162. }
  163. //
  164. // =================
  165. // Install the files.
  166. // =================
  167. //
  168. //
  169. // Get the device path of the nt partition.
  170. //
  171. SpNtNameFromRegion( NtPartitionRegion,
  172. TemporaryBuffer,
  173. sizeof(TemporaryBuffer),
  174. PartitionOrdinalCurrent );
  175. NtPartition = SpDupStringW(TemporaryBuffer);
  176. //
  177. // Get the device path of the system partition.
  178. //
  179. if (SystemPartitionRegion != NULL) {
  180. SpNtNameFromRegion( SystemPartitionRegion,
  181. TemporaryBuffer,
  182. sizeof(TemporaryBuffer),
  183. PartitionOrdinalCurrent );
  184. SystemPartition = SpDupStringW(TemporaryBuffer);
  185. } else {
  186. SystemPartition = NULL;
  187. }
  188. //
  189. // Generate media descriptors for the source media.
  190. //
  191. SpInitializeFileLists( SifHandle,
  192. &DiskFileLists,
  193. &DiskCount );
  194. SpCopyThirdPartyDrivers( ThirdPartySourceDevicePath,
  195. NtPartition,
  196. Sysroot,
  197. SystemPartition,
  198. SystemPartitionDirectory,
  199. DiskFileLists,
  200. DiskCount );
  201. //
  202. // =================
  203. // Set the registry.
  204. // =================
  205. //
  206. //
  207. // We need to open the hive of the target install, not
  208. // our own. Get a path to the system hive.
  209. //
  210. wcscpy(Path, NtPartition);
  211. SpConcatenatePaths(Path, Sysroot);
  212. SpConcatenatePaths(Path, L"system32\\config\\system");
  213. //
  214. // Load him up.
  215. //
  216. INIT_OBJA(&Obj, &UnicodeString2, Path);
  217. INIT_OBJA(&DstObj, &UnicodeString1, L"\\Registry\\SysPrepReg");
  218. Status = ZwLoadKey(&DstObj, &Obj);
  219. if (!NT_SUCCESS(Status)) {
  220. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpFixupThirdPartyComponents: ZwLoadKey to SysPrepReg failed %lx\n", Status));
  221. goto CleanUp0;
  222. }
  223. //
  224. // Now get path to services key in the SysPrep image
  225. //
  226. wcscpy(Path, L"\\Registry\\SysPrepReg");
  227. INIT_OBJA(&Obj, &UnicodeString2, Path);
  228. Status = ZwOpenKey(&DstHandle, KEY_READ, &Obj);
  229. if (!NT_SUCCESS(Status)) {
  230. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpFixupThirdPartyComponents: ZwOpenKey of root SysPrepReg failed %lx\n", Status));
  231. goto CleanUp1;
  232. }
  233. //
  234. // Allocate a temporary buffer, then figure out which is the current control set.
  235. //
  236. Buffer = SpMemAlloc(1024 * 4);
  237. if( Buffer == NULL ) {
  238. Status = STATUS_NO_MEMORY;
  239. goto CleanUp1;
  240. }
  241. Status = SpGetValueKey( DstHandle,
  242. L"Select",
  243. L"Current",
  244. 1024 * 4,
  245. Buffer,
  246. &Size );
  247. if (!NT_SUCCESS(Status)) {
  248. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpFixupThirdPartyComponents: SpGetValueKey of Select\\Current failed %lx\n", Status));
  249. goto CleanUp1;
  250. }
  251. if ( (ULONG)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Type) != REG_DWORD ) {
  252. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpFixupThirdPartyComponents: SpGetValueKey of Select\\Current didn't return a REG_DWORD.\n"));
  253. goto CleanUp1;
  254. }
  255. Number = *((DWORD *)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data));
  256. ZwClose(DstHandle);
  257. DstHandle = NULL;
  258. //
  259. // We're ready to actually open CCS\Services key.
  260. //
  261. swprintf(Path,
  262. L"\\Registry\\SysPrepReg\\ControlSet%03d\\Services",
  263. Number
  264. );
  265. INIT_OBJA(&Obj, &UnicodeString, Path);
  266. Status = ZwOpenKey(&DstHandle, KEY_ALL_ACCESS, &Obj);
  267. if (!NT_SUCCESS(Status)) {
  268. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpFixupThirdPartyComponents: ZwOpenKey of SysPrepReg services failed %lx for %ws\n", Status,Path));
  269. goto CleanUp1;
  270. }
  271. //
  272. // Do it.
  273. //
  274. Status = SpThirdPartyRegistry(DstHandle);
  275. if (!NT_SUCCESS(Status)) {
  276. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpFixupThirdPartyComponents: SpThirdPartyRegistry failed %lx\n", Status));
  277. goto CleanUp1;
  278. }
  279. CleanUp1:
  280. ZwUnloadKey(&DstObj);
  281. if( Buffer ) {
  282. SpMemFree( Buffer );
  283. }
  284. if( DstHandle ) {
  285. ZwClose(DstHandle);
  286. }
  287. CleanUp0:
  288. if( NtPartition ) {
  289. SpMemFree( NtPartition );
  290. }
  291. if( SystemPartition ) {
  292. SpMemFree( SystemPartition );
  293. }
  294. return Status;
  295. }
  296. BOOLEAN
  297. SpReadIMirrorFile(
  298. OUT PMIRROR_CFG_INFO_FILE *ppFileData,
  299. IN PCHAR IMirrorFilePath
  300. )
  301. /*++
  302. Routine Description:
  303. This routine opens the file in IMirrorFilePath, allocates a buffer, copies the data
  304. into the buffer and returns the buffer. This buffer needs to be freed later.
  305. Arguments:
  306. ppFileData - If TRUE is returned, a pointer to an in-memory copy of the file.
  307. IMirrorFilePath - The UNC to the root directory containing all the IMirrorX directories.
  308. Return Value:
  309. TRUE if successful, else it generates a fatal error.
  310. --*/
  311. {
  312. WCHAR wszRootDir[MAX_PATH];
  313. ULONG ulReturnData;
  314. mbstowcs(wszRootDir, IMirrorFilePath, strlen(IMirrorFilePath) + 1);
  315. *ppFileData = NULL;
  316. //
  317. // Enumerate thru all the files in the base directory looking for the IMirror data file.
  318. // If it is found, the callback function fills in pFileData.
  319. //
  320. if ((SpEnumFiles(wszRootDir, SpFindMirrorDataFile, &ulReturnData, (PVOID)ppFileData) == EnumFileError) ||
  321. (*ppFileData == NULL)) {
  322. SpSysPrepFailure( SP_SYSPREP_NO_MIRROR_FILE, wszRootDir, NULL );
  323. // shouldn't get here.
  324. return FALSE;
  325. }
  326. return TRUE;
  327. }
  328. BOOLEAN
  329. SpFindMirrorDataFile(
  330. IN PCWSTR SrcPath,
  331. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  332. OUT PULONG ReturnData,
  333. IN PVOID *ppFileData
  334. )
  335. /*++
  336. Routine Description:
  337. This routine is called by the file enumerator as a callback for
  338. each file or subdirectory found in the source directory.
  339. If FileInfo represents a file, then we skip it.
  340. If FileInfo represents a directory, then we search it for the IMirror data file.
  341. Arguments:
  342. SrcPath - Absolute path to the source directory. This path should contain
  343. the path to the source device.
  344. FileInfo - supplies find data for a file in the source dir.
  345. ReturnData - receives an error code if an error occurs.
  346. ppFileData - If successful in finding the IMirror data file, this is a buffer which is
  347. a copy of the file.
  348. Return Value:
  349. FALSE if we find the IMirror data file, else TRUE. (return value is used to continue
  350. the enumeration or not)
  351. --*/
  352. {
  353. PWSTR Temp1;
  354. PWSTR Temp2;
  355. ULONG ulLen;
  356. NTSTATUS Status;
  357. UNICODE_STRING UnicodeString;
  358. OBJECT_ATTRIBUTES Obja;
  359. IO_STATUS_BLOCK IoStatusBlock;
  360. HANDLE Handle;
  361. if(!(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  362. return TRUE;
  363. }
  364. Handle = NULL;
  365. //
  366. // Build the path name to the IMirror data file
  367. //
  368. Temp1 = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  369. ulLen = FileInfo->FileNameLength/sizeof(WCHAR);
  370. wcsncpy(Temp1,FileInfo->FileName, ulLen);
  371. Temp1[ulLen] = 0;
  372. wcscpy(TemporaryBuffer, SrcPath);
  373. SpConcatenatePaths(TemporaryBuffer, Temp1);
  374. SpConcatenatePaths(TemporaryBuffer, IMIRROR_DAT_FILE_NAME);
  375. Temp2 = SpDupStringW(TemporaryBuffer);
  376. INIT_OBJA(&Obja, &UnicodeString, Temp2);
  377. Status = ZwCreateFile(&Handle,
  378. FILE_GENERIC_READ,
  379. &Obja,
  380. &IoStatusBlock,
  381. NULL,
  382. FILE_ATTRIBUTE_NORMAL,
  383. FILE_SHARE_READ,
  384. FILE_OPEN,
  385. FILE_SYNCHRONOUS_IO_NONALERT,
  386. NULL,
  387. 0
  388. );
  389. SpMemFree(Temp2);
  390. if(!NT_SUCCESS(Status)) {
  391. return TRUE;
  392. }
  393. Status = SpGetFileSize(Handle, &ulLen);
  394. if(!NT_SUCCESS(Status)) {
  395. ZwClose(Handle);
  396. return TRUE;
  397. }
  398. //
  399. // Now allocate memory and read in the file.
  400. //
  401. *ppFileData = SpMemAlloc(ulLen);
  402. Status = ZwReadFile(Handle,
  403. NULL,
  404. NULL,
  405. NULL,
  406. &IoStatusBlock,
  407. *ppFileData,
  408. ulLen,
  409. 0,
  410. NULL
  411. );
  412. if(!NT_SUCCESS(Status)) {
  413. SpMemFree(*ppFileData);
  414. *ppFileData = NULL;
  415. ZwClose(Handle);
  416. return TRUE;
  417. }
  418. ZwClose(Handle);
  419. return FALSE;
  420. }
  421. BOOLEAN
  422. SpDetermineDiskLayout(
  423. IN PMIRROR_CFG_INFO_FILE pFileData,
  424. OUT PMIRROR_CFG_INFO_MEMORY *pMemoryData
  425. )
  426. /*++
  427. Routine Description:
  428. This routine takes the passed-in IMirror.dat file and produces a
  429. resulting memory structure indicating how the local disks should
  430. be partitioned.
  431. Arguments:
  432. pFileData - A pointer to an in-memory copy of IMirror.Dat.
  433. pMemoryData - Returnes an allocated pointed to how the disks should
  434. be partitioned.
  435. Return Value:
  436. TRUE if successful, else it generates a fatal error.
  437. --*/
  438. {
  439. PMIRROR_CFG_INFO_MEMORY memData;
  440. UNICODE_STRING UnicodeString;
  441. OBJECT_ATTRIBUTES Obja;
  442. HANDLE Handle;
  443. NTSTATUS Status;
  444. ULONG ResultLength;
  445. PKEY_BASIC_INFORMATION KeyInfo;
  446. PWSTR CurrentHalName, OriginalHalName;
  447. ULONG CurrentHalNameLength;
  448. ULONG i, j;
  449. ULONG diskNumber;
  450. PPARTITIONED_DISK pDisk;
  451. if (pFileData->MirrorVersion != IMIRROR_CURRENT_VERSION) {
  452. SpSysPrepFailure( SP_SYSPREP_INVALID_VERSION, NULL, NULL );
  453. return FALSE;
  454. }
  455. //
  456. // Check if the current HAL that textmode installed for this
  457. // system is different from the one that is running on this system
  458. // (note that this works because for remote install boots, setupldr
  459. // loads the real HAL, not the one from the short list of HALs
  460. // included on the boot floppy).
  461. //
  462. INIT_OBJA(&Obja, &UnicodeString, L"\\Registry\\Machine\\Hardware\\RESOURCEMAP\\Hardware Abstraction Layer");
  463. Status = ZwOpenKey(&Handle, KEY_READ, &Obja);
  464. if (!NT_SUCCESS(Status)) {
  465. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpDetermineDiskLayout: ZwOpenKey of HAL key failed %lx\n", Status));
  466. SpSysPrepFailure( SP_SYSPREP_WRONG_HAL, NULL, NULL );
  467. return FALSE;
  468. }
  469. KeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
  470. Status = ZwEnumerateKey(Handle, 0, KeyBasicInformation, KeyInfo, sizeof(TemporaryBuffer), &ResultLength);
  471. ZwClose(Handle);
  472. if (!NT_SUCCESS(Status)) {
  473. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpDetermineDiskLayout: ZwEnumerateKey of HAL key failed %lx\n", Status));
  474. SpSysPrepFailure( SP_SYSPREP_WRONG_HAL, NULL, NULL );
  475. return FALSE;
  476. }
  477. KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = L'\0';
  478. CurrentHalName = SpDupStringW(KeyInfo->Name);
  479. CurrentHalNameLength = KeyInfo->NameLength;
  480. OriginalHalName = (PWCHAR)(((PUCHAR)pFileData) + pFileData->HalNameOffset);
  481. if (!CurrentHalName ||
  482. (memcmp(OriginalHalName, CurrentHalName, CurrentHalNameLength) != 0)) {
  483. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  484. "SpDetermineDiskLayout: HAL strings different, old <%ws> new <%ws>\n",
  485. OriginalHalName,
  486. CurrentHalName));
  487. SpSysPrepFailure(
  488. SP_SYSPREP_WRONG_HAL,
  489. OriginalHalName,
  490. CurrentHalName);
  491. return FALSE;
  492. }
  493. //
  494. // For the moment, don't worry about the number of processors being
  495. // different. The HAL check will probably catch it, and if not it should
  496. // still work as long as the build is internally consistent, since we
  497. // don't replace any components right now. There are two error screens
  498. // defined for this case, SP_SYSPREP_WRONG_PROCESSOR_COUNT_UNI and
  499. // SP_SYSPREP_WRONG_PROCESSOR_COUNT_MULTI.
  500. //
  501. memData = SpMemAlloc(FIELD_OFFSET(MIRROR_CFG_INFO_MEMORY, Volumes[0]) +
  502. (pFileData->NumberVolumes * sizeof(MIRROR_VOLUME_INFO_MEMORY)));
  503. memData->NumberVolumes = pFileData->NumberVolumes;
  504. for (i = 0; i < pFileData->NumberVolumes; i++) {
  505. memData->Volumes[i].DriveLetter = pFileData->Volumes[i].DriveLetter;
  506. memData->Volumes[i].PartitionType = pFileData->Volumes[i].PartitionType;
  507. memData->Volumes[i].PartitionActive = pFileData->Volumes[i].PartitionActive;
  508. memData->Volumes[i].IsBootDisk = pFileData->Volumes[i].IsBootDisk;
  509. memData->Volumes[i].CompressedVolume = pFileData->Volumes[i].CompressedVolume;
  510. diskNumber = pFileData->Volumes[i].DiskNumber;
  511. memData->Volumes[i].DiskNumber = diskNumber;
  512. memData->Volumes[i].PartitionNumber = pFileData->Volumes[i].PartitionNumber;
  513. memData->Volumes[i].DiskSignature = pFileData->Volumes[i].DiskSignature;
  514. memData->Volumes[i].BlockSize = pFileData->Volumes[i].BlockSize;
  515. memData->Volumes[i].LastUSNMirrored = pFileData->Volumes[i].LastUSNMirrored;
  516. memData->Volumes[i].FileSystemFlags = pFileData->Volumes[i].FileSystemFlags;
  517. wcscpy(memData->Volumes[i].FileSystemName, pFileData->Volumes[i].FileSystemName);
  518. memData->Volumes[i].VolumeLabel = SpDupStringW((PWCHAR)(((PUCHAR)pFileData) + pFileData->Volumes[i].VolumeLabelOffset));
  519. memData->Volumes[i].OriginalArcName = SpDupStringW((PWCHAR)(((PUCHAR)pFileData) + pFileData->Volumes[i].ArcNameOffset));
  520. memData->Volumes[i].DiskSpaceUsed = pFileData->Volumes[i].DiskSpaceUsed;
  521. memData->Volumes[i].StartingOffset = pFileData->Volumes[i].StartingOffset;
  522. memData->Volumes[i].PartitionSize = pFileData->Volumes[i].PartitionSize;
  523. //
  524. // Ensure that the required disk number actually exists, and that the
  525. // disk is online.
  526. //
  527. pDisk = &PartitionedDisks[diskNumber];
  528. if ((diskNumber >= HardDiskCount) ||
  529. (pDisk->HardDisk == NULL) ||
  530. (pDisk->HardDisk->Status == DiskOffLine) ) {
  531. SpSysPrepFailure( SP_SYSPREP_INVALID_PARTITION, NULL, NULL );
  532. }
  533. }
  534. *pMemoryData = memData;
  535. SpMemFree(CurrentHalName);
  536. return TRUE;
  537. }
  538. NTSTATUS
  539. SpGetBaseDeviceName(
  540. IN PWSTR SymbolicName,
  541. OUT PWSTR Buffer,
  542. IN ULONG Size
  543. )
  544. /*++
  545. Routine Description:
  546. This routine drills down thru symbolic links until it finds the base device name.
  547. Arguments:
  548. SymbolicName - The name to start with.
  549. Buffer - The output buffer.
  550. Size - Length, in bytes of Buffer
  551. Return Value:
  552. STATUS_SUCCESS if it completes adding all the to do items properly.
  553. --*/
  554. {
  555. UNICODE_STRING UnicodeString;
  556. OBJECT_ATTRIBUTES Obja;
  557. HANDLE Handle;
  558. NTSTATUS Status;
  559. //
  560. // Start at the first name
  561. //
  562. INIT_OBJA(&Obja,&UnicodeString,SymbolicName);
  563. Status = ZwOpenSymbolicLinkObject(&Handle,
  564. (ACCESS_MASK)SYMBOLIC_LINK_QUERY,
  565. &Obja
  566. );
  567. if (!NT_SUCCESS(Status)) {
  568. return Status;
  569. }
  570. while (TRUE) {
  571. //
  572. // Take this open and get the next name
  573. //
  574. UnicodeString.Length = 0;
  575. UnicodeString.MaximumLength = (USHORT)Size;
  576. UnicodeString.Buffer = (PWCHAR)Buffer;
  577. Status = ZwQuerySymbolicLinkObject(Handle,
  578. &UnicodeString,
  579. NULL
  580. );
  581. ZwClose(Handle);
  582. Buffer[(UnicodeString.Length / sizeof(WCHAR))] = UNICODE_NULL;
  583. if (!NT_SUCCESS(Status)) {
  584. return Status;
  585. }
  586. //
  587. // See if the next name is also a symbolic name
  588. //
  589. INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
  590. Status = ZwOpenSymbolicLinkObject(&Handle,
  591. (ACCESS_MASK)SYMBOLIC_LINK_QUERY,
  592. &Obja
  593. );
  594. if (!NT_SUCCESS(Status)) {
  595. return STATUS_SUCCESS;
  596. }
  597. }
  598. }
  599. BOOLEAN
  600. SpVerifyDriveLetter(
  601. IN PWSTR RegionName,
  602. IN WCHAR DriveLetter
  603. )
  604. /*++
  605. Routine Description:
  606. This routine makes sure that the specified region has been assigned
  607. the correct drive letter by the mount manager, if not it changes it.
  608. Arguments:
  609. RegionName - The region name, \Device\HardiskX\PartitionY.
  610. DriveLetter - The desired drive letter.
  611. Return Value:
  612. TRUE if successful, else FALSE.
  613. --*/
  614. {
  615. WCHAR currentLetter;
  616. ULONG i;
  617. PMOUNTMGR_MOUNT_POINT mountPoint = NULL;
  618. PMOUNTMGR_CREATE_POINT_INPUT createMountPoint;
  619. WCHAR NewSymbolicLink[16];
  620. PWSTR regionBaseName;
  621. ULONG mountPointSize;
  622. ULONG createMountPointSize;
  623. NTSTATUS Status;
  624. OBJECT_ATTRIBUTES Obja;
  625. UNICODE_STRING UnicodeString;
  626. IO_STATUS_BLOCK IoStatusBlock;
  627. HANDLE Handle;
  628. PMOUNTMGR_MOUNT_POINTS mountPointsReturned;
  629. LARGE_INTEGER DelayTime;
  630. //
  631. // See what drive letter the region has. Since the mount manager
  632. // assigns drive letters asynchronously, we wait a little while
  633. // if we don't get one back.
  634. //
  635. for (i = 0; ; i++) {
  636. currentLetter = SpGetDriveLetter(RegionName, &mountPoint);
  637. if (currentLetter == DriveLetter) {
  638. if (mountPoint) {
  639. SpMemFree(mountPoint);
  640. }
  641. return TRUE;
  642. } else if (currentLetter != L'\0') {
  643. break;
  644. } else if (i == 5) {
  645. break;
  646. }
  647. //
  648. // Wait 2 sec and try again.
  649. //
  650. DelayTime.HighPart = -1;
  651. DelayTime.LowPart = (ULONG)(-20000000);
  652. KeDelayExecutionThread(KernelMode,FALSE,&DelayTime);
  653. }
  654. //
  655. // At this point, we either have no drive letter assigned, or a
  656. // wrong one.
  657. //
  658. if (currentLetter != L'\0') {
  659. //
  660. // There is an existing drive letter, so delete it.
  661. //
  662. INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
  663. Status = ZwOpenFile(
  664. &Handle,
  665. // (ACCESS_MASK)(FILE_GENERIC_READ | FILE_GENERIC_WRITE),
  666. (ACCESS_MASK)(FILE_GENERIC_READ),
  667. &Obja,
  668. &IoStatusBlock,
  669. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
  670. FILE_NON_DIRECTORY_FILE
  671. );
  672. if( !NT_SUCCESS( Status ) ) {
  673. SpMemFree(mountPoint);
  674. FALSE;
  675. }
  676. mountPointsReturned = SpMemAlloc( 4096 );
  677. mountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) +
  678. mountPoint->SymbolicLinkNameLength +
  679. mountPoint->UniqueIdLength +
  680. mountPoint->DeviceNameLength;
  681. Status = ZwDeviceIoControlFile(
  682. Handle,
  683. NULL,
  684. NULL,
  685. NULL,
  686. &IoStatusBlock,
  687. IOCTL_MOUNTMGR_DELETE_POINTS,
  688. mountPoint,
  689. mountPointSize,
  690. mountPointsReturned,
  691. 4096
  692. );
  693. if (!NT_SUCCESS( Status )) {
  694. SpMemFree(mountPointsReturned);
  695. SpMemFree(mountPoint);
  696. ZwClose(Handle);
  697. return FALSE;
  698. }
  699. SpMemFree(mountPointsReturned);
  700. SpMemFree(mountPoint); // don't need this anymore
  701. }
  702. //
  703. // Now add the one we want.
  704. //
  705. //
  706. // We need to get the real base name (\Device\HardDiskX\PartitionY
  707. // is a symbolic link).
  708. //
  709. SpGetBaseDeviceName(RegionName, TemporaryBuffer, sizeof(TemporaryBuffer));
  710. regionBaseName = SpDupStringW(TemporaryBuffer);
  711. swprintf(NewSymbolicLink, L"\\DosDevices\\%c:", DriveLetter);
  712. createMountPointSize = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
  713. (wcslen(regionBaseName) * sizeof(WCHAR)) +
  714. (wcslen(NewSymbolicLink) * sizeof(WCHAR));
  715. createMountPoint = SpMemAlloc(createMountPointSize);
  716. createMountPoint->SymbolicLinkNameLength = wcslen(NewSymbolicLink) * sizeof(WCHAR);
  717. createMountPoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  718. memcpy((PCHAR)createMountPoint + createMountPoint->SymbolicLinkNameOffset,
  719. NewSymbolicLink,
  720. createMountPoint->SymbolicLinkNameLength);
  721. createMountPoint->DeviceNameLength = wcslen(regionBaseName) * sizeof(WCHAR);
  722. createMountPoint->DeviceNameOffset = createMountPoint->SymbolicLinkNameOffset +
  723. createMountPoint->SymbolicLinkNameLength;
  724. memcpy((PCHAR)createMountPoint + createMountPoint->DeviceNameOffset,
  725. regionBaseName,
  726. createMountPoint->DeviceNameLength);
  727. Status = ZwDeviceIoControlFile(
  728. Handle,
  729. NULL,
  730. NULL,
  731. NULL,
  732. &IoStatusBlock,
  733. IOCTL_MOUNTMGR_CREATE_POINT,
  734. createMountPoint,
  735. createMountPointSize,
  736. NULL,
  737. 0
  738. );
  739. SpMemFree(createMountPoint);
  740. SpMemFree(regionBaseName);
  741. ZwClose(Handle);
  742. if (!NT_SUCCESS(Status)) {
  743. return FALSE;
  744. }
  745. return TRUE;
  746. }
  747. BOOLEAN
  748. SpSetVolumeLabel(
  749. IN PWSTR RegionName,
  750. IN PWSTR VolumeLabel
  751. )
  752. /*++
  753. Routine Description:
  754. This routine sets the volume label on the specified region.
  755. Arguments:
  756. RegionName - The region name, \Device\HardiskX\PartitionY.
  757. DriveLetter - The desired volume label.
  758. Return Value:
  759. TRUE if successful, else FALSE.
  760. --*/
  761. {
  762. NTSTATUS Status;
  763. OBJECT_ATTRIBUTES Obja;
  764. UNICODE_STRING UnicodeString;
  765. IO_STATUS_BLOCK IoStatusBlock;
  766. HANDLE Handle;
  767. struct LABEL_BUFFER {
  768. FILE_FS_LABEL_INFORMATION VolumeInfo;
  769. WCHAR Label[64];
  770. } LabelBuffer;
  771. INIT_OBJA(&Obja,&UnicodeString,RegionName);
  772. Status = ZwOpenFile(
  773. &Handle,
  774. (ACCESS_MASK)(FILE_GENERIC_READ | FILE_GENERIC_WRITE),
  775. &Obja,
  776. &IoStatusBlock,
  777. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
  778. FILE_NON_DIRECTORY_FILE
  779. );
  780. if( !NT_SUCCESS( Status ) ) {
  781. return FALSE;
  782. }
  783. LabelBuffer.VolumeInfo.VolumeLabelLength = wcslen(VolumeLabel) * sizeof(WCHAR);
  784. wcscpy(LabelBuffer.VolumeInfo.VolumeLabel, VolumeLabel);
  785. Status = ZwSetVolumeInformationFile(
  786. Handle,
  787. &IoStatusBlock,
  788. &LabelBuffer,
  789. FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabel[0]) + LabelBuffer.VolumeInfo.VolumeLabelLength,
  790. FileFsLabelInformation);
  791. ZwClose(Handle);
  792. if( !NT_SUCCESS( Status ) ) {
  793. return FALSE;
  794. }
  795. return TRUE;
  796. }
  797. BOOLEAN
  798. SpFixupLocalDisks(
  799. IN HANDLE SifHandle,
  800. OUT PDISK_REGION *InstallRegion,
  801. OUT PDISK_REGION *SystemPartitionRegion,
  802. IN PWSTR SetupSourceDevicePath,
  803. IN PWSTR DirectoryOnSetupSource,
  804. IN PMIRROR_CFG_INFO_MEMORY pMemoryData,
  805. IN BOOLEAN UseWholeDisk
  806. )
  807. /*++
  808. Routine Description:
  809. This routine parses the IMirror.dat file given and makes the local disk(s) look as
  810. closely as possible to the configuration in the file.
  811. Arguments:
  812. SifHandle - Controlling sif file.
  813. InstallRegion - Returns the install region to use.
  814. SystemPartitionRegion - Returns the system partition to use.
  815. SetupSourceDevicePath - Path to the setup device.
  816. DirectoryOnSetupSource - Subdirectory of the setup files.
  817. pMemoryData - A pointer to an in-memory copy of the file.
  818. UseWholeDisk - TRUE if disks should be partitioned as their current
  819. physical size; FALSE if they should be partitioned to match
  820. the size that the original source machine had.
  821. Return Value:
  822. TRUE if successful, else it generates a fatal error.
  823. --*/
  824. {
  825. PDISK_REGION pRegion=NULL;
  826. PDISK_REGION p;
  827. PWSTR RegionDescr;
  828. PWSTR RegionNtName;
  829. NTSTATUS Status;
  830. BOOLEAN DiskCleaned[8] = { FALSE }; // track if a disk has been cleaned up.
  831. ULONG volume, disk;
  832. PMIRROR_VOLUME_INFO_MEMORY volumeInfo;
  833. LARGE_INTEGER SizeInMB;
  834. PPARTITIONED_DISK pDisk;
  835. BOOLEAN ExpandToEnd;
  836. ULONG j;
  837. PARTITION_INFORMATION_EX PartInfo;
  838. ULONGLONG SysPartStartSector = 0;
  839. ULONG SysPartDisk = 0;
  840. LARGE_INTEGER SizeAvailable;
  841. LARGE_INTEGER SlopSize;
  842. LARGE_INTEGER SlopSizeTimes100;
  843. LARGE_INTEGER SizeRequiredMax;
  844. LARGE_INTEGER SizeRequiredMin;
  845. PULONGLONG StartSectors = NULL;
  846. if (pMemoryData->NumberVolumes) {
  847. StartSectors = (PULONGLONG)(SpMemAlloc(sizeof(ULONGLONG) * pMemoryData->NumberVolumes));
  848. if (!StartSectors) {
  849. *InstallRegion = NULL;
  850. *SystemPartitionRegion = NULL;
  851. return FALSE; // ran out of memory
  852. }
  853. }
  854. RtlZeroMemory(StartSectors, (sizeof(ULONGLONG) * pMemoryData->NumberVolumes));
  855. //
  856. // NOTE: imirror.dat
  857. // doesn't have information about which partitions were in the extended
  858. // partition. We could read the boot sector from the server, or just
  859. // try to guess at when we need an extended partition. For the moment,
  860. // we will just let the partition creation code create extended
  861. // partitions whent it wants to (all regions after the first primary
  862. // become logical disks in an extended partition).
  863. //
  864. for (volume = 0; volume < pMemoryData->NumberVolumes; volume++) {
  865. volumeInfo = &pMemoryData->Volumes[volume];
  866. //
  867. // If this disk has not been cleaned up, then do so.
  868. //
  869. disk = volumeInfo->DiskNumber;
  870. if (!DiskCleaned[disk]) {
  871. //
  872. // Clean out the different partitions on disk.
  873. //
  874. SpPtPartitionDiskForRemoteBoot(
  875. disk,
  876. &pRegion);
  877. //
  878. // That function may leave one big partitioned region, if so delete
  879. // it so we can start from scratch.
  880. //
  881. if (pRegion && pRegion->PartitionedSpace) {
  882. SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
  883. }
  884. DiskCleaned[disk] = TRUE;
  885. } else {
  886. //
  887. // We have already cleaned out this disk, so pRegion points
  888. // to the last partition we created. However, we have these 2 dirty looking validation checks on pRegion
  889. // to make PREFIX happy. pRegion is never NULL but if it is we think that something is wrong and move on.
  890. //
  891. if( pRegion == NULL )
  892. continue;
  893. pRegion = pRegion->Next;
  894. if( pRegion == NULL )
  895. continue;
  896. }
  897. //
  898. // Create a region of the specified size.
  899. // NOTE: Worry about volumeInfo->PartitionType/CompressedVolume?
  900. // NOTE: What if the rounding to the nearest MB loses something?
  901. //
  902. // We allow for some slop.
  903. // a) If the new disk is <= x% smaller, and the image will still fit, then we'll do it.
  904. // b) If the new disk is <= x% bigger, then we'll make one partition out of the whole disk.
  905. // c) If the new disk is >x% bigger, then we'll make one partition equal to the original one and leave the rest of the disk raw.
  906. // d) If the new disk is >x% smaller, then we'll fail.
  907. pDisk = &PartitionedDisks[pRegion->DiskNumber];
  908. // SizeAvailable = RtlEnlargedUnsignedMultiply( pRegion->SectorCount, pDisk->HardDisk->Geometry.BytesPerSector );
  909. SizeAvailable.QuadPart = pRegion->SectorCount * pDisk->HardDisk->Geometry.BytesPerSector;
  910. // SYSPREP_PARTITION_SLOP is specified as a percentage
  911. SlopSizeTimes100 = RtlExtendedIntegerMultiply(SizeAvailable, SYSPREP_PARTITION_SLOP);
  912. SlopSize = RtlExtendedLargeIntegerDivide( SlopSizeTimes100, 100, NULL );
  913. SizeRequiredMin = RtlLargeIntegerSubtract( volumeInfo->PartitionSize, SlopSize );
  914. if ( SizeRequiredMin.QuadPart < volumeInfo->DiskSpaceUsed.QuadPart ) {
  915. SizeRequiredMin = volumeInfo->DiskSpaceUsed;
  916. }
  917. SizeRequiredMax = RtlLargeIntegerAdd( volumeInfo->PartitionSize, SlopSize );
  918. ExpandToEnd = FALSE;
  919. if (UseWholeDisk) {
  920. ExpandToEnd = TRUE;
  921. //
  922. // If this is the last partition on the disk, then use the rest of it.
  923. //
  924. for (j = 0; j < pMemoryData->NumberVolumes; j++) {
  925. if ((j != volume) &&
  926. (pMemoryData->Volumes[j].DiskNumber == pMemoryData->Volumes[volume].DiskNumber) &&
  927. (pMemoryData->Volumes[j].StartingOffset.QuadPart > pMemoryData->Volumes[volume].StartingOffset.QuadPart)) {
  928. ExpandToEnd = FALSE;
  929. break;
  930. }
  931. }
  932. }
  933. SizeInMB = RtlExtendedLargeIntegerDivide(volumeInfo->PartitionSize, 1024 * 1024, NULL);
  934. if (!ExpandToEnd && (SizeAvailable.QuadPart > SizeRequiredMax.QuadPart)) {
  935. // use volumeInfo->PartitionSize
  936. } else if (SizeAvailable.QuadPart >= SizeRequiredMin.QuadPart ) {
  937. SizeInMB.QuadPart = 0; // use all available space
  938. } else {
  939. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Sysprep partition of %d Mb is too big\n", SizeInMB.LowPart));
  940. SpSysPrepFailure( SP_SYSPREP_NOT_ENOUGH_DISK_SPACE, NULL, NULL );
  941. return(FALSE);
  942. }
  943. //
  944. // TBD : fix the partition type
  945. // if(!SpPtDoCreate(pRegion,&p,TRUE,SizeInMB.LowPart,volumeInfo->PartitionType,TRUE)) {
  946. //
  947. RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
  948. PartInfo.Mbr.PartitionType = volumeInfo->PartitionType;
  949. if(!SpPtDoCreate(pRegion, &p, TRUE, SizeInMB.LowPart, &PartInfo, TRUE)) {
  950. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not create sys prep partition %d Mb\n", SizeInMB.LowPart));
  951. SpSysPrepFailure( SP_SYSPREP_NOT_ENOUGH_DISK_SPACE, NULL, NULL );
  952. return(FALSE);
  953. }
  954. //
  955. // If we just created an extended partition and a logical drive,
  956. // we'll need to switch regions -- Region points to the extended partition
  957. // region, but we want to point to the logical drive region.
  958. //
  959. ASSERT(p);
  960. pRegion = p;
  961. #ifdef _X86_
  962. if (volumeInfo->PartitionActive) {
  963. if (volumeInfo->IsBootDisk) {
  964. //
  965. // On an x86 machine, make sure that we have a valid primary partition
  966. // on drive 0 (C:), for booting.
  967. //
  968. PDISK_REGION SysPart = SpPtValidSystemPartition();
  969. ASSERT(pRegion == SysPart);
  970. SPPT_MARK_REGION_AS_SYSTEMPARTITION(pRegion, TRUE);
  971. SPPT_SET_REGION_DIRTY(pRegion, TRUE);
  972. SysPartDisk = disk;
  973. SysPartStartSector = pRegion->StartSector;
  974. }
  975. //
  976. // Make sure the system partition is active and all others are inactive.
  977. //
  978. SpPtMakeRegionActive(pRegion);
  979. }
  980. #endif
  981. volumeInfo->CreatedRegion = NULL;
  982. StartSectors[disk] = pRegion->StartSector;
  983. }
  984. if (SysPartStartSector == 0) {
  985. *InstallRegion = *SystemPartitionRegion = NULL;
  986. SpMemFree(StartSectors);
  987. return FALSE; // We need the system partition and install region
  988. }
  989. //
  990. // At this point, everything is fine, so commit any
  991. // partition changes the user may have made.
  992. // This won't return if an error occurs while updating the disk.
  993. //
  994. SpPtDoCommitChanges();
  995. //
  996. // Now format all the partitions and make sure the drive letter
  997. // is correct.
  998. //
  999. for (volume = 0; volume < pMemoryData->NumberVolumes; volume++) {
  1000. ULONG FilesystemType;
  1001. ULONG DiskNumber = volumeInfo->DiskNumber;
  1002. volumeInfo = &pMemoryData->Volumes[volume];
  1003. if (StartSectors[DiskNumber]) {
  1004. volumeInfo->CreatedRegion = SpPtLookupRegionByStart(
  1005. SPPT_GET_PARTITIONED_DISK(DiskNumber),
  1006. TRUE,
  1007. StartSectors[DiskNumber]);
  1008. } else {
  1009. ASSERT(FALSE);
  1010. continue;
  1011. }
  1012. pRegion = volumeInfo->CreatedRegion;
  1013. SpPtRegionDescription(
  1014. &PartitionedDisks[pRegion->DiskNumber],
  1015. pRegion,
  1016. TemporaryBuffer,
  1017. sizeof(TemporaryBuffer)
  1018. );
  1019. RegionDescr = SpDupStringW(TemporaryBuffer);
  1020. if (wcscmp(volumeInfo->FileSystemName, L"FAT") == 0) {
  1021. FilesystemType = FilesystemFat;
  1022. } else if (wcscmp(volumeInfo->FileSystemName, L"FAT32") == 0) {
  1023. FilesystemType = FilesystemFat32;
  1024. } else {
  1025. FilesystemType = FilesystemNtfs;
  1026. }
  1027. Status = SpDoFormat(
  1028. RegionDescr,
  1029. pRegion,
  1030. FilesystemType,
  1031. FALSE,
  1032. FALSE, // don't need to worry about fat size
  1033. TRUE,
  1034. SifHandle,
  1035. 0, // default cluster size
  1036. SetupSourceDevicePath,
  1037. DirectoryOnSetupSource
  1038. );
  1039. SpMemFree(RegionDescr);
  1040. //
  1041. // This checks that the drive letter is correct.
  1042. //
  1043. SpNtNameFromRegion(
  1044. pRegion,
  1045. TemporaryBuffer,
  1046. sizeof(TemporaryBuffer),
  1047. PartitionOrdinalCurrent);
  1048. RegionNtName = SpDupStringW(TemporaryBuffer);
  1049. SpVerifyDriveLetter(
  1050. RegionNtName,
  1051. volumeInfo->DriveLetter
  1052. );
  1053. SpSetVolumeLabel(
  1054. RegionNtName,
  1055. volumeInfo->VolumeLabel
  1056. );
  1057. pRegion->DriveLetter = volumeInfo->DriveLetter;
  1058. wcsncpy(pRegion->VolumeLabel,
  1059. volumeInfo->VolumeLabel,
  1060. (sizeof(pRegion->VolumeLabel) / sizeof(WCHAR)) - 1
  1061. );
  1062. pRegion->VolumeLabel[ (sizeof(pRegion->VolumeLabel) / sizeof(WCHAR)) - 1] = UNICODE_NULL;
  1063. SpMemFree(RegionNtName);
  1064. }
  1065. //
  1066. // Locate the system and install region
  1067. //
  1068. *SystemPartitionRegion = SpPtLookupRegionByStart(SPPT_GET_PARTITIONED_DISK(SysPartDisk),
  1069. TRUE,
  1070. SysPartStartSector);
  1071. *InstallRegion = *SystemPartitionRegion;
  1072. SpMemFree(StartSectors);
  1073. return (*InstallRegion != NULL);
  1074. }
  1075. BOOLEAN
  1076. SpCopyMirrorDisk(
  1077. IN PMIRROR_CFG_INFO_FILE pFileData,
  1078. IN ULONG cDisk
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. This routine uses the IMirror.dat file given and a disk number to copy the contents
  1083. on the mirror share down to the local machine.
  1084. Arguments:
  1085. pFileData - A pointer to an in-memory copy of the file.
  1086. cDisk - The disk number to copy.
  1087. Return Value:
  1088. TRUE if successful, else FALSE.
  1089. --*/
  1090. {
  1091. PMIRROR_VOLUME_INFO_FILE pVolume;
  1092. PDISK_REGION pRegion;
  1093. WCHAR Buffer[MAX_PATH];
  1094. NTSTATUS Status;
  1095. PWSTR pNtName;
  1096. if (pFileData->NumberVolumes <= cDisk) {
  1097. SpSysPrepFailure( SP_SYSPREP_INVALID_PARTITION, NULL, NULL );
  1098. return FALSE;
  1099. }
  1100. //
  1101. // Find the correct region.
  1102. // NOTE: the drive with this
  1103. // letter might not be on the same disk, we should scan all disks
  1104. // for this drive letter.
  1105. //
  1106. pVolume = &(pFileData->Volumes[cDisk]);
  1107. pRegion = PartitionedDisks[pVolume->DiskNumber].PrimaryDiskRegions;
  1108. while (pRegion != NULL) {
  1109. if (pRegion->DriveLetter == pVolume->DriveLetter) {
  1110. break;
  1111. }
  1112. pRegion = pRegion->Next;
  1113. }
  1114. if (pRegion == NULL) {
  1115. pRegion = PartitionedDisks[pVolume->DiskNumber].ExtendedDiskRegions;
  1116. while (pRegion != NULL) {
  1117. if (pRegion->DriveLetter == pVolume->DriveLetter) {
  1118. break;
  1119. }
  1120. pRegion = pRegion->Next;
  1121. }
  1122. if (pRegion == NULL) {
  1123. SpSysPrepFailure( SP_SYSPREP_NOT_ENOUGH_PARTITIONS, NULL, NULL );
  1124. return FALSE;
  1125. }
  1126. }
  1127. SpPtRegionDescription(
  1128. &PartitionedDisks[pRegion->DiskNumber],
  1129. pRegion,
  1130. Buffer,
  1131. sizeof(Buffer)
  1132. );
  1133. //
  1134. // Now copy all files over
  1135. //
  1136. SpNtNameFromRegion(
  1137. pRegion,
  1138. TemporaryBuffer,
  1139. sizeof(TemporaryBuffer),
  1140. PartitionOrdinalCurrent
  1141. );
  1142. pNtName = SpDupStringW(TemporaryBuffer);
  1143. mbstowcs(Buffer, RemoteIMirrorFilePath, strlen(RemoteIMirrorFilePath) + 1);
  1144. wcscat(Buffer, (PWSTR)(((PUCHAR)pFileData) + pVolume->MirrorUncPathOffset));
  1145. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Copying directories from %ws to %ws%ws\n",
  1146. Buffer, pNtName, L"\\"));
  1147. //
  1148. // setup the global that says whether we look at compression bit or ACL.
  1149. //
  1150. if ((wcscmp(pVolume->FileSystemName, L"FAT") == 0) ||
  1151. (wcscmp(pVolume->FileSystemName, L"FAT32") == 0)) {
  1152. RemoteSysPrepVolumeIsNtfs = FALSE;
  1153. } else {
  1154. RemoteSysPrepVolumeIsNtfs = TRUE;
  1155. }
  1156. //
  1157. // copy the acl onto the root.
  1158. //
  1159. Status = SpSysPrepSetExtendedInfo( Buffer, pNtName, TRUE, TRUE );
  1160. if (!NT_SUCCESS(Status)) {
  1161. SpSysPrepFailure( SP_SYSPREP_ACL_FAILURE, pNtName, NULL );
  1162. SpMemFree( pNtName );
  1163. return FALSE;
  1164. }
  1165. SpCopyDirRecursive(
  1166. Buffer,
  1167. pNtName,
  1168. L"\\",
  1169. 0
  1170. );
  1171. //
  1172. // create the \sysprep\sysprep.inf file as a dup of our sif file for gui
  1173. // mode setup answer file.
  1174. //
  1175. if (pVolume->IsBootDisk) {
  1176. //
  1177. // first we create the sysprep directory, then we create the inf
  1178. // file in it.
  1179. //
  1180. SpCreateDirectory( pNtName,
  1181. NULL,
  1182. L"sysprep",
  1183. 0,
  1184. 0 );
  1185. Status = SpWriteSetupTextFile(WinntSifHandle,pNtName,L"sysprep",L"sysprep.inf");
  1186. }
  1187. SpMemFree( pNtName );
  1188. return TRUE;
  1189. }
  1190. VOID
  1191. SpDeleteStorageVolumes (
  1192. IN HANDLE SysPrepRegHandle,
  1193. IN DWORD ControlSetNumber
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This routine deletes those subkeys of the CCS\Enum\STORAGE\Volume key that
  1198. represent volumes that were never fully installed. This eliminates stale
  1199. information about volumes that may not exist on this computer.
  1200. The motivation for this is this scenario and others like it:
  1201. On the initial install of the OS, the disk has one large partition. The user
  1202. chooses to delete this partition and create a smaller one to hold the OS.
  1203. The result of this is that textmode setup transfers volume information about
  1204. both partitions into the system hive for the running OS. GUI mode setup then
  1205. completely installs the smaller volume, but the larger volume is left partially
  1206. installed and marked with CONFIGFLAG_REINSTALL.
  1207. Next RIPREP is run to copy the OS image to a RIS server. When the image is
  1208. brought back down, say to the same machine or to a machine with the same
  1209. hard disk size, and the automatic UseWholeDisk partitioning is done, there
  1210. will be one large partition of the same size as the original large partition.
  1211. The Volume instance name will match the partially installed one, so when
  1212. mini-GUI mode setup starts, it will get a bugcheck 7B because the partially
  1213. installed volume cannot be used as the system disk.
  1214. To combat this problem, this routine deletes all partially installed volumes
  1215. from the CCS\Enum\STORAGE\Volume key.
  1216. Arguments:
  1217. SysPrepRegHandle - Handle to the system hive of the build we are patching.
  1218. ControlSetNumber - Current control set number in the hive.
  1219. Return Value:
  1220. None.
  1221. --*/
  1222. {
  1223. NTSTATUS status;
  1224. OBJECT_ATTRIBUTES obja;
  1225. UNICODE_STRING unicodeString;
  1226. HANDLE volumeKeyHandle;
  1227. DWORD enumIndex;
  1228. DWORD resultLength;
  1229. PKEY_BASIC_INFORMATION keyInfo;
  1230. PKEY_VALUE_FULL_INFORMATION valueInfo;
  1231. PWCH instanceName;
  1232. HANDLE instanceKeyHandle;
  1233. DWORD configFlags;
  1234. //
  1235. // Open the Enum\STORAGE\Volume key in the current control set.
  1236. //
  1237. swprintf(
  1238. TemporaryBuffer,
  1239. L"ControlSet%03d\\Enum\\STORAGE\\Volume",
  1240. ControlSetNumber
  1241. );
  1242. INIT_OBJA( &obja, &unicodeString, TemporaryBuffer );
  1243. obja.RootDirectory = SysPrepRegHandle;
  1244. status = ZwOpenKey( &volumeKeyHandle, KEY_ALL_ACCESS, &obja );
  1245. if( !NT_SUCCESS(status) ) {
  1246. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpDeleteStorageVolumes: Unable to open %ws. status = %lx\n", TemporaryBuffer, status ));
  1247. return;
  1248. }
  1249. //
  1250. // Enumerate all of the instance keys.
  1251. //
  1252. enumIndex = 0;
  1253. while ( TRUE ) {
  1254. status = ZwEnumerateKey(
  1255. volumeKeyHandle,
  1256. enumIndex,
  1257. KeyBasicInformation,
  1258. TemporaryBuffer,
  1259. sizeof(TemporaryBuffer),
  1260. &resultLength
  1261. );
  1262. if ( !NT_SUCCESS(status) ) {
  1263. if ( status == STATUS_NO_MORE_ENTRIES ) {
  1264. //
  1265. // Enumeration completed successfully.
  1266. //
  1267. status = STATUS_SUCCESS;
  1268. } else {
  1269. //
  1270. // Some kind of error occurred. Print a message and bail.
  1271. //
  1272. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpDeleteStorageVolumes: Unable to enumerate existing storage volumes (%lx)\n", status ));
  1273. }
  1274. break;
  1275. }
  1276. //
  1277. // Zero-terminate the subkey name just in case. Copy it out of the
  1278. // temporary buffer into "local" storage.
  1279. //
  1280. keyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
  1281. keyInfo->Name[keyInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  1282. instanceName = SpDupStringW( keyInfo->Name );
  1283. //
  1284. // Open the key for the volume instance.
  1285. //
  1286. INIT_OBJA( &obja, &unicodeString, instanceName );
  1287. obja.RootDirectory = volumeKeyHandle;
  1288. status = ZwOpenKey( &instanceKeyHandle, KEY_ALL_ACCESS, &obja );
  1289. if( !NT_SUCCESS(status) ) {
  1290. //
  1291. // Unable to open the instance key. Print a message and move
  1292. // on to the next one.
  1293. //
  1294. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpDeleteStorageVolumes: Unable to open %ws. status = %lx\n", instanceName, status ));
  1295. SpMemFree( instanceName );
  1296. enumIndex++;
  1297. continue;
  1298. }
  1299. //
  1300. // Query the ConfigFlags value.
  1301. //
  1302. RtlInitUnicodeString( &unicodeString, L"ConfigFlags");
  1303. status = ZwQueryValueKey(
  1304. instanceKeyHandle,
  1305. &unicodeString,
  1306. KeyValueFullInformation,
  1307. TemporaryBuffer,
  1308. sizeof(TemporaryBuffer),
  1309. &resultLength
  1310. );
  1311. valueInfo = (PKEY_VALUE_FULL_INFORMATION)TemporaryBuffer;
  1312. if ( NT_SUCCESS(status) &&
  1313. (valueInfo->Type == REG_DWORD) ) {
  1314. //
  1315. // Got the value. If the volume isn't fully installed, delete the
  1316. // whole instance key.
  1317. //
  1318. configFlags = *(PULONG)((PUCHAR)valueInfo + valueInfo->DataOffset);
  1319. if ( (configFlags &
  1320. (CONFIGFLAG_REINSTALL | CONFIGFLAG_FINISH_INSTALL)) != 0 ) {
  1321. //KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpDeleteStorageVolumes: instance %ws has ConfigFlags %x; DELETING\n", instanceName, configFlags ));
  1322. ZwClose( instanceKeyHandle );
  1323. status = SppDeleteKeyRecursive(
  1324. volumeKeyHandle,
  1325. instanceName,
  1326. TRUE // ThisKeyToo
  1327. );
  1328. SpMemFree( instanceName );
  1329. // Don't increment enumIndex, because we just deleted a key.
  1330. continue;
  1331. } else {
  1332. //
  1333. // This volume is fully installed. Leave it alone.
  1334. //
  1335. //KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpDeleteStorageVolumes: instance %ws has ConfigFlags %x; not deleting\n", instanceName, configFlags ));
  1336. }
  1337. } else {
  1338. //
  1339. // ConfigFlags value not present or not a DWORD. Print a
  1340. // message and move on.
  1341. //
  1342. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpDeleteStorageVolumes: instance %ws has invalid ConfigFlags\n", instanceName ));
  1343. }
  1344. //
  1345. // Clean up and move on to the next volume instance.
  1346. //
  1347. ZwClose( instanceKeyHandle );
  1348. SpMemFree( instanceName );
  1349. enumIndex++;
  1350. }
  1351. //
  1352. // All done. Close the Volume key.
  1353. //
  1354. ZwClose( volumeKeyHandle );
  1355. return;
  1356. }
  1357. NTSTATUS
  1358. SpPatchSysPrepImage(
  1359. IN HANDLE SetupSifHandle,
  1360. IN HANDLE WinntSifHandle,
  1361. IN PMIRROR_CFG_INFO_FILE pFileData,
  1362. IN PMIRROR_CFG_INFO_MEMORY pMemoryData
  1363. )
  1364. /*++
  1365. Routine Description:
  1366. This routine uses the IMirror.dat file given and the given SIF file to make the
  1367. following modifications to a locally copied SysPrep image.
  1368. - Replace the disk controller driver in the image with one that supports the current hardware.
  1369. - Replace the NIC driver in the image with one that supports the current hardware.
  1370. - Replace the HAL, kernel and other mp/up dependent drivers if necessary.
  1371. - Migrate the mounted device settings.
  1372. - Modify boot.ini ARC names if necessary.
  1373. Arguments:
  1374. WinntSifHandle - Handle to the open SIF file.
  1375. pFileData - A pointer to an in-memory copy of IMirror.Dat
  1376. pMemoryData - A pointer to an in-memory copy of IMirror.Dat, modified to
  1377. match the specs of this computer (disk sizes etc).
  1378. Return Value:
  1379. The NTSTATUS of the operation.
  1380. --*/
  1381. {
  1382. PWCHAR SysPrepDriversDevice;
  1383. PWCHAR Tmp;
  1384. ULONG Index;
  1385. DWORD Size;
  1386. DWORD Number;
  1387. WCHAR Path[MAX_PATH];
  1388. WCHAR Path2[MAX_PATH];
  1389. WCHAR ImageName[MAX_PATH];
  1390. WCHAR SrvPath[MAX_PATH];
  1391. HANDLE SrcHandle = NULL;
  1392. HANDLE DstHandle = NULL;
  1393. HANDLE TmpHandle = NULL;
  1394. HANDLE TmpHandle2 = NULL;
  1395. HANDLE FileHandle = NULL;
  1396. HANDLE FileHandle2 = NULL;
  1397. PVOID Buffer = NULL;
  1398. BOOLEAN NeedToUnload = FALSE;
  1399. NTSTATUS Status;
  1400. UNICODE_STRING UnicodeString;
  1401. OBJECT_ATTRIBUTES Obj;
  1402. OBJECT_ATTRIBUTES DstObj;
  1403. UNICODE_STRING UnicodeString1;
  1404. UNICODE_STRING UnicodeString2;
  1405. IO_STATUS_BLOCK IoStatusBlock;
  1406. PKEY_BASIC_INFORMATION pKeyNode;
  1407. ULONG volume;
  1408. PMIRROR_VOLUME_INFO_MEMORY volumeInfo;
  1409. PDISK_FILE_LIST DiskFileLists;
  1410. ULONG DiskCount;
  1411. BOOLEAN HaveCopyList = FALSE;
  1412. BOOLEAN CopyListEmpty = TRUE;
  1413. PMIRROR_VOLUME_INFO_FILE pVolume = NULL;
  1414. PWSTR pVolumePath = NULL;
  1415. //
  1416. // Find the volume descriptor for the boot disk.
  1417. //
  1418. DiskCount = 0;
  1419. while (DiskCount < pFileData->NumberVolumes) {
  1420. pVolume = &(pFileData->Volumes[DiskCount]);
  1421. if (pVolume->IsBootDisk) {
  1422. break;
  1423. }
  1424. pVolume = NULL;
  1425. DiskCount++;
  1426. }
  1427. if (pVolume == NULL) {
  1428. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Couldn't find boot drive record\n"));
  1429. return STATUS_INVALID_PARAMETER;
  1430. }
  1431. //
  1432. // First check if the SIF file has a value for SysPrepDriversDevice so that we can
  1433. // get new drivers, etc, if necessary.
  1434. //
  1435. SysPrepDriversDevice = SpGetSectionKeyIndex(WinntSifHandle,
  1436. L"SetupData",
  1437. L"SysPrepDriversDevice",
  1438. 0
  1439. );
  1440. if ((SysPrepDriversDevice == NULL) || (wcslen(SysPrepDriversDevice) == 0)) {
  1441. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SIF has no SysPrepDriversDevice value\n"));
  1442. return STATUS_INVALID_PARAMETER;
  1443. }
  1444. Tmp = SysPrepDriversDevice;
  1445. while(*Tmp != UNICODE_NULL) {
  1446. if (*Tmp == L'%') {
  1447. return STATUS_INVALID_PARAMETER;
  1448. }
  1449. Tmp++;
  1450. }
  1451. //
  1452. // Generate media descriptors for the source media.
  1453. //
  1454. SpInitializeFileLists(
  1455. SetupSifHandle,
  1456. &DiskFileLists,
  1457. &DiskCount
  1458. );
  1459. HaveCopyList = TRUE;
  1460. //
  1461. // Allocate a temporary buffer
  1462. //
  1463. Buffer = SpMemAlloc(1024 * 4);
  1464. //
  1465. // Make a string that contains the path to the volume (\??\X:).
  1466. //
  1467. wcscpy(TemporaryBuffer, L"\\??\\X:");
  1468. TemporaryBuffer[4] = pVolume->DriveLetter;
  1469. pVolumePath = SpDupStringW(TemporaryBuffer);
  1470. //
  1471. // Now load the local version of the SysPrep hives, using IMirror.Dat to find them
  1472. // NOTE: DstObj is assumed by CleanUp to still be the key.
  1473. //
  1474. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1475. wcscpy(Path, L"\\??\\");
  1476. wcscat(Path, Tmp);
  1477. wcscat(Path, L"\\System32\\Config\\System");
  1478. INIT_OBJA(&DstObj, &UnicodeString1, L"\\Registry\\SysPrepReg");
  1479. INIT_OBJA(&Obj, &UnicodeString2, Path);
  1480. Status = ZwLoadKey(&DstObj, &Obj);
  1481. if (!NT_SUCCESS(Status)) {
  1482. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwLoadKey to SysPrepReg failed %lx\n", Status));
  1483. goto CleanUp;
  1484. }
  1485. NeedToUnload = TRUE;
  1486. //
  1487. // Compare the local SysPrep NIC to the NIC that is currently running
  1488. //
  1489. //
  1490. // If different, then replace the NIC
  1491. //
  1492. //
  1493. // Put all critical devices in the currently running hives into the SysPrep hive.
  1494. //
  1495. wcscpy(Path, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
  1496. INIT_OBJA(&Obj, &UnicodeString2, Path);
  1497. Status = ZwOpenKey(&SrcHandle, KEY_READ, &Obj);
  1498. if (!NT_SUCCESS(Status)) {
  1499. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey of local CriticalDeviceDatabase failed %lx\n", Status));
  1500. goto CleanUp;
  1501. }
  1502. wcscpy(Path, L"\\Registry\\SysPrepReg");
  1503. INIT_OBJA(&Obj, &UnicodeString2, Path);
  1504. Status = ZwOpenKey(&DstHandle, KEY_READ, &Obj);
  1505. if (!NT_SUCCESS(Status)) {
  1506. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey of root SysPrepReg failed %lx\n", Status));
  1507. goto CleanUp;
  1508. }
  1509. Status = SpGetValueKey(
  1510. DstHandle,
  1511. L"Select",
  1512. L"Current",
  1513. 1024 * 4,
  1514. Buffer,
  1515. &Size
  1516. );
  1517. if (!NT_SUCCESS(Status)) {
  1518. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpGetValueKey of Select\\Current failed %lx\n", Status));
  1519. goto CleanUp;
  1520. }
  1521. Number = *((DWORD *)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data));
  1522. ZwClose(DstHandle);
  1523. DstHandle = NULL;
  1524. //
  1525. // Print the current control set number to find the current control set
  1526. //
  1527. swprintf(Path,
  1528. L"\\Registry\\SysPrepReg\\ControlSet%03d\\Control\\CriticalDeviceDatabase",
  1529. Number
  1530. );
  1531. //
  1532. // Open the critical device database in the SysPrep image
  1533. //
  1534. INIT_OBJA(&Obj, &UnicodeString2, Path);
  1535. Status = ZwOpenKey(&DstHandle, KEY_READ | KEY_WRITE, &Obj);
  1536. if (!NT_SUCCESS(Status)) {
  1537. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey of SysPrepReg CriticalDeviceDatabase failed %lx\n", Status));
  1538. goto CleanUp;
  1539. }
  1540. //
  1541. // Start looping and copying the data from the currently running critical device database
  1542. // into the SysPrep's database.
  1543. //
  1544. pKeyNode = (PKEY_BASIC_INFORMATION)Buffer;
  1545. for (Index = 0; ; Index++) {
  1546. if (TmpHandle) {
  1547. ZwClose(TmpHandle);
  1548. TmpHandle = NULL;
  1549. }
  1550. if (TmpHandle2) {
  1551. ZwClose(TmpHandle2);
  1552. TmpHandle2 = NULL;
  1553. }
  1554. Status = ZwEnumerateKey(SrcHandle,
  1555. Index,
  1556. KeyBasicInformation,
  1557. pKeyNode,
  1558. 1024 * 4,
  1559. &Size
  1560. );
  1561. if (!NT_SUCCESS(Status)) {
  1562. Status = STATUS_SUCCESS;
  1563. break;
  1564. }
  1565. RtlCopyMemory((PUCHAR)Path2, (PUCHAR)(pKeyNode->Name), pKeyNode->NameLength);
  1566. Path2[pKeyNode->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  1567. //
  1568. // We need to quit migrating everything from the current critical device database.
  1569. // In order to do that, we'll only migrate the following types:
  1570. //
  1571. //
  1572. // Make sure this is the type of device we really want to migrate. We will
  1573. // accept any of the following classes:
  1574. // {4D36E965-E325-11CE-BFC1-08002BE10318} CDROM
  1575. // {4D36E967-E325-11CE-BFC1-08002BE10318} DiskDrive
  1576. // {4D36E96A-E325-11CE-BFC1-08002BE10318} hdc
  1577. // {4D36E96B-E325-11CE-BFC1-08002BE10318} Keyboard
  1578. // {4D36E96F-E325-11CE-BFC1-08002BE10318} Mouse
  1579. // {4D36E97B-E325-11CE-BFC1-08002BE10318} SCSIAdapter
  1580. // {4D36E97D-E325-11CE-BFC1-08002BE10318} System
  1581. //
  1582. Status = SpGetValueKey( SrcHandle,
  1583. Path2,
  1584. L"ClassGUID",
  1585. 1024 * 4,
  1586. Buffer,
  1587. &Size );
  1588. if( NT_SUCCESS(Status) ) {
  1589. if( (_wcsnicmp(L"{4D36E965-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) &&
  1590. (_wcsnicmp(L"{4D36E967-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) &&
  1591. (_wcsnicmp(L"{4D36E96A-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) &&
  1592. (_wcsnicmp(L"{4D36E96B-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) &&
  1593. (_wcsnicmp(L"{4D36E96F-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) &&
  1594. (_wcsnicmp(L"{4D36E97B-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) &&
  1595. (_wcsnicmp(L"{4D36E97D-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength)) ) {
  1596. // he's not something we want to migrate.
  1597. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpPatchSysPrepImage: We're skipping migration of %ws because his type is %ws\n", Path2, ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data));
  1598. continue;
  1599. } else {
  1600. // looks good.
  1601. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpPatchSysPrepImage: We're going to migration %ws because his type is %ws\n", Path2, ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data));
  1602. }
  1603. } else {
  1604. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpPatchSysPrepImage: SpGetValueKey failed to open %ws\\ClassGUID, but we're going to migrate this key anyway. (%lx)\n", Path2, Status));
  1605. }
  1606. INIT_OBJA(&Obj, &UnicodeString, Path2);
  1607. Obj.RootDirectory = DstHandle;
  1608. Status = ZwOpenKey(&TmpHandle, KEY_ALL_ACCESS, &Obj);
  1609. if(NT_SUCCESS(Status)) {
  1610. //
  1611. // Delete the current item to rid of stale data
  1612. //
  1613. ZwDeleteKey(TmpHandle);
  1614. ZwClose(TmpHandle);
  1615. }
  1616. TmpHandle = NULL;
  1617. Status = SppCopyKeyRecursive(SrcHandle,
  1618. DstHandle,
  1619. Path2,
  1620. Path2,
  1621. TRUE, // CopyAlways
  1622. FALSE // ApplyACLsAlways
  1623. );
  1624. if (!NT_SUCCESS(Status)) {
  1625. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive of %ws failed %lx\n", Path2, Status));
  1626. continue;
  1627. }
  1628. //
  1629. // Now open the services key in both registries
  1630. //
  1631. Status = SpGetValueKey(
  1632. DstHandle,
  1633. Path2,
  1634. L"Service",
  1635. sizeof(TemporaryBuffer),
  1636. (PVOID)TemporaryBuffer,
  1637. &Size
  1638. );
  1639. if (!NT_SUCCESS(Status)) {
  1640. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Couldn't get target service for %ws, 0x%x\n", Path2,Status));
  1641. continue;
  1642. }
  1643. RtlCopyMemory(Path,
  1644. ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->Data,
  1645. ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength
  1646. );
  1647. Path[((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength/sizeof(WCHAR)] = UNICODE_NULL;
  1648. INIT_OBJA(&Obj,
  1649. &UnicodeString,
  1650. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
  1651. );
  1652. Status = ZwOpenKey(&TmpHandle, KEY_ALL_ACCESS, &Obj);
  1653. if (!NT_SUCCESS(Status)) {
  1654. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey of Services failed %lx for %ws\n", Status, Path2));
  1655. continue;
  1656. }
  1657. //
  1658. // Get the image path -- remember, since we are in Textmode Setup, the path
  1659. // does *not* contain system32\drivers
  1660. //
  1661. Status = SpGetValueKey(TmpHandle,
  1662. Path,
  1663. L"ImagePath",
  1664. sizeof(TemporaryBuffer),
  1665. (PVOID)TemporaryBuffer,
  1666. &Size
  1667. );
  1668. if (!NT_SUCCESS(Status)) {
  1669. //
  1670. // if ImagePath isn't there, we default to using the service name.
  1671. //
  1672. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: GetValue for ImagePath failed %lx for %ws, we'll default it.\n", Status, Path));
  1673. wcscpy( ImageName, Path );
  1674. wcscat( ImageName, L".sys" );
  1675. } else {
  1676. RtlCopyMemory(ImageName,
  1677. ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->Data,
  1678. ((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength
  1679. );
  1680. ImageName[((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->DataLength/sizeof(WCHAR)] = UNICODE_NULL;
  1681. }
  1682. //
  1683. // Now delete the old services entry first
  1684. //
  1685. swprintf(TemporaryBuffer,
  1686. L"\\Registry\\SysPrepReg\\ControlSet%03d\\Services\\%ws",
  1687. Number,
  1688. Path
  1689. );
  1690. INIT_OBJA(&Obj, &UnicodeString, TemporaryBuffer);
  1691. Status = ZwOpenKey(&TmpHandle2, KEY_ALL_ACCESS, &Obj);
  1692. if (NT_SUCCESS(Status)) {
  1693. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Deleting target service %ws so that we can recreate it cleanly.\n", Path));
  1694. ZwDeleteKey(TmpHandle2);
  1695. ZwClose(TmpHandle2);
  1696. TmpHandle2 = NULL;
  1697. }
  1698. //
  1699. // Now get path to services key in the SysPrep image
  1700. //
  1701. swprintf(TemporaryBuffer,
  1702. L"\\Registry\\SysPrepReg\\ControlSet%03d\\Services",
  1703. Number
  1704. );
  1705. INIT_OBJA(&Obj, &UnicodeString, TemporaryBuffer);
  1706. Status = ZwOpenKey(&TmpHandle2, KEY_ALL_ACCESS, &Obj);
  1707. if (!NT_SUCCESS(Status)) {
  1708. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey of SysPrepReg services failed %lx for %ws\n", Status,Path2));
  1709. continue;
  1710. }
  1711. //
  1712. // Build the path to the server source.
  1713. //
  1714. wcscpy(SrvPath, SysPrepDriversDevice);
  1715. SpConcatenatePaths(SrvPath, ImageName);
  1716. //
  1717. // Build the path in the SysPrep image for where to store it
  1718. //
  1719. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1720. wcscpy(TemporaryBuffer, L"\\??\\");
  1721. SpConcatenatePaths(TemporaryBuffer, Tmp);
  1722. SpConcatenatePaths(TemporaryBuffer, L"\\System32\\Drivers\\");
  1723. SpConcatenatePaths(TemporaryBuffer, ImageName);
  1724. wcscpy(Path2, TemporaryBuffer);
  1725. //
  1726. // Copy the driver from the server
  1727. //
  1728. Status = SpCopyFileUsingNames(SrvPath,
  1729. Path2,
  1730. 0,
  1731. COPY_ONLY_IF_NOT_PRESENT | COPY_DECOMPRESS_SYSPREP
  1732. );
  1733. if (!NT_SUCCESS(Status)) {
  1734. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpCopyFilesUsingNames for %ws failed %lx\n", Path2, Status));
  1735. continue;
  1736. }
  1737. wcscpy( ImageName, L"Files." );
  1738. wcscat( ImageName, Path );
  1739. CopyListEmpty = FALSE;
  1740. // copy the rest of the files for this service by looking up the
  1741. // appropriate section in txtsetup.inf
  1742. SpAddSectionFilesToCopyList(
  1743. SetupSifHandle,
  1744. DiskFileLists,
  1745. DiskCount,
  1746. ImageName, // this is now L"Files.Path"
  1747. pVolumePath, // L"\\Device\\Harddisk0\\Partition1"
  1748. NULL, // it should look up the target directory
  1749. COPY_ONLY_IF_NOT_PRESENT,
  1750. TRUE // force nocompression, we don't know what
  1751. ); // type of driver it is.
  1752. //
  1753. // Now duplicate the services key
  1754. //
  1755. Status = SppCopyKeyRecursive(TmpHandle,
  1756. TmpHandle2,
  1757. Path,
  1758. Path,
  1759. TRUE, // CopyAlways
  1760. FALSE // ApplyACLsAlways
  1761. );
  1762. if (!NT_SUCCESS(Status)) {
  1763. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive for %ws failed %lx\n", Path, Status));
  1764. continue;
  1765. }
  1766. //
  1767. // Set the start type to 0
  1768. //
  1769. Size = 0;
  1770. Status = SpOpenSetValueAndClose(TmpHandle2,
  1771. Path,
  1772. L"Start",
  1773. REG_DWORD,
  1774. &Size,
  1775. sizeof(ULONG)
  1776. );
  1777. if (!NT_SUCCESS(Status)) {
  1778. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpOpenSetValueAndClose for %ws Start failed %lx\n", Path, Status));
  1779. continue;
  1780. }
  1781. //
  1782. // Set the image path to one with system32\drivers on the front. We do this by
  1783. // moving backwards thru the target path we have already built to the 3rd backslash
  1784. // from the end.
  1785. //
  1786. Tmp = &(Path2[wcslen(Path2)]);
  1787. for (Size = 0; Size < 3; Size++) {
  1788. while (*Tmp != L'\\') {
  1789. Tmp--;
  1790. }
  1791. Tmp--;
  1792. }
  1793. Tmp += 2;
  1794. Status = SpOpenSetValueAndClose(TmpHandle2,
  1795. Path,
  1796. L"ImagePath",
  1797. REG_EXPAND_SZ,
  1798. Tmp,
  1799. (wcslen(Tmp) + 1) * sizeof(WCHAR)
  1800. );
  1801. ZwClose(TmpHandle);
  1802. ZwClose(TmpHandle2);
  1803. TmpHandle = NULL;
  1804. TmpHandle2 = NULL;
  1805. if (!NT_SUCCESS(Status)) {
  1806. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpOpenSetValueAndClose for %ws ImagePath failed %lx\n", Path, Status));
  1807. continue;
  1808. }
  1809. }
  1810. //
  1811. // Copy over the NIC files, including the INF file.
  1812. //
  1813. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1814. wcscpy(Path, L"\\??\\");
  1815. SpConcatenatePaths(Path, Tmp);
  1816. Status = SpCopyNicFiles(SysPrepDriversDevice, Path);
  1817. //
  1818. // Get the HAL and just always copy it over.
  1819. //
  1820. //
  1821. // Now test for mp/up and then replace dependent drivers as necessary.
  1822. //
  1823. //
  1824. // Migrate the MountedDevices and DISK registry information.
  1825. //
  1826. ZwClose(SrcHandle);
  1827. SrcHandle = NULL;
  1828. ZwClose(DstHandle);
  1829. DstHandle = NULL;
  1830. //
  1831. // Open the system hive of the current build.
  1832. //
  1833. INIT_OBJA(&Obj, &UnicodeString2, L"\\Registry\\Machine\\SYSTEM");
  1834. Status = ZwOpenKey(&SrcHandle, KEY_READ, &Obj);
  1835. if (!NT_SUCCESS(Status)) {
  1836. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey for local SYSTEM failed %lx\n", Status));
  1837. goto CleanUp;
  1838. }
  1839. //
  1840. // Open the system hive of the build we are patching.
  1841. //
  1842. INIT_OBJA(&Obj, &UnicodeString2, L"\\Registry\\SysPrepReg");
  1843. Status = ZwOpenKey(&DstHandle, KEY_READ | KEY_WRITE, &Obj);
  1844. if (!NT_SUCCESS(Status)) {
  1845. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey for SysPrepReg SYSTEM failed %lx\n", Status));
  1846. goto CleanUp;
  1847. }
  1848. //
  1849. // Delete the existing subkeys of the MountedDevices key.
  1850. //
  1851. Status = SppDeleteKeyRecursive(DstHandle,
  1852. L"MountedDevices",
  1853. TRUE); // ThisKeyToo
  1854. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1855. Status = STATUS_SUCCESS;
  1856. }
  1857. if (!NT_SUCCESS(Status)) {
  1858. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppDeleteKeyRecursive of MountedDevices failed %lx\n", Status));
  1859. goto CleanUp;
  1860. }
  1861. //
  1862. // Copy the MountedDevices key over.
  1863. //
  1864. Status = SppCopyKeyRecursive(SrcHandle,
  1865. DstHandle,
  1866. L"MountedDevices",
  1867. L"MountedDevices",
  1868. TRUE, // CopyAlways
  1869. TRUE); // ApplyACLsAlways
  1870. if (!NT_SUCCESS(Status)) {
  1871. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive of MountedDevices failed %lx\n", Status));
  1872. goto CleanUp;
  1873. }
  1874. //
  1875. // Delete the existing subkeys of the DISK key. This routine returns
  1876. // STATUS_OBJECT_NAME_NOT_FOUND if the key does not exist, which is
  1877. // not an error in this case.
  1878. //
  1879. Status = SppDeleteKeyRecursive(DstHandle,
  1880. L"DISK",
  1881. TRUE); // ThisKeyToo
  1882. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1883. Status = STATUS_SUCCESS;
  1884. }
  1885. if (!NT_SUCCESS(Status)) {
  1886. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppDeleteKeyRecursive of DISK failed %lx\n", Status));
  1887. goto CleanUp;
  1888. }
  1889. //
  1890. // Copy the DISK key over.
  1891. //
  1892. Status = SppCopyKeyRecursive(SrcHandle,
  1893. DstHandle,
  1894. L"DISK",
  1895. L"DISK",
  1896. TRUE, // CopyAlways
  1897. TRUE); // ApplyACLsAlways
  1898. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1899. Status = STATUS_SUCCESS;
  1900. }
  1901. if (!NT_SUCCESS(Status)) {
  1902. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive of DISK failed %lx\n", Status));
  1903. Status = STATUS_SUCCESS;
  1904. goto CleanUp;
  1905. }
  1906. //
  1907. // Delete those subkeys of the CCS\Enum\STORAGE\Volume key that
  1908. // represent volumes that were never fully installed. This eliminates
  1909. // stale information about volumes that may not exist on this computer.
  1910. //
  1911. SpDeleteStorageVolumes( DstHandle, Number );
  1912. CleanUp:
  1913. if (!CopyListEmpty) {
  1914. //
  1915. // Copy files in the copy list.
  1916. //
  1917. WCHAR emptyString = L'\0';
  1918. PWCHAR lastComponent;
  1919. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1920. if (*Tmp != L'\0' && *(Tmp+1) == L':') {
  1921. Tmp += 2; // have it skip L"C:" at front of path
  1922. wcscpy(Path2, Tmp);
  1923. } else {
  1924. wcscpy(Path2, L"\\??\\");
  1925. SpConcatenatePaths(Path2, Tmp);
  1926. }
  1927. //
  1928. // first we need to remove the L"\i386" off the end of the source
  1929. // path since SpCopyFilesInCopyList or decendent will tack it on.
  1930. //
  1931. // divide up the source path into two parts so that SpConcatenatePaths
  1932. // does the right thing when it puts it back together.
  1933. //
  1934. wcscpy( SrvPath, SysPrepDriversDevice );
  1935. lastComponent = SrvPath + wcslen( SrvPath ) - 1;
  1936. while (lastComponent > SrvPath && *lastComponent != L'\\') {
  1937. lastComponent--;
  1938. }
  1939. if (lastComponent > SrvPath) {
  1940. *lastComponent = L'\0'; // this removes the architecture off the end
  1941. // now move backwards until we find the start of the last component
  1942. while (lastComponent > SrvPath && *lastComponent != L'\\') {
  1943. lastComponent--;
  1944. }
  1945. if (lastComponent > SrvPath) {
  1946. *lastComponent = L'\0';
  1947. lastComponent++;
  1948. } else {
  1949. lastComponent = &emptyString;
  1950. }
  1951. } else {
  1952. lastComponent = &emptyString;
  1953. }
  1954. SpCopyFilesInCopyList(
  1955. SetupSifHandle,
  1956. DiskFileLists,
  1957. DiskCount,
  1958. SrvPath, // L"\\device\\harddisk0\\partition1"
  1959. lastComponent, // L"\\$win_nt$.~ls"
  1960. Path2, // L"\\WINNT"
  1961. NULL
  1962. );
  1963. }
  1964. if (HaveCopyList) {
  1965. SpFreeCopyLists(&DiskFileLists,DiskCount);
  1966. }
  1967. if (SrcHandle != NULL) {
  1968. ZwClose(SrcHandle);
  1969. }
  1970. if (DstHandle != NULL) {
  1971. ZwClose(DstHandle);
  1972. }
  1973. if (TmpHandle != NULL) {
  1974. ZwClose(TmpHandle);
  1975. }
  1976. if (TmpHandle2 != NULL) {
  1977. ZwClose(TmpHandle2);
  1978. }
  1979. if (NeedToUnload) {
  1980. ZwUnloadKey(&DstObj);
  1981. NeedToUnload = FALSE;
  1982. }
  1983. if (pVolumePath != NULL) {
  1984. SpMemFree( pVolumePath );
  1985. }
  1986. //
  1987. // update the NT source path in the software section of the registry
  1988. // since we have a valid SysPrepDriversDevice
  1989. //
  1990. if (SysPrepDriversDevice && *SysPrepDriversDevice != L'\0') {
  1991. //
  1992. // Now load the local version of the SysPrep hives, using IMirror.Dat to find them
  1993. // NOTE: DstObj is assumed by CleanUp to still be the key.
  1994. //
  1995. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1996. wcscpy(Path, L"\\??\\");
  1997. wcscat(Path, Tmp);
  1998. wcscat(Path, L"\\System32\\Config\\Software");
  1999. INIT_OBJA(&DstObj, &UnicodeString1, L"\\Registry\\SysPrepReg");
  2000. INIT_OBJA(&Obj, &UnicodeString2, Path);
  2001. Status = ZwLoadKey(&DstObj, &Obj);
  2002. if (NT_SUCCESS(Status)) {
  2003. NeedToUnload = TRUE;
  2004. //
  2005. // Open the system hive of the build we are patching.
  2006. //
  2007. INIT_OBJA(&Obj, &UnicodeString2, L"\\Registry\\SysPrepReg\\Microsoft\\Windows\\CurrentVersion\\Setup");
  2008. Status = ZwOpenKey(&DstHandle, KEY_READ | KEY_WRITE, &Obj);
  2009. if (NT_SUCCESS(Status)) {
  2010. BOOLEAN haveDecentString = FALSE;
  2011. //
  2012. // the path is of the form
  2013. // \device\lanmanredirector\server\share\..\flat\i386
  2014. // when we want it of the form \\server\share\..\flat
  2015. //
  2016. Tmp = SysPrepDriversDevice + 1;
  2017. while (*Tmp != L'\0' && *Tmp != L'\\') {
  2018. Tmp++;
  2019. }
  2020. if (*Tmp == L'\\') {
  2021. Tmp++;
  2022. while (*Tmp != L'\0' && *Tmp != L'\\') {
  2023. Tmp++;
  2024. }
  2025. if (*Tmp == L'\\') { // back up one before the \server\share
  2026. // so we can put another \ on it
  2027. Tmp--;
  2028. wcscpy( Path, Tmp );
  2029. Tmp = Path;
  2030. *Tmp = L'\\'; // we now have \\server\share\..\flat\i386
  2031. Tmp = Path + wcslen(Path);
  2032. while (Tmp > Path && *Tmp != L'\\') {
  2033. Tmp--;
  2034. }
  2035. if (Tmp > Path) {
  2036. *Tmp = L'\0'; // remove the \i386
  2037. haveDecentString = TRUE;
  2038. }
  2039. }
  2040. }
  2041. if (haveDecentString) {
  2042. INIT_OBJA(&Obj, &UnicodeString2, L"SourcePath");
  2043. Status = ZwSetValueKey (DstHandle,
  2044. &UnicodeString2,
  2045. 0,
  2046. REG_SZ,
  2047. Path,
  2048. (wcslen(Path) + 1 ) * sizeof(WCHAR));
  2049. if (!NT_SUCCESS(Status)) {
  2050. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Setting SourcePath to %ws failed with 0x%x\n", Path, Status));
  2051. }
  2052. } else {
  2053. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Couldn't set SourcePath to %ws\n", SysPrepDriversDevice));
  2054. Status = STATUS_OBJECT_PATH_INVALID;
  2055. }
  2056. ZwClose(DstHandle);
  2057. DstHandle = NULL;
  2058. } else {
  2059. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey for SysPrepReg SOFTWARE failed %lx\n", Status));
  2060. }
  2061. } else {
  2062. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwLoadKey to SysPrepReg failed %lx\n", Status));
  2063. }
  2064. }
  2065. //
  2066. // patch boot.ini regardless of the status of the patching of everything
  2067. // else. if we don't patch boot.ini, the whole image has no hope of
  2068. // booting.
  2069. //
  2070. #ifdef _X86_
  2071. //
  2072. // Patch boot.ini if the ARC names have changed. Boot.ini will
  2073. // be on the active partition of disk 0.
  2074. //
  2075. for (volume = 0; volume < pMemoryData->NumberVolumes; volume++) {
  2076. volumeInfo = &pMemoryData->Volumes[volume];
  2077. if ((volumeInfo->DiskNumber == 0) &&
  2078. (volumeInfo->PartitionActive)) {
  2079. ULONG tmpLen;
  2080. wcscpy(Path, L"\\??\\");
  2081. tmpLen = wcslen(Path);
  2082. Path[tmpLen] = volumeInfo->DriveLetter;
  2083. Path[tmpLen+1] = L'\0';
  2084. wcscat(Path, L":\\boot.ini");
  2085. SpPatchBootIni(Path, pMemoryData);
  2086. break;
  2087. }
  2088. }
  2089. #endif
  2090. if (NeedToUnload) {
  2091. ZwUnloadKey(&DstObj);
  2092. }
  2093. if (Buffer != NULL) {
  2094. SpMemFree(Buffer);
  2095. }
  2096. return Status;
  2097. }
  2098. VOID
  2099. SpReplaceArcName(
  2100. IN PUCHAR CurrentArcName,
  2101. IN PMIRROR_CFG_INFO_MEMORY pMemoryData,
  2102. OUT PBOOLEAN Replaced
  2103. )
  2104. /*++
  2105. Routine Description:
  2106. This routine looks in pMemoryData to see if there is a partition
  2107. whose OriginalArcName is equal to CurrentArcName, and if so it
  2108. replaces CurrentArcName, adjusting the rest of the string that
  2109. follows CurrentArcName if needed.
  2110. Arguments:
  2111. CurrentArcName - The ARC name to check.
  2112. pMemoryData - A pointer to an in-memory copy of IMirror.Dat, modified to
  2113. match the specs of this computer (disk sizes etc).
  2114. Replaced - Returns TRUE if the name is replaced.
  2115. Return Value:
  2116. The NTSTATUS of the operation.
  2117. --*/
  2118. {
  2119. ULONG volume;
  2120. PMIRROR_VOLUME_INFO_MEMORY volumeInfo;
  2121. ULONG originalArcNameLength, newArcNameLength;
  2122. CHAR TmpArcName[128];
  2123. //
  2124. // Scan pMemoryData to see if any ARC names match.
  2125. //
  2126. *Replaced = FALSE;
  2127. for (volume = 0; volume < pMemoryData->NumberVolumes; volume++) {
  2128. volumeInfo = &pMemoryData->Volumes[volume];
  2129. originalArcNameLength = wcslen(volumeInfo->OriginalArcName);
  2130. wcstombs(TmpArcName, volumeInfo->OriginalArcName, originalArcNameLength+1);
  2131. if (RtlCompareMemory(TmpArcName, CurrentArcName, originalArcNameLength) == originalArcNameLength) {
  2132. //
  2133. // This is the partition that CurrentArcName refers to,
  2134. // see what the ARC name is now.
  2135. //
  2136. SpArcNameFromRegion(
  2137. volumeInfo->CreatedRegion,
  2138. TemporaryBuffer,
  2139. sizeof(TemporaryBuffer),
  2140. PartitionOrdinalOnDisk,
  2141. PrimaryArcPath);
  2142. //
  2143. // If we got an ARC name and it is different from what it was on
  2144. // the old machine, we need to replace.
  2145. //
  2146. if (*TemporaryBuffer &&
  2147. (wcscmp(volumeInfo->OriginalArcName, TemporaryBuffer) != 0)) {
  2148. //
  2149. // See if we need to adjust the buffer because the length
  2150. // of the ARC names is different.
  2151. //
  2152. newArcNameLength = wcslen(TemporaryBuffer);
  2153. if (newArcNameLength != originalArcNameLength) {
  2154. memmove(
  2155. CurrentArcName+newArcNameLength,
  2156. CurrentArcName+originalArcNameLength,
  2157. strlen(CurrentArcName+originalArcNameLength) + 1);
  2158. }
  2159. //
  2160. // Copy over the new ARC name.
  2161. //
  2162. wcstombs(TmpArcName, TemporaryBuffer, newArcNameLength);
  2163. memcpy(CurrentArcName, TmpArcName, newArcNameLength);
  2164. *Replaced = TRUE;
  2165. break; // no need to look at any other volumeInfo's.
  2166. }
  2167. }
  2168. }
  2169. }
  2170. NTSTATUS
  2171. SpPatchBootIni(
  2172. IN PWCHAR BootIniPath,
  2173. IN PMIRROR_CFG_INFO_MEMORY pMemoryData
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. This routine modifies boot.ini to modify any ARC names that have
  2178. changed.
  2179. Arguments:
  2180. BootIniPath - The path to the local boot.ini.
  2181. pMemoryData - A pointer to an in-memory copy of IMirror.Dat, modified to
  2182. match the specs of this computer (disk sizes etc).
  2183. Return Value:
  2184. The NTSTATUS of the operation.
  2185. --*/
  2186. {
  2187. ULONG ulLen;
  2188. NTSTATUS Status = STATUS_SUCCESS;
  2189. UNICODE_STRING UnicodeString;
  2190. OBJECT_ATTRIBUTES Obja;
  2191. IO_STATUS_BLOCK IoStatusBlock;
  2192. HANDLE Handle;
  2193. PCHAR pFileData = NULL, pNewFileData = NULL;
  2194. PCHAR curLoc, endOfLine;
  2195. BOOLEAN changedFile = FALSE;
  2196. PWCHAR TmpBootIni = NULL;
  2197. //
  2198. // Read in the current boot.ini.
  2199. //
  2200. INIT_OBJA(&Obja, &UnicodeString, BootIniPath);
  2201. Status = ZwCreateFile(&Handle,
  2202. FILE_GENERIC_READ,
  2203. &Obja,
  2204. &IoStatusBlock,
  2205. NULL,
  2206. FILE_ATTRIBUTE_NORMAL,
  2207. FILE_SHARE_READ,
  2208. FILE_OPEN,
  2209. FILE_SYNCHRONOUS_IO_NONALERT,
  2210. NULL,
  2211. 0
  2212. );
  2213. if(!NT_SUCCESS(Status)) {
  2214. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not open %ws: %lx\n", BootIniPath, Status));
  2215. goto Cleanup;
  2216. }
  2217. Status = SpGetFileSize(Handle, &ulLen);
  2218. if(!NT_SUCCESS(Status)) {
  2219. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not SpGetFileSize: %lx\n", Status));
  2220. ZwClose(Handle);
  2221. goto Cleanup;
  2222. }
  2223. //
  2224. // Allocate memory and read in the file.
  2225. //
  2226. pFileData = SpMemAlloc(ulLen);
  2227. Status = ZwReadFile(Handle,
  2228. NULL,
  2229. NULL,
  2230. NULL,
  2231. &IoStatusBlock,
  2232. pFileData,
  2233. ulLen,
  2234. 0,
  2235. NULL
  2236. );
  2237. ZwClose(Handle);
  2238. if(!NT_SUCCESS(Status)) {
  2239. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not ZwReadFile: %lx\n", Status));
  2240. goto Cleanup;
  2241. }
  2242. //
  2243. // Allocate memory for the new copy of the file (we use twice the
  2244. // current size as a worst-case scenario).
  2245. //
  2246. pNewFileData = SpMemAlloc(ulLen * 2);
  2247. memcpy(pNewFileData, pFileData, ulLen);
  2248. pNewFileData[ulLen] = '\0'; // NULL-terminate to make replace easier.
  2249. //
  2250. // Run through each line of the file, looking for ARC names to
  2251. // replace. ARC names are either after the "default=" text or
  2252. // else they start a line.
  2253. //
  2254. curLoc = pNewFileData;
  2255. while (TRUE) {
  2256. BOOLEAN replaced = FALSE;
  2257. LONG adjustment;
  2258. //
  2259. // Replace if this is a "default=" line, or a line that does not
  2260. // start with "timeout=" or a '['.
  2261. //
  2262. if (RtlCompareMemory(curLoc, "default=", strlen("default=")) == strlen("default=")) {
  2263. SpReplaceArcName(curLoc + strlen("default="), pMemoryData, &replaced);
  2264. } else if ((*curLoc != '[') &&
  2265. (RtlCompareMemory(curLoc, "timeout=", strlen("timeout=")) != strlen("timeout="))) {
  2266. SpReplaceArcName(curLoc, pMemoryData, &replaced);
  2267. }
  2268. if (replaced) {
  2269. changedFile = TRUE;
  2270. }
  2271. //
  2272. // Look for a '\n' in the file.
  2273. //
  2274. endOfLine = strchr(curLoc, '\n');
  2275. if (endOfLine == NULL) {
  2276. break;
  2277. }
  2278. curLoc = endOfLine + 1;
  2279. if (*curLoc == L'\0') {
  2280. break;
  2281. }
  2282. }
  2283. //
  2284. // If we changed the file, write out the new one.
  2285. //
  2286. if (changedFile) {
  2287. //
  2288. // Replace the old boot.ini with the new one.
  2289. //
  2290. TmpBootIni = SpDupStringW(BootIniPath);
  2291. if (!TmpBootIni) {
  2292. goto Cleanup;
  2293. }
  2294. TmpBootIni[wcslen(TmpBootIni)-1] = L'$'; // make it boot.in$
  2295. INIT_OBJA(&Obja, &UnicodeString, TmpBootIni);
  2296. Status = ZwCreateFile(&Handle,
  2297. FILE_GENERIC_WRITE,
  2298. &Obja,
  2299. &IoStatusBlock,
  2300. NULL,
  2301. FILE_ATTRIBUTE_NORMAL,
  2302. 0, // no sharing
  2303. FILE_OVERWRITE_IF,
  2304. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_WRITE_THROUGH,
  2305. NULL,
  2306. 0
  2307. );
  2308. if(!NT_SUCCESS(Status)) {
  2309. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not create %ws: %lx\n", TmpBootIni, Status));
  2310. goto Cleanup;
  2311. }
  2312. Status = ZwWriteFile(Handle,
  2313. NULL,
  2314. NULL,
  2315. NULL,
  2316. &IoStatusBlock,
  2317. pNewFileData,
  2318. strlen(pNewFileData),
  2319. NULL,
  2320. NULL
  2321. );
  2322. ZwClose(Handle);
  2323. if(!NT_SUCCESS(Status)) {
  2324. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not ZwWriteFile: %lx\n", Status));
  2325. goto Cleanup;
  2326. }
  2327. //
  2328. // Now that we have written the tmp file, do the swap.
  2329. //
  2330. Status = SpDeleteFile(BootIniPath, NULL, NULL);
  2331. if(!NT_SUCCESS(Status)) {
  2332. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not SpDeleteFile(%ws): %lx\n", BootIniPath, Status));
  2333. goto Cleanup;
  2334. }
  2335. Status = SpRenameFile(TmpBootIni, BootIniPath, FALSE);
  2336. if(!NT_SUCCESS(Status)) {
  2337. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not SpRenameFile(%ws,%ws): %lx\n", TmpBootIni, BootIniPath, Status));
  2338. goto Cleanup;
  2339. }
  2340. }
  2341. Cleanup:
  2342. if (pFileData != NULL) {
  2343. SpMemFree(pFileData);
  2344. }
  2345. if (pNewFileData != NULL) {
  2346. SpMemFree(pNewFileData);
  2347. }
  2348. if (TmpBootIni != NULL) {
  2349. SpMemFree(TmpBootIni);
  2350. }
  2351. return Status;
  2352. }
  2353. NTSTATUS
  2354. SpCopyNicFiles(
  2355. IN PWCHAR SetupPath,
  2356. IN PWCHAR DestPath
  2357. )
  2358. /*++
  2359. Routine Description:
  2360. This routine packages up information and sends it to the BINL server, getting back
  2361. a list of files to copy to support the given NIC. It then copies those files.
  2362. Arguments:
  2363. SetupPath - Setup path that supports the SysPrep image.
  2364. DestPath - Path to the winnt directory.
  2365. Return Value:
  2366. The NTSTATUS of the operation.
  2367. --*/
  2368. {
  2369. PSPUDP_PACKET pUdpPacket = NULL;
  2370. WCHAR UNALIGNED * pPacketEnd;
  2371. PSP_NETCARD_INFO_REQ pReqPacket;
  2372. PSP_NETCARD_INFO_RSP pRspPacket;
  2373. ULONG PacketSize;
  2374. NTSTATUS Status = STATUS_SUCCESS;
  2375. ULONG i,j;
  2376. PWCHAR pSrc, pDst, pTmp;
  2377. WCHAR SrcFqn[MAX_PATH];
  2378. WCHAR DstFqn[MAX_PATH];
  2379. //
  2380. // BINL expects the path to be a UNC w/o the architecture type, so take the current
  2381. // setup path, in the form of "\device\lanmanredirector\server\share\...\i386" and
  2382. // make it "\\server\share\..."
  2383. //
  2384. // First remove the architecture type, and the the leading stuff.
  2385. //
  2386. wcscpy(SrcFqn, SetupPath);
  2387. pTmp = &(SrcFqn[wcslen(SrcFqn)]);
  2388. while ((*pTmp != L'\\') && (pTmp != SrcFqn)) {
  2389. pTmp--;
  2390. }
  2391. if (*pTmp == L'\\') {
  2392. *pTmp = UNICODE_NULL;
  2393. }
  2394. pTmp = SrcFqn;
  2395. pTmp++;
  2396. while ((*pTmp != UNICODE_NULL) && (*pTmp != L'\\')) {
  2397. pTmp++;
  2398. }
  2399. if (*pTmp == L'\\') {
  2400. pTmp++;
  2401. }
  2402. while ((*pTmp != UNICODE_NULL) && (*pTmp != L'\\')) {
  2403. pTmp++;
  2404. }
  2405. if (*pTmp == L'\\') {
  2406. pTmp--;
  2407. *pTmp = L'\\';
  2408. }
  2409. //
  2410. // Allocate the packet
  2411. //
  2412. PacketSize = FIELD_OFFSET(SPUDP_PACKET, Data[0]) +
  2413. FIELD_OFFSET(SP_NETCARD_INFO_REQ, SetupPath[0]) +
  2414. (wcslen(pTmp) + 1) * sizeof(WCHAR);
  2415. pUdpPacket = (PSPUDP_PACKET)SpMemAllocNonPagedPool(PacketSize);
  2416. //
  2417. // Fill in the packet
  2418. //
  2419. RtlCopyMemory(&(pUdpPacket->Signature[0]), SetupRequestSignature, 4);
  2420. pUdpPacket->Length = PacketSize - FIELD_OFFSET(SPUDP_PACKET, RequestType);
  2421. pUdpPacket->RequestType = 0;
  2422. pUdpPacket->Status = STATUS_SUCCESS;
  2423. pUdpPacket->SequenceNumber = 1;
  2424. pUdpPacket->FragmentNumber = 1;
  2425. pUdpPacket->FragmentTotal = 1;
  2426. pReqPacket = (PSP_NETCARD_INFO_REQ)(&(pUdpPacket->Data[0]));
  2427. pReqPacket->Version = OSCPKT_NETCARD_REQUEST_VERSION;
  2428. RtlCopyMemory(&(pReqPacket->CardInfo), &RemoteSysPrepNetCardInfo, sizeof(NET_CARD_INFO));
  2429. wcscpy(&(pReqPacket->SetupPath[0]), pTmp);
  2430. #if defined(_AMD64_)
  2431. pReqPacket->Architecture = PROCESSOR_ARCHITECTURE_AMD64;
  2432. #elif defined(_IA64_)
  2433. pReqPacket->Architecture = PROCESSOR_ARCHITECTURE_IA64;
  2434. #elif defined(_X86_)
  2435. pReqPacket->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
  2436. #else
  2437. #error "No Target Architecture"
  2438. #endif
  2439. //
  2440. // Open the Udp stack
  2441. //
  2442. Status = SpUdpConnect();
  2443. if (!NT_SUCCESS(Status)) {
  2444. goto CleanUp;
  2445. }
  2446. //
  2447. // Send the request
  2448. //
  2449. Status = SpUdpSendAndReceiveDatagram(pUdpPacket,
  2450. PacketSize,
  2451. RemoteServerIpAddress,
  2452. BINL_DEFAULT_PORT,
  2453. SpSysPrepNicRcvFunc
  2454. );
  2455. SpUdpDisconnect();
  2456. if (!NT_SUCCESS(Status)) {
  2457. goto CleanUp;
  2458. }
  2459. //
  2460. // Get the received packet
  2461. //
  2462. SpMemFree(pUdpPacket);
  2463. pUdpPacket = (PSPUDP_PACKET)pGlobalResponsePacket;
  2464. Status = pUdpPacket->Status;
  2465. if (!NT_SUCCESS(Status)) {
  2466. goto CleanUp;
  2467. }
  2468. if (GlobalResponsePacketLength <
  2469. (ULONG)(FIELD_OFFSET(SPUDP_PACKET, Data[0]) + FIELD_OFFSET(SP_NETCARD_INFO_RSP, MultiSzFiles[0]))) {
  2470. Status = STATUS_INVALID_PARAMETER;
  2471. goto CleanUp;
  2472. }
  2473. pRspPacket = (PSP_NETCARD_INFO_RSP)(&(pUdpPacket->Data[0]));
  2474. pPacketEnd = (WCHAR UNALIGNED *)(((PUCHAR)pGlobalResponsePacket) + GlobalResponsePacketLength);
  2475. //
  2476. // Now copy each file
  2477. //
  2478. pTmp = &(pRspPacket->MultiSzFiles[0]);
  2479. for (i = 0; i < pRspPacket->cFiles;) {
  2480. i++;
  2481. if (pTmp >= pPacketEnd) {
  2482. Status = STATUS_INVALID_PARAMETER;
  2483. goto CleanUp;
  2484. }
  2485. //
  2486. // Be careful about reading this data, since it's come in over the
  2487. // network. ie., make sure that the string length is reasonable
  2488. // before proceeding with processing the string.
  2489. //
  2490. pSrc = pTmp;
  2491. try {
  2492. j = wcslen(pSrc);
  2493. } except(EXCEPTION_EXECUTE_HANDLER) {
  2494. j = sizeof(SrcFqn)/sizeof(WCHAR) + 1;
  2495. }
  2496. if (j + wcslen(SetupPath) + 1 > sizeof(SrcFqn)/sizeof(WCHAR)) {
  2497. Status = STATUS_INVALID_PARAMETER;
  2498. goto CleanUp;
  2499. }
  2500. pDst = pTmp = pSrc + j + 1;
  2501. if (pTmp >= pPacketEnd) {
  2502. Status = STATUS_INVALID_PARAMETER;
  2503. goto CleanUp;
  2504. }
  2505. wcscpy(SrcFqn, SetupPath);
  2506. SpConcatenatePaths(SrcFqn, pSrc);
  2507. wcscpy(DstFqn, DestPath);
  2508. if (i == pRspPacket->cFiles) { // the last file in the list is the INF
  2509. SpConcatenatePaths(DstFqn, L"inf");
  2510. } else { // all the others go in system32\drivers
  2511. SpConcatenatePaths(DstFqn, L"system32\\drivers");
  2512. }
  2513. if (*pDst != UNICODE_NULL) {
  2514. try {
  2515. j = wcslen(pDst);
  2516. } except(EXCEPTION_EXECUTE_HANDLER) {
  2517. j = sizeof(DstFqn)/sizeof(WCHAR) + 1;
  2518. }
  2519. if (j+wcslen(DstFqn)+1 > sizeof(DstFqn)/sizeof(WCHAR)) {
  2520. Status = STATUS_INVALID_PARAMETER;
  2521. goto CleanUp;
  2522. }
  2523. pTmp = pDst + j + 1;
  2524. if (pTmp >= pPacketEnd) {
  2525. Status = STATUS_INVALID_PARAMETER;
  2526. goto CleanUp;
  2527. }
  2528. SpConcatenatePaths(DstFqn, pDst);
  2529. } else {
  2530. SpConcatenatePaths(DstFqn, pSrc);
  2531. pTmp = pDst + 1;
  2532. }
  2533. Status = SpCopyFileUsingNames(SrcFqn, DstFqn, 0, COPY_DECOMPRESS_SYSPREP );
  2534. if (!NT_SUCCESS(Status)) {
  2535. goto CleanUp;
  2536. }
  2537. }
  2538. CleanUp:
  2539. if (pUdpPacket != NULL) {
  2540. SpMemFree(pUdpPacket);
  2541. }
  2542. return Status;
  2543. }
  2544. NTSTATUS
  2545. SpSysPrepNicRcvFunc(
  2546. PVOID DataBuffer,
  2547. ULONG DataBufferLength
  2548. )
  2549. /*++
  2550. Routine Description:
  2551. This routine receives datagrams from the server into the global variable
  2552. pGlobalResponsePacket, iff it is NULL, otherwise it is presumed to hold data
  2553. and the incoming packet is assumed to be a duplicate response packet.
  2554. NOTE: spudp.c guarantees singly-threaded callbacks, so we don't have to spin lock
  2555. here.
  2556. Arguments:
  2557. DataBuffer - The incoming data.
  2558. DataBufferLength - Length of the data in bytes.
  2559. Return Value:
  2560. The NTSTATUS of the operation.
  2561. --*/
  2562. {
  2563. PSPUDP_PACKET pUdpPacket;
  2564. WCHAR UNALIGNED * pPacketEnd;
  2565. if ((pGlobalResponsePacket != NULL) || (DataBufferLength == 0)) {
  2566. return STATUS_UNSUCCESSFUL;
  2567. }
  2568. pUdpPacket = (PSPUDP_PACKET)DataBuffer;
  2569. if (RtlCompareMemory(&(pUdpPacket->Signature[0]), SetupResponseSignature, 4) != 4) {
  2570. return STATUS_UNSUCCESSFUL;
  2571. }
  2572. pGlobalResponsePacket = SpMemAlloc(DataBufferLength + sizeof(WCHAR));
  2573. RtlCopyMemory(pGlobalResponsePacket, DataBuffer, DataBufferLength);
  2574. pPacketEnd = (WCHAR UNALIGNED *)(((PUCHAR)pGlobalResponsePacket) + DataBufferLength);
  2575. *pPacketEnd = L'\0'; // NULL-terminate it
  2576. GlobalResponsePacketLength = DataBufferLength;
  2577. return STATUS_SUCCESS;
  2578. }
  2579. VOID
  2580. SpSysPrepFailure(
  2581. ULONG ReasonNumber,
  2582. PVOID Parameter1,
  2583. PVOID Parameter2
  2584. )
  2585. /*++
  2586. Routine Description:
  2587. Inform the user that we were unable to bring down the sysprep image
  2588. correctly.
  2589. This is a fatal condition.
  2590. Arguments:
  2591. None.
  2592. Return Value:
  2593. Does not return.
  2594. --*/
  2595. {
  2596. ULONG ValidKeys[2] = { KEY_F3, 0 };
  2597. PWCHAR MessageText = NULL;
  2598. WCHAR blankMessage[1];
  2599. if (ReasonNumber > 0) {
  2600. // Get the message text.
  2601. //
  2602. if (Parameter1 == NULL) {
  2603. MessageText = SpRetreiveMessageText(NULL,ReasonNumber,NULL,0);
  2604. } else {
  2605. SpFormatMessage( TemporaryBuffer,
  2606. sizeof(TemporaryBuffer),
  2607. ReasonNumber,
  2608. Parameter1,
  2609. Parameter2
  2610. );
  2611. MessageText = SpDupStringW(TemporaryBuffer);
  2612. }
  2613. if (MessageText == NULL) {
  2614. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpSysPrepFailure: SpRetreiveMessageText %u returned NULL\n",ReasonNumber));
  2615. }
  2616. }
  2617. if (MessageText == NULL) {
  2618. blankMessage[0] = L'\0';
  2619. MessageText = &blankMessage[0];
  2620. }
  2621. CLEAR_CLIENT_SCREEN();
  2622. SpStartScreen( SP_SCRN_SYSPREP_FATAL_FAILURE,
  2623. 3,
  2624. HEADER_HEIGHT+1,
  2625. FALSE,
  2626. FALSE,
  2627. DEFAULT_ATTRIBUTE,
  2628. MessageText
  2629. );
  2630. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  2631. SpWaitValidKey(ValidKeys,NULL,NULL);
  2632. SpDone(0,FALSE,FALSE);
  2633. }
  2634. NTSTATUS
  2635. SpSysPrepSetShortFileName (
  2636. PWCHAR Source,
  2637. PWCHAR Dest
  2638. )
  2639. /*++
  2640. Routine Description:
  2641. Try to set the short filename out of the sysprep image.
  2642. This should be considered non-fatal if it fails since not all
  2643. files will have this information set for them.
  2644. Arguments:
  2645. Source :
  2646. Return Value:
  2647. The status code from setting the info. May not return if we hit a failure
  2648. and the user specifies to abort the setup.
  2649. --*/
  2650. {
  2651. ULONG stringLength = 0;
  2652. ULONG FileNameInformationLength = 0;
  2653. PWCHAR fullName = NULL;
  2654. PWCHAR SFNBuffer = NULL;
  2655. HANDLE sourceHandle = NULL;
  2656. HANDLE streamHandle = NULL;
  2657. HANDLE destHandle = NULL;
  2658. OBJECT_ATTRIBUTES Obja;
  2659. IO_STATUS_BLOCK IoStatusBlock;
  2660. UNICODE_STRING UnicodeString;
  2661. NTSTATUS Status;
  2662. MIRROR_SFN_STREAM mirrorHeader;
  2663. LARGE_INTEGER byteOffset;
  2664. ULONG bytesRead;
  2665. BOOLEAN haveSFN = FALSE;
  2666. BOOLEAN haveStream = FALSE;
  2667. BOOLEAN haveSourceAttributes = FALSE;
  2668. PFILE_NAME_INFORMATION FileNameInformation;
  2669. if ((Source == NULL) || (Dest == NULL)) {
  2670. return STATUS_SUCCESS;
  2671. }
  2672. // alloc a buffer to hold the full file of the source including stream
  2673. while (*(Source+stringLength) != L'\0') {
  2674. stringLength++;
  2675. }
  2676. stringLength += sizeof( IMIRROR_SFN_STREAM_NAME ) + 1; // + 1 for size of null
  2677. stringLength *= sizeof(WCHAR);
  2678. fullName = SpMemAlloc( stringLength );
  2679. if (!fullName) {
  2680. Status = STATUS_SUCCESS;
  2681. goto exit;
  2682. }
  2683. wcscpy( fullName, Source );
  2684. wcscat( fullName, IMIRROR_SFN_STREAM_NAME );
  2685. //
  2686. // Open the source stream.
  2687. //
  2688. INIT_OBJA(&Obja,&UnicodeString,fullName);
  2689. Status = ZwCreateFile(
  2690. &streamHandle,
  2691. GENERIC_READ | SYNCHRONIZE,
  2692. &Obja,
  2693. &IoStatusBlock,
  2694. NULL,
  2695. 0,
  2696. FILE_SHARE_READ,
  2697. FILE_OPEN,
  2698. FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  2699. NULL,
  2700. 0
  2701. );
  2702. if ( ! NT_SUCCESS(Status) ) {
  2703. //
  2704. // for now, if a directory or file doesn't have our stream, it's ok.
  2705. // we'll just skip it.
  2706. //
  2707. Status = STATUS_SUCCESS;
  2708. goto exit;
  2709. }
  2710. byteOffset.QuadPart = 0;
  2711. Status = ZwReadFile(streamHandle,
  2712. NULL,
  2713. NULL,
  2714. NULL,
  2715. &IoStatusBlock,
  2716. (PCHAR) &mirrorHeader,
  2717. sizeof( mirrorHeader ),
  2718. &byteOffset,
  2719. NULL
  2720. );
  2721. if (!NT_SUCCESS(Status) ||
  2722. (IoStatusBlock.Information < sizeof( mirrorHeader ))) {
  2723. //
  2724. // we can't read the header correctly. just skip setting SFN.
  2725. //
  2726. Status = STATUS_SUCCESS;
  2727. goto exit;
  2728. }
  2729. if (mirrorHeader.StreamVersion != IMIRROR_SFN_STREAM_VERSION) {
  2730. //
  2731. // we can't read the header correctly. just skip setting SFN.
  2732. //
  2733. Status = STATUS_SUCCESS;
  2734. goto exit;
  2735. }
  2736. haveStream = TRUE;
  2737. //
  2738. // allocate a buffer to hold the SFN. The size is embedded in the header.
  2739. // take off room for the structure and tack on two for a UNICODE_NULL at
  2740. // the end, just in case the stream doesn't have one.
  2741. //
  2742. if (mirrorHeader.StreamLength) {
  2743. SFNBuffer = SpMemAlloc( mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM) + 2 );
  2744. if (!SFNBuffer) {
  2745. Status = STATUS_SUCCESS;
  2746. goto exit;
  2747. }
  2748. byteOffset.QuadPart += sizeof( mirrorHeader );
  2749. //
  2750. // now we read the SFN since we know how long it is.
  2751. //
  2752. Status = ZwReadFile(streamHandle,
  2753. NULL,
  2754. NULL,
  2755. NULL,
  2756. &IoStatusBlock,
  2757. SFNBuffer,
  2758. mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM),
  2759. &byteOffset,
  2760. NULL
  2761. );
  2762. if (!NT_SUCCESS(Status) ||
  2763. (IoStatusBlock.Information < (mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM)))) {
  2764. //
  2765. // oh joy, we can't read the SFN correctly
  2766. //
  2767. Status = STATUS_SUCCESS;
  2768. goto exit;
  2769. }
  2770. haveSFN = TRUE;
  2771. //
  2772. // tack on a unicode NULL just in case.
  2773. //
  2774. SFNBuffer[(mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM))/sizeof(WCHAR)] = UNICODE_NULL;
  2775. } else {
  2776. ASSERT(FALSE);
  2777. Status = STATUS_SUCCESS;
  2778. goto exit;
  2779. }
  2780. INIT_OBJA(&Obja,&UnicodeString,Dest);
  2781. Status = ZwCreateFile(
  2782. &destHandle,
  2783. FILE_READ_ATTRIBUTES |
  2784. FILE_WRITE_ATTRIBUTES |
  2785. FILE_READ_DATA |
  2786. FILE_WRITE_DATA |
  2787. DELETE,
  2788. &Obja,
  2789. &IoStatusBlock,
  2790. NULL,
  2791. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
  2792. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2793. FILE_OPEN,
  2794. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  2795. NULL,
  2796. 0
  2797. );
  2798. if (!NT_SUCCESS(Status)) {
  2799. //
  2800. // Maybe it's not a directory... Try for a file.
  2801. //
  2802. Status = ZwCreateFile(
  2803. &destHandle,
  2804. FILE_READ_ATTRIBUTES |
  2805. FILE_WRITE_ATTRIBUTES |
  2806. FILE_READ_DATA |
  2807. FILE_WRITE_DATA |
  2808. DELETE,
  2809. &Obja,
  2810. &IoStatusBlock,
  2811. NULL,
  2812. FILE_ATTRIBUTE_NORMAL,
  2813. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2814. FILE_OPEN,
  2815. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  2816. NULL,
  2817. 0
  2818. );
  2819. if( !NT_SUCCESS(Status) ) {
  2820. Status = STATUS_SUCCESS;
  2821. goto exit;
  2822. }
  2823. }
  2824. FileNameInformationLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + ((wcslen(SFNBuffer)+1)*sizeof(WCHAR));
  2825. FileNameInformation = SpMemAlloc( FileNameInformationLength );
  2826. if (FileNameInformation) {
  2827. FileNameInformation->FileNameLength = wcslen(SFNBuffer) * sizeof(WCHAR);
  2828. wcscpy( FileNameInformation->FileName, SFNBuffer );
  2829. Status = ZwSetInformationFile( destHandle,
  2830. &IoStatusBlock,
  2831. FileNameInformation,
  2832. FileNameInformationLength,
  2833. FileShortNameInformation
  2834. );
  2835. SpMemFree( FileNameInformation );
  2836. // Keep quiet.
  2837. Status = STATUS_SUCCESS;
  2838. }
  2839. exit:
  2840. if (fullName) {
  2841. SpMemFree( fullName );
  2842. }
  2843. if (SFNBuffer) {
  2844. SpMemFree( SFNBuffer );
  2845. }
  2846. if (streamHandle) {
  2847. ZwClose( streamHandle );
  2848. }
  2849. if (sourceHandle) {
  2850. ZwClose( sourceHandle );
  2851. }
  2852. if (destHandle) {
  2853. ZwClose( destHandle );
  2854. }
  2855. return(Status);
  2856. }
  2857. NTSTATUS
  2858. SpSysPrepSetExtendedInfo (
  2859. PWCHAR Source,
  2860. PWCHAR Dest,
  2861. BOOLEAN Directory,
  2862. BOOLEAN RootDir
  2863. )
  2864. /*++
  2865. Routine Description:
  2866. Try to set the extended information out of the sysprep image. This
  2867. includes the acl and the compression info. If we encounter an error,
  2868. we may not only fail the operation but also reboot if the user chooses
  2869. to abandon the setup.
  2870. Arguments:
  2871. Source :
  2872. Return Value:
  2873. The status code from setting the info. May not return if we hit a failure
  2874. and the user specifies to abort the setup.
  2875. --*/
  2876. {
  2877. ULONG stringLength = 0;
  2878. PWCHAR fullName = NULL;
  2879. PWCHAR rootWithSlash = NULL;
  2880. HANDLE sourceHandle = NULL;
  2881. HANDLE streamHandle = NULL;
  2882. HANDLE destHandle = NULL;
  2883. PCHAR sdBuffer = NULL;
  2884. OBJECT_ATTRIBUTES Obja;
  2885. IO_STATUS_BLOCK IoStatusBlock;
  2886. UNICODE_STRING UnicodeString;
  2887. NTSTATUS Status;
  2888. MIRROR_ACL_STREAM mirrorHeader;
  2889. LARGE_INTEGER byteOffset;
  2890. ULONG bytesRead;
  2891. ULONG ValidKeys[4] = { ASCI_ESC, KEY_F3, 0 };
  2892. ULONG WarnKeys[2] = { KEY_F3, 0 };
  2893. ULONG MnemonicKeys[] = { MnemonicContinueSetup, 0 };
  2894. BOOLEAN haveSecurityDescriptor = FALSE;
  2895. BOOLEAN haveStream = FALSE;
  2896. BOOLEAN haveSourceAttributes = FALSE;
  2897. FILE_BASIC_INFORMATION BasicFileInfo;
  2898. USHORT CompressionState;
  2899. if ((Source == NULL) || (Dest == NULL)) {
  2900. return STATUS_SUCCESS;
  2901. }
  2902. if (!RootDir) {
  2903. SpSysPrepSetShortFileName(Source, Dest);
  2904. }
  2905. mirrorHeader.ExtendedAttributes = 0;
  2906. // alloc a buffer to hold the full file of the source including stream
  2907. while (*(Source+stringLength) != L'\0') {
  2908. stringLength++;
  2909. }
  2910. stringLength += sizeof( IMIRROR_ACL_STREAM_NAME ) + 1; // + 1 for size of null
  2911. stringLength *= sizeof(WCHAR);
  2912. fullName = SpMemAlloc( stringLength );
  2913. wcscpy( fullName, Source );
  2914. wcscat( fullName, IMIRROR_ACL_STREAM_NAME );
  2915. //
  2916. // Open the source stream.
  2917. //
  2918. INIT_OBJA(&Obja,&UnicodeString,fullName);
  2919. Status = ZwCreateFile(
  2920. &streamHandle,
  2921. GENERIC_READ | SYNCHRONIZE,
  2922. &Obja,
  2923. &IoStatusBlock,
  2924. NULL,
  2925. 0,
  2926. FILE_SHARE_READ,
  2927. FILE_OPEN,
  2928. FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  2929. NULL,
  2930. 0
  2931. );
  2932. if ( ! NT_SUCCESS(Status) ) {
  2933. //
  2934. // for now, if a directory or file doesn't have our stream, it's ok.
  2935. // we'll just copy the attributes from the source.
  2936. //
  2937. Status = STATUS_SUCCESS;
  2938. goto setFileAttributes;
  2939. }
  2940. byteOffset.QuadPart = 0;
  2941. Status = ZwReadFile(streamHandle,
  2942. NULL,
  2943. NULL,
  2944. NULL,
  2945. &IoStatusBlock,
  2946. (PCHAR) &mirrorHeader,
  2947. sizeof( mirrorHeader ),
  2948. &byteOffset,
  2949. NULL
  2950. );
  2951. if (!NT_SUCCESS(Status) ||
  2952. (IoStatusBlock.Information < sizeof( mirrorHeader ))) {
  2953. //
  2954. // oh joy, we can't read the header correctly. Let's ask the user
  2955. // if he wants to continue or abort.
  2956. //
  2957. failSetInfo:
  2958. SpStartScreen(
  2959. SP_SCRN_SYSPREP_SETACL_FAILED,
  2960. 3,
  2961. HEADER_HEIGHT+1,
  2962. FALSE,
  2963. FALSE,
  2964. DEFAULT_ATTRIBUTE,
  2965. Dest
  2966. );
  2967. SpDisplayStatusOptions(
  2968. DEFAULT_STATUS_ATTRIBUTE,
  2969. SP_STAT_ESC_EQUALS_SKIP_FILE,
  2970. SP_STAT_F3_EQUALS_EXIT,
  2971. 0
  2972. );
  2973. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  2974. case ASCI_ESC: // skip file
  2975. break;
  2976. case KEY_F3: // exit setup
  2977. SpConfirmExit();
  2978. goto failSetInfo;
  2979. }
  2980. CLEAR_CLIENT_SCREEN();
  2981. //
  2982. // we're skipping the file, delete it if it's not a directory since
  2983. // it isn't correctly formed.
  2984. //
  2985. if (destHandle) {
  2986. ZwClose( destHandle );
  2987. destHandle = NULL;
  2988. }
  2989. if ( ! Directory ) {
  2990. SpDeleteFile(Dest,NULL,NULL);
  2991. } else {
  2992. if (!RootDir) {
  2993. SpDeleteFileEx( Dest, NULL, NULL,
  2994. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  2995. FILE_OPEN_FOR_BACKUP_INTENT );
  2996. }
  2997. }
  2998. return Status;
  2999. }
  3000. if (mirrorHeader.StreamVersion != IMIRROR_ACL_STREAM_VERSION) {
  3001. //
  3002. // oh joy, we've hit a file we don't support.
  3003. //
  3004. goto failSetInfo;
  3005. }
  3006. haveStream = TRUE;
  3007. //
  3008. // allocate a buffer to hold the security descriptor.
  3009. //
  3010. if (mirrorHeader.SecurityDescriptorLength) {
  3011. sdBuffer = SpMemAlloc( mirrorHeader.SecurityDescriptorLength );
  3012. byteOffset.QuadPart += sizeof( mirrorHeader );
  3013. //
  3014. // now we read the security descriptor since we know how long it is.
  3015. //
  3016. Status = ZwReadFile(streamHandle,
  3017. NULL,
  3018. NULL,
  3019. NULL,
  3020. &IoStatusBlock,
  3021. sdBuffer,
  3022. mirrorHeader.SecurityDescriptorLength,
  3023. &byteOffset,
  3024. NULL
  3025. );
  3026. if (!NT_SUCCESS(Status) ||
  3027. (IoStatusBlock.Information < mirrorHeader.SecurityDescriptorLength)) {
  3028. //
  3029. // oh joy, we can't read the SD correctly
  3030. //
  3031. goto failSetInfo;
  3032. }
  3033. haveSecurityDescriptor = TRUE;
  3034. }
  3035. setFileAttributes:
  3036. //
  3037. // we first open the source to get the file attributes and times that we're
  3038. // going to copy over to the dest.
  3039. //
  3040. INIT_OBJA(&Obja,&UnicodeString,Source);
  3041. Status = ZwCreateFile(
  3042. &sourceHandle,
  3043. FILE_READ_ATTRIBUTES,
  3044. &Obja,
  3045. &IoStatusBlock,
  3046. NULL,
  3047. 0,
  3048. FILE_SHARE_READ,
  3049. FILE_OPEN,
  3050. Directory ? ( FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT ) : FILE_NON_DIRECTORY_FILE,
  3051. NULL,
  3052. 0
  3053. );
  3054. if ( NT_SUCCESS(Status) ) {
  3055. Status = ZwQueryInformationFile( sourceHandle,
  3056. &IoStatusBlock,
  3057. &BasicFileInfo,
  3058. sizeof(BasicFileInfo),
  3059. FileBasicInformation
  3060. );
  3061. if (NT_SUCCESS(Status)) {
  3062. haveSourceAttributes = TRUE;
  3063. }
  3064. }
  3065. //
  3066. // Now we open the target to write out the security descriptor and
  3067. // attributes.
  3068. //
  3069. if (RootDir) {
  3070. //
  3071. // append a \ to the end of the dest path
  3072. //
  3073. stringLength = 0;
  3074. while (*(Dest+stringLength) != L'\0') {
  3075. stringLength++;
  3076. }
  3077. stringLength += 2; // one for null, one for backslash
  3078. stringLength *= sizeof(WCHAR);
  3079. rootWithSlash = SpMemAlloc( stringLength );
  3080. wcscpy( rootWithSlash, Dest );
  3081. wcscat( rootWithSlash, L"\\" );
  3082. INIT_OBJA(&Obja,&UnicodeString,rootWithSlash);
  3083. } else {
  3084. INIT_OBJA(&Obja,&UnicodeString,Dest);
  3085. }
  3086. Status = ZwCreateFile(
  3087. &destHandle,
  3088. WRITE_OWNER |
  3089. WRITE_DAC |
  3090. ACCESS_SYSTEM_SECURITY |
  3091. FILE_READ_ATTRIBUTES |
  3092. FILE_WRITE_ATTRIBUTES |
  3093. FILE_READ_DATA |
  3094. FILE_WRITE_DATA,
  3095. &Obja,
  3096. &IoStatusBlock,
  3097. NULL,
  3098. 0,
  3099. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3100. FILE_OPEN,
  3101. FILE_SYNCHRONOUS_IO_NONALERT,
  3102. NULL,
  3103. 0
  3104. );
  3105. if (!NT_SUCCESS(Status)) {
  3106. //
  3107. // oh joy, we can't open the target correctly.
  3108. //
  3109. goto failSetInfo;
  3110. }
  3111. // NOTE: figure out what to do about reparse points and encrypted files
  3112. // if (mirrorHeader.ExtendedAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  3113. // }
  3114. // if (mirrorHeader.ExtendedAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  3115. // }
  3116. if (mirrorHeader.ExtendedAttributes & FILE_ATTRIBUTE_COMPRESSED) {
  3117. CompressionState = COMPRESSION_FORMAT_DEFAULT;
  3118. } else {
  3119. CompressionState = COMPRESSION_FORMAT_NONE;
  3120. }
  3121. try {
  3122. Status = ZwFsControlFile( destHandle,
  3123. NULL,
  3124. NULL,
  3125. NULL,
  3126. &IoStatusBlock,
  3127. FSCTL_SET_COMPRESSION,
  3128. &CompressionState,
  3129. sizeof(CompressionState),
  3130. NULL,
  3131. 0
  3132. );
  3133. if (Status == STATUS_INVALID_DEVICE_REQUEST) {
  3134. //
  3135. // if this file system doesn't support compression for this
  3136. // object, we'll just ignore the error.
  3137. //
  3138. Status = STATUS_SUCCESS;
  3139. }
  3140. } except(EXCEPTION_EXECUTE_HANDLER) {
  3141. Status = STATUS_IN_PAGE_ERROR;
  3142. }
  3143. if ( NT_SUCCESS(Status) && ! haveSourceAttributes ) {
  3144. //
  3145. // if we don't have the source attributes, just grab them from the
  3146. // destination so that we have some attributes to manipulate.
  3147. //
  3148. Status = ZwQueryInformationFile( destHandle,
  3149. &IoStatusBlock,
  3150. &BasicFileInfo,
  3151. sizeof(BasicFileInfo),
  3152. FileBasicInformation
  3153. );
  3154. }
  3155. if (haveStream) {
  3156. //
  3157. // If this file has our stream, use the stream fields as the overriding
  3158. // values. They even override the source file's attributes on the server.
  3159. //
  3160. BasicFileInfo.FileAttributes = mirrorHeader.ExtendedAttributes;
  3161. BasicFileInfo.ChangeTime.QuadPart = mirrorHeader.ChangeTime.QuadPart;
  3162. }
  3163. if ( NT_SUCCESS(Status) ) {
  3164. if (Directory) {
  3165. BasicFileInfo.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  3166. } else if (BasicFileInfo.FileAttributes == 0) {
  3167. BasicFileInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  3168. }
  3169. Status = ZwSetInformationFile( destHandle,
  3170. &IoStatusBlock,
  3171. &BasicFileInfo,
  3172. sizeof(BasicFileInfo),
  3173. FileBasicInformation
  3174. );
  3175. if (Status == STATUS_INVALID_PARAMETER && RootDir) {
  3176. //
  3177. // if this file system doesn't support setting attributes on the
  3178. // root of the volume, we'll ignore the error.
  3179. //
  3180. Status = STATUS_SUCCESS;
  3181. }
  3182. }
  3183. if (!NT_SUCCESS(Status)) {
  3184. //
  3185. // post a warning that we couldn't set it. shouldn't be fatal.
  3186. //
  3187. SpStartScreen(
  3188. SP_SCRN_SYSPREP_COPY_FAILURE,
  3189. 3,
  3190. HEADER_HEIGHT+1,
  3191. FALSE,
  3192. FALSE,
  3193. DEFAULT_ATTRIBUTE,
  3194. Status,
  3195. Dest
  3196. );
  3197. SpDisplayStatusOptions(
  3198. DEFAULT_STATUS_ATTRIBUTE,
  3199. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  3200. SP_STAT_F3_EQUALS_EXIT,
  3201. 0
  3202. );
  3203. switch(SpWaitValidKey(WarnKeys,NULL,MnemonicKeys)) {
  3204. case KEY_F3: // exit setup
  3205. SpConfirmExit();
  3206. break;
  3207. default:
  3208. break;
  3209. }
  3210. }
  3211. if (haveSecurityDescriptor) {
  3212. try {
  3213. // the state of the security descriptor is unknown, let's protect
  3214. // ourselves
  3215. Status = ZwSetSecurityObject( destHandle,
  3216. OWNER_SECURITY_INFORMATION |
  3217. GROUP_SECURITY_INFORMATION |
  3218. DACL_SECURITY_INFORMATION |
  3219. SACL_SECURITY_INFORMATION,
  3220. (PSECURITY_DESCRIPTOR) sdBuffer
  3221. );
  3222. } except(EXCEPTION_EXECUTE_HANDLER) {
  3223. Status = STATUS_IN_PAGE_ERROR;
  3224. }
  3225. if (!NT_SUCCESS(Status)) {
  3226. //
  3227. // oh joy, we can't write the SD correctly.
  3228. //
  3229. goto failSetInfo;
  3230. }
  3231. }
  3232. // endSetExtended:
  3233. if (rootWithSlash) {
  3234. SpMemFree( rootWithSlash );
  3235. }
  3236. if (fullName) {
  3237. SpMemFree( fullName );
  3238. }
  3239. if (sdBuffer) {
  3240. SpMemFree( sdBuffer );
  3241. }
  3242. if (streamHandle) {
  3243. ZwClose( streamHandle );
  3244. }
  3245. if (sourceHandle) {
  3246. ZwClose( sourceHandle );
  3247. }
  3248. if (destHandle) {
  3249. ZwClose( destHandle );
  3250. }
  3251. return STATUS_SUCCESS;
  3252. }
  3253. NTSTATUS
  3254. SpCopyEAsAndStreams (
  3255. PWCHAR SourceFile,
  3256. HANDLE SourceHandle OPTIONAL,
  3257. PWCHAR TargetFile,
  3258. HANDLE TargetHandle OPTIONAL,
  3259. BOOLEAN Directory
  3260. )
  3261. //
  3262. // This copies the EAs and streams from the source to the target. The
  3263. // source and dest handles are specified for files and optional for
  3264. // directories.
  3265. //
  3266. {
  3267. NTSTATUS Status;
  3268. IO_STATUS_BLOCK IoStatusBlock;
  3269. ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  3270. FILE_EA_INFORMATION eaInfo;
  3271. HANDLE tempSourceHandle = SourceHandle;
  3272. HANDLE tempTargetHandle = TargetHandle;
  3273. HANDLE StreamHandle;
  3274. HANDLE newStreamHandle;
  3275. OBJECT_ATTRIBUTES Obja;
  3276. UNICODE_STRING UnicodeString;
  3277. ULONG StreamInfoSize = 4096-8; // alloc a whole page. spmemalloc reserves 8 bytes
  3278. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  3279. PFILE_STREAM_INFORMATION StreamInfo;
  3280. PUCHAR StreamBuffer = NULL;
  3281. UNICODE_STRING StreamName;
  3282. retryCopyEAs:
  3283. if (tempSourceHandle == NULL) {
  3284. INIT_OBJA(&Obja,&UnicodeString,SourceFile);
  3285. Status = ZwCreateFile(
  3286. &tempSourceHandle,
  3287. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  3288. &Obja,
  3289. &IoStatusBlock,
  3290. NULL,
  3291. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
  3292. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3293. FILE_OPEN_IF,
  3294. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  3295. NULL,
  3296. 0
  3297. );
  3298. if (!NT_SUCCESS(Status)) {
  3299. goto EndCopyEAs;
  3300. }
  3301. }
  3302. if (tempTargetHandle == NULL) {
  3303. INIT_OBJA(&Obja,&UnicodeString,TargetFile);
  3304. Status = ZwCreateFile(
  3305. &tempTargetHandle,
  3306. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  3307. &Obja,
  3308. &IoStatusBlock,
  3309. NULL,
  3310. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
  3311. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3312. FILE_OPEN_IF,
  3313. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  3314. NULL,
  3315. 0
  3316. );
  3317. if(!NT_SUCCESS(Status)) {
  3318. goto EndCopyEAs;
  3319. }
  3320. }
  3321. //
  3322. // EAs can be on either FAT or NTFS.
  3323. //
  3324. Status = ZwQueryInformationFile( tempSourceHandle,
  3325. &IoStatusBlock,
  3326. &eaInfo,
  3327. sizeof( eaInfo ),
  3328. FileEaInformation
  3329. );
  3330. if (Status == STATUS_SUCCESS && eaInfo.EaSize > 0) {
  3331. //
  3332. // FileEaInformation, oddly enough, doesn't tell you how big a
  3333. // buffer you need to retrieve the EAs. Instead, it tells you
  3334. // how much room the EAs take up on the disk (in OS/2 format)!
  3335. // So we use the OS/2 size as a rough approximation of how large
  3336. // a buffer we need.
  3337. //
  3338. ULONG actualEaSize = eaInfo.EaSize;
  3339. PCHAR eaBuffer;
  3340. do {
  3341. actualEaSize *= 2;
  3342. eaBuffer = SpMemAlloc( actualEaSize );
  3343. Status = ZwQueryEaFile( tempSourceHandle,
  3344. &IoStatusBlock,
  3345. eaBuffer,
  3346. actualEaSize,
  3347. FALSE,
  3348. NULL,
  3349. 0,
  3350. NULL,
  3351. TRUE );
  3352. if ( !NT_SUCCESS(Status) ) {
  3353. SpMemFree( eaBuffer );
  3354. IoStatusBlock.Information = 0;
  3355. }
  3356. } while ( (Status == STATUS_BUFFER_OVERFLOW) ||
  3357. (Status == STATUS_BUFFER_TOO_SMALL) );
  3358. actualEaSize = (ULONG)IoStatusBlock.Information;
  3359. if (NT_SUCCESS( Status )) {
  3360. Status = ZwSetEaFile( tempTargetHandle,
  3361. &IoStatusBlock,
  3362. eaBuffer,
  3363. actualEaSize
  3364. );
  3365. }
  3366. SpMemFree( eaBuffer );
  3367. if (! NT_SUCCESS( Status )) {
  3368. goto EndCopyEAs;
  3369. }
  3370. }
  3371. //
  3372. // Streams are only on NTFS and they're also only on files, not directories.
  3373. //
  3374. if (( RemoteSysPrepVolumeIsNtfs != TRUE ) || Directory ) {
  3375. goto EndCopyEAs;
  3376. }
  3377. do {
  3378. if (StreamInfoBase == NULL) {
  3379. StreamInfoBase = SpMemAlloc( StreamInfoSize );
  3380. }
  3381. Status = ZwQueryInformationFile(
  3382. tempSourceHandle,
  3383. &IoStatusBlock,
  3384. (PVOID) StreamInfoBase,
  3385. StreamInfoSize,
  3386. FileStreamInformation
  3387. );
  3388. if ( !NT_SUCCESS(Status) ) {
  3389. SpMemFree( StreamInfoBase );
  3390. StreamInfoBase = NULL;
  3391. StreamInfoSize *= 2;
  3392. }
  3393. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  3394. Status == STATUS_BUFFER_TOO_SMALL );
  3395. if ( NT_SUCCESS(Status) && IoStatusBlock.Information ) {
  3396. StreamInfo = StreamInfoBase;
  3397. for (;;) {
  3398. PWCHAR streamPtr;
  3399. USHORT remainingLength;
  3400. PWCHAR streamName;
  3401. //
  3402. // Build a string descriptor for the name of the stream.
  3403. //
  3404. StreamName.Buffer = &StreamInfo->StreamName[0];
  3405. StreamName.Length = (USHORT) StreamInfo->StreamNameLength;
  3406. StreamName.MaximumLength = StreamName.Length;
  3407. streamPtr = StreamName.Buffer;
  3408. if ((StreamName.Length > 0) && *streamPtr == L':') {
  3409. streamPtr++; // skip leading ":"
  3410. streamName = streamPtr; // remember start of stream name
  3411. remainingLength = StreamName.Length - sizeof(WCHAR);
  3412. while (remainingLength > 0 && *streamPtr != L':') {
  3413. streamPtr++;
  3414. remainingLength -= sizeof(WCHAR);
  3415. }
  3416. if (remainingLength > 0) {
  3417. if ((remainingLength == (sizeof(L":$DATA")-sizeof(WCHAR))) &&
  3418. (RtlCompareMemory( streamPtr, L":$DATA", remainingLength )
  3419. == remainingLength)) {
  3420. //
  3421. // the attribute type on this is of type data so we
  3422. // have a data stream here. Now check that it is not
  3423. // the unnamed primary data stream and our own acl stream
  3424. // or the short file name stream.
  3425. //
  3426. if ((*streamName != L':') &&
  3427. ((RtlCompareMemory(StreamName.Buffer,
  3428. IMIRROR_ACL_STREAM_NAME,
  3429. (sizeof(IMIRROR_ACL_STREAM_NAME)-sizeof(WCHAR)))
  3430. != (sizeof(IMIRROR_ACL_STREAM_NAME)-sizeof(WCHAR))) &&
  3431. (RtlCompareMemory(StreamName.Buffer,
  3432. IMIRROR_SFN_STREAM_NAME,
  3433. (sizeof(IMIRROR_SFN_STREAM_NAME)-sizeof(WCHAR)))
  3434. != (sizeof(IMIRROR_SFN_STREAM_NAME)-sizeof(WCHAR))))) {
  3435. //
  3436. // allocate a buffer to hold the stream data.
  3437. // Can't use TemporaryBuffer as it's used by
  3438. // SpCopyDirRecursiveCallback et al.
  3439. //
  3440. if (StreamBuffer == NULL) {
  3441. StreamBuffer = SpMemAlloc( StreamInfoSize );
  3442. }
  3443. //
  3444. // we chop off the ":DATA" suffix from the stream name
  3445. //
  3446. StreamName.Length -= remainingLength;
  3447. //
  3448. // Open the source stream.
  3449. //
  3450. InitializeObjectAttributes(
  3451. &Obja,
  3452. &StreamName,
  3453. 0,
  3454. tempSourceHandle,
  3455. NULL
  3456. );
  3457. Status = ZwCreateFile(
  3458. &StreamHandle,
  3459. GENERIC_READ | SYNCHRONIZE,
  3460. &Obja,
  3461. &IoStatusBlock,
  3462. NULL,
  3463. 0,
  3464. FILE_SHARE_READ,
  3465. FILE_OPEN,
  3466. FILE_SYNCHRONOUS_IO_NONALERT,
  3467. NULL,
  3468. 0
  3469. );
  3470. if ( ! NT_SUCCESS(Status) ) {
  3471. break;
  3472. }
  3473. //
  3474. // Open the source stream.
  3475. //
  3476. InitializeObjectAttributes(
  3477. &Obja,
  3478. &StreamName,
  3479. 0,
  3480. tempTargetHandle,
  3481. NULL
  3482. );
  3483. Status = ZwCreateFile(
  3484. &newStreamHandle,
  3485. GENERIC_WRITE,
  3486. &Obja,
  3487. &IoStatusBlock,
  3488. NULL,
  3489. 0,
  3490. FILE_SHARE_READ,
  3491. FILE_CREATE,
  3492. FILE_SYNCHRONOUS_IO_NONALERT,
  3493. NULL,
  3494. 0
  3495. );
  3496. if ( NT_SUCCESS(Status) ) {
  3497. LARGE_INTEGER byteOffset;
  3498. ULONG bytesRead;
  3499. byteOffset.QuadPart = 0;
  3500. while (NT_SUCCESS(Status)) {
  3501. Status = ZwReadFile(StreamHandle,
  3502. NULL,
  3503. NULL,
  3504. NULL,
  3505. &IoStatusBlock,
  3506. StreamBuffer,
  3507. StreamInfoSize,
  3508. &byteOffset,
  3509. NULL
  3510. );
  3511. if ( ! NT_SUCCESS(Status) ) {
  3512. if (Status == STATUS_END_OF_FILE) {
  3513. Status = STATUS_SUCCESS;
  3514. }
  3515. break;
  3516. }
  3517. bytesRead = (ULONG)IoStatusBlock.Information;
  3518. try {
  3519. Status = ZwWriteFile(newStreamHandle,
  3520. NULL,
  3521. NULL,
  3522. NULL,
  3523. &IoStatusBlock,
  3524. StreamBuffer,
  3525. bytesRead,
  3526. &byteOffset,
  3527. NULL
  3528. );
  3529. } except(EXCEPTION_EXECUTE_HANDLER) {
  3530. Status = STATUS_IN_PAGE_ERROR;
  3531. }
  3532. byteOffset.QuadPart += bytesRead;
  3533. }
  3534. ZwClose(newStreamHandle);
  3535. }
  3536. ZwClose(StreamHandle);
  3537. }
  3538. }
  3539. }
  3540. }
  3541. if ( NT_SUCCESS(Status) && StreamInfo->NextEntryOffset ) {
  3542. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  3543. } else {
  3544. break;
  3545. }
  3546. }
  3547. }
  3548. EndCopyEAs:
  3549. if (tempSourceHandle != NULL && SourceHandle == NULL) {
  3550. ZwClose( tempSourceHandle );
  3551. }
  3552. if (tempTargetHandle != NULL && TargetHandle == NULL) {
  3553. ZwClose( tempTargetHandle );
  3554. }
  3555. if (!NT_SUCCESS(Status)) {
  3556. //
  3557. // this failed. let's ask the user if he wants to retry, skip, or
  3558. // abort.
  3559. //
  3560. repaint:
  3561. SpStartScreen(
  3562. SP_SCRN_COPY_FAILED,
  3563. 3,
  3564. HEADER_HEIGHT+1,
  3565. FALSE,
  3566. FALSE,
  3567. DEFAULT_ATTRIBUTE,
  3568. TargetFile
  3569. );
  3570. SpDisplayStatusOptions(
  3571. DEFAULT_STATUS_ATTRIBUTE,
  3572. SP_STAT_ENTER_EQUALS_RETRY,
  3573. SP_STAT_ESC_EQUALS_SKIP_FILE,
  3574. SP_STAT_F3_EQUALS_EXIT,
  3575. 0
  3576. );
  3577. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  3578. case ASCI_CR: // retry
  3579. SpCopyFilesScreenRepaint(SourceFile,TargetFile,TRUE);
  3580. goto retryCopyEAs;
  3581. case ASCI_ESC: // skip file
  3582. break;
  3583. case KEY_F3: // exit setup
  3584. SpConfirmExit();
  3585. goto repaint;
  3586. }
  3587. //
  3588. // we're skipping the file, delete it if it's not a directory since
  3589. // it isn't correctly formed.
  3590. //
  3591. if ( ! Directory ) {
  3592. SpDeleteFile(TargetFile,NULL,NULL);
  3593. }
  3594. //
  3595. // Need to completely repaint gauge, etc.
  3596. //
  3597. SpCopyFilesScreenRepaint(SourceFile,TargetFile,TRUE);
  3598. }
  3599. if (StreamInfoBase != NULL) {
  3600. SpMemFree(StreamInfoBase);
  3601. }
  3602. if (StreamBuffer != NULL) {
  3603. SpMemFree(StreamBuffer);
  3604. }
  3605. return Status;
  3606. }