Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4641 lines
140 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. #if defined(_AMD64_) || defined(_X86_)
  962. if (volumeInfo->PartitionActive) {
  963. if (volumeInfo->IsBootDisk) {
  964. //
  965. // On an amd64/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 // defined(_AMD64_) || defined(_X86_)
  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)Buffer)->DataLength/sizeof(WCHAR))) ) &&
  1590. ( _wcsnicmp(L"{4D36E967-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, (((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength/sizeof(WCHAR))) ) &&
  1591. ( _wcsnicmp(L"{4D36E96A-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, (((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength/sizeof(WCHAR))) ) &&
  1592. ( _wcsnicmp(L"{4D36E96B-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, (((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength/sizeof(WCHAR))) ) &&
  1593. ( _wcsnicmp(L"{4D36E96F-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, (((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength/sizeof(WCHAR))) ) &&
  1594. ( _wcsnicmp(L"{4D36E97B-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, (((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength/sizeof(WCHAR))) ) &&
  1595. ( _wcsnicmp(L"{4D36E97D-E325-11CE-BFC1-08002BE10318}", (PWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data, (((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength/sizeof(WCHAR))) ) ) {
  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 ClassGUID 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. wcsncpy(Path2,
  1725. TemporaryBuffer,
  1726. MAX_COPY_SIZE(Path2));
  1727. Path2[MAX_COPY_SIZE(Path2)] = L'\0';
  1728. //
  1729. // Copy the driver from the server
  1730. //
  1731. Status = SpCopyFileUsingNames(SrvPath,
  1732. Path2,
  1733. 0,
  1734. COPY_ONLY_IF_NOT_PRESENT | COPY_DECOMPRESS_SYSPREP
  1735. );
  1736. if (!NT_SUCCESS(Status)) {
  1737. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpCopyFilesUsingNames for %ws failed %lx\n", Path2, Status));
  1738. continue;
  1739. }
  1740. wcscpy( ImageName, L"Files." );
  1741. wcscat( ImageName, Path );
  1742. CopyListEmpty = FALSE;
  1743. // copy the rest of the files for this service by looking up the
  1744. // appropriate section in txtsetup.inf
  1745. SpAddSectionFilesToCopyList(
  1746. SetupSifHandle,
  1747. DiskFileLists,
  1748. DiskCount,
  1749. ImageName, // this is now L"Files.Path"
  1750. pVolumePath, // L"\\Device\\Harddisk0\\Partition1"
  1751. NULL, // it should look up the target directory
  1752. COPY_ONLY_IF_NOT_PRESENT,
  1753. TRUE, // force nocompression, we don't know what type of driver it is.
  1754. FALSE);
  1755. //
  1756. // Now duplicate the services key
  1757. //
  1758. Status = SppCopyKeyRecursive(TmpHandle,
  1759. TmpHandle2,
  1760. Path,
  1761. Path,
  1762. TRUE, // CopyAlways
  1763. FALSE // ApplyACLsAlways
  1764. );
  1765. if (!NT_SUCCESS(Status)) {
  1766. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive for %ws failed %lx\n", Path, Status));
  1767. continue;
  1768. }
  1769. //
  1770. // Set the start type to 0
  1771. //
  1772. Size = 0;
  1773. Status = SpOpenSetValueAndClose(TmpHandle2,
  1774. Path,
  1775. L"Start",
  1776. REG_DWORD,
  1777. &Size,
  1778. sizeof(ULONG)
  1779. );
  1780. if (!NT_SUCCESS(Status)) {
  1781. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpOpenSetValueAndClose for %ws Start failed %lx\n", Path, Status));
  1782. continue;
  1783. }
  1784. //
  1785. // Set the image path to one with system32\drivers on the front. We do this by
  1786. // moving backwards thru the target path we have already built to the 3rd backslash
  1787. // from the end.
  1788. //
  1789. Tmp = &(Path2[wcslen(Path2)]);
  1790. for (Size = 0; Size < 3; Size++) {
  1791. while (*Tmp != L'\\') {
  1792. Tmp--;
  1793. }
  1794. Tmp--;
  1795. }
  1796. Tmp += 2;
  1797. Status = SpOpenSetValueAndClose(TmpHandle2,
  1798. Path,
  1799. L"ImagePath",
  1800. REG_EXPAND_SZ,
  1801. Tmp,
  1802. (wcslen(Tmp) + 1) * sizeof(WCHAR)
  1803. );
  1804. ZwClose(TmpHandle);
  1805. ZwClose(TmpHandle2);
  1806. TmpHandle = NULL;
  1807. TmpHandle2 = NULL;
  1808. if (!NT_SUCCESS(Status)) {
  1809. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SpOpenSetValueAndClose for %ws ImagePath failed %lx\n", Path, Status));
  1810. continue;
  1811. }
  1812. }
  1813. //
  1814. // Copy over the NIC files, including the INF file.
  1815. //
  1816. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1817. wcscpy(Path, L"\\??\\");
  1818. SpConcatenatePaths(Path, Tmp);
  1819. Status = SpCopyNicFiles(SysPrepDriversDevice, Path);
  1820. //
  1821. // Get the HAL and just always copy it over.
  1822. //
  1823. //
  1824. // Now test for mp/up and then replace dependent drivers as necessary.
  1825. //
  1826. //
  1827. // Migrate the MountedDevices and DISK registry information.
  1828. //
  1829. ZwClose(SrcHandle);
  1830. SrcHandle = NULL;
  1831. ZwClose(DstHandle);
  1832. DstHandle = NULL;
  1833. //
  1834. // Open the system hive of the current build.
  1835. //
  1836. INIT_OBJA(&Obj, &UnicodeString2, L"\\Registry\\Machine\\SYSTEM");
  1837. Status = ZwOpenKey(&SrcHandle, KEY_READ, &Obj);
  1838. if (!NT_SUCCESS(Status)) {
  1839. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey for local SYSTEM failed %lx\n", Status));
  1840. goto CleanUp;
  1841. }
  1842. //
  1843. // Open the system hive of the build we are patching.
  1844. //
  1845. INIT_OBJA(&Obj, &UnicodeString2, L"\\Registry\\SysPrepReg");
  1846. Status = ZwOpenKey(&DstHandle, KEY_READ | KEY_WRITE, &Obj);
  1847. if (!NT_SUCCESS(Status)) {
  1848. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey for SysPrepReg SYSTEM failed %lx\n", Status));
  1849. goto CleanUp;
  1850. }
  1851. //
  1852. // Delete the existing subkeys of the MountedDevices key.
  1853. //
  1854. Status = SppDeleteKeyRecursive(DstHandle,
  1855. L"MountedDevices",
  1856. TRUE); // ThisKeyToo
  1857. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1858. Status = STATUS_SUCCESS;
  1859. }
  1860. if (!NT_SUCCESS(Status)) {
  1861. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppDeleteKeyRecursive of MountedDevices failed %lx\n", Status));
  1862. goto CleanUp;
  1863. }
  1864. //
  1865. // Copy the MountedDevices key over.
  1866. //
  1867. Status = SppCopyKeyRecursive(SrcHandle,
  1868. DstHandle,
  1869. L"MountedDevices",
  1870. L"MountedDevices",
  1871. TRUE, // CopyAlways
  1872. TRUE); // ApplyACLsAlways
  1873. if (!NT_SUCCESS(Status)) {
  1874. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive of MountedDevices failed %lx\n", Status));
  1875. goto CleanUp;
  1876. }
  1877. //
  1878. // Delete the existing subkeys of the DISK key. This routine returns
  1879. // STATUS_OBJECT_NAME_NOT_FOUND if the key does not exist, which is
  1880. // not an error in this case.
  1881. //
  1882. Status = SppDeleteKeyRecursive(DstHandle,
  1883. L"DISK",
  1884. TRUE); // ThisKeyToo
  1885. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1886. Status = STATUS_SUCCESS;
  1887. }
  1888. if (!NT_SUCCESS(Status)) {
  1889. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppDeleteKeyRecursive of DISK failed %lx\n", Status));
  1890. goto CleanUp;
  1891. }
  1892. //
  1893. // Copy the DISK key over.
  1894. //
  1895. Status = SppCopyKeyRecursive(SrcHandle,
  1896. DstHandle,
  1897. L"DISK",
  1898. L"DISK",
  1899. TRUE, // CopyAlways
  1900. TRUE); // ApplyACLsAlways
  1901. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1902. Status = STATUS_SUCCESS;
  1903. }
  1904. if (!NT_SUCCESS(Status)) {
  1905. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: SppCopyKeyRecursive of DISK failed %lx\n", Status));
  1906. Status = STATUS_SUCCESS;
  1907. goto CleanUp;
  1908. }
  1909. //
  1910. // Delete those subkeys of the CCS\Enum\STORAGE\Volume key that
  1911. // represent volumes that were never fully installed. This eliminates
  1912. // stale information about volumes that may not exist on this computer.
  1913. //
  1914. SpDeleteStorageVolumes( DstHandle, Number );
  1915. CleanUp:
  1916. if (!CopyListEmpty) {
  1917. //
  1918. // Copy files in the copy list.
  1919. //
  1920. WCHAR emptyString = L'\0';
  1921. PWCHAR lastComponent;
  1922. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1923. if (*Tmp != L'\0' && *(Tmp+1) == L':') {
  1924. Tmp += 2; // have it skip L"C:" at front of path
  1925. wcscpy(Path2, Tmp);
  1926. } else {
  1927. wcscpy(Path2, L"\\??\\");
  1928. SpConcatenatePaths(Path2, Tmp);
  1929. }
  1930. //
  1931. // first we need to remove the L"\i386" off the end of the source
  1932. // path since SpCopyFilesInCopyList or decendent will tack it on.
  1933. //
  1934. // divide up the source path into two parts so that SpConcatenatePaths
  1935. // does the right thing when it puts it back together.
  1936. //
  1937. wcscpy( SrvPath, SysPrepDriversDevice );
  1938. lastComponent = SrvPath + wcslen( SrvPath ) - 1;
  1939. while (lastComponent > SrvPath && *lastComponent != L'\\') {
  1940. lastComponent--;
  1941. }
  1942. if (lastComponent > SrvPath) {
  1943. *lastComponent = L'\0'; // this removes the architecture off the end
  1944. // now move backwards until we find the start of the last component
  1945. while (lastComponent > SrvPath && *lastComponent != L'\\') {
  1946. lastComponent--;
  1947. }
  1948. if (lastComponent > SrvPath) {
  1949. *lastComponent = L'\0';
  1950. lastComponent++;
  1951. } else {
  1952. lastComponent = &emptyString;
  1953. }
  1954. } else {
  1955. lastComponent = &emptyString;
  1956. }
  1957. SpCopyFilesInCopyList(
  1958. SetupSifHandle,
  1959. DiskFileLists,
  1960. DiskCount,
  1961. SrvPath, // L"\\device\\harddisk0\\partition1"
  1962. lastComponent, // L"\\$win_nt$.~ls"
  1963. Path2, // L"\\WINNT"
  1964. NULL
  1965. );
  1966. }
  1967. if (HaveCopyList) {
  1968. SpFreeCopyLists(&DiskFileLists,DiskCount);
  1969. }
  1970. if (SrcHandle != NULL) {
  1971. ZwClose(SrcHandle);
  1972. }
  1973. if (DstHandle != NULL) {
  1974. ZwClose(DstHandle);
  1975. }
  1976. if (TmpHandle != NULL) {
  1977. ZwClose(TmpHandle);
  1978. }
  1979. if (TmpHandle2 != NULL) {
  1980. ZwClose(TmpHandle2);
  1981. }
  1982. if (NeedToUnload) {
  1983. ZwUnloadKey(&DstObj);
  1984. NeedToUnload = FALSE;
  1985. }
  1986. if (pVolumePath != NULL) {
  1987. SpMemFree( pVolumePath );
  1988. }
  1989. //
  1990. // update the NT source path in the software section of the registry
  1991. // since we have a valid SysPrepDriversDevice
  1992. //
  1993. if (SysPrepDriversDevice && *SysPrepDriversDevice != L'\0') {
  1994. //
  1995. // Now load the local version of the SysPrep hives, using IMirror.Dat to find them
  1996. // NOTE: DstObj is assumed by CleanUp to still be the key.
  1997. //
  1998. Tmp = (PWCHAR)(((PUCHAR)pFileData) + pFileData->SystemPathOffset);
  1999. wcscpy(Path, L"\\??\\");
  2000. wcscat(Path, Tmp);
  2001. wcscat(Path, L"\\System32\\Config\\Software");
  2002. INIT_OBJA(&DstObj, &UnicodeString1, L"\\Registry\\SysPrepReg");
  2003. INIT_OBJA(&Obj, &UnicodeString2, Path);
  2004. Status = ZwLoadKey(&DstObj, &Obj);
  2005. if (NT_SUCCESS(Status)) {
  2006. NeedToUnload = TRUE;
  2007. //
  2008. // Open the system hive of the build we are patching.
  2009. //
  2010. INIT_OBJA(&Obj, &UnicodeString2, L"\\Registry\\SysPrepReg\\Microsoft\\Windows\\CurrentVersion\\Setup");
  2011. Status = ZwOpenKey(&DstHandle, KEY_READ | KEY_WRITE, &Obj);
  2012. if (NT_SUCCESS(Status)) {
  2013. BOOLEAN haveDecentString = FALSE;
  2014. //
  2015. // the path is of the form
  2016. // \device\lanmanredirector\server\share\..\flat\i386
  2017. // when we want it of the form \\server\share\..\flat
  2018. //
  2019. Tmp = SysPrepDriversDevice + 1;
  2020. while (*Tmp != L'\0' && *Tmp != L'\\') {
  2021. Tmp++;
  2022. }
  2023. if (*Tmp == L'\\') {
  2024. Tmp++;
  2025. while (*Tmp != L'\0' && *Tmp != L'\\') {
  2026. Tmp++;
  2027. }
  2028. if (*Tmp == L'\\') { // back up one before the \server\share
  2029. // so we can put another \ on it
  2030. Tmp--;
  2031. wcscpy( Path, Tmp );
  2032. Tmp = Path;
  2033. *Tmp = L'\\'; // we now have \\server\share\..\flat\i386
  2034. Tmp = Path + wcslen(Path);
  2035. while (Tmp > Path && *Tmp != L'\\') {
  2036. Tmp--;
  2037. }
  2038. if (Tmp > Path) {
  2039. *Tmp = L'\0'; // remove the \i386
  2040. haveDecentString = TRUE;
  2041. }
  2042. }
  2043. }
  2044. if (haveDecentString) {
  2045. INIT_OBJA(&Obj, &UnicodeString2, L"SourcePath");
  2046. Status = ZwSetValueKey (DstHandle,
  2047. &UnicodeString2,
  2048. 0,
  2049. REG_SZ,
  2050. Path,
  2051. (wcslen(Path) + 1 ) * sizeof(WCHAR));
  2052. if (!NT_SUCCESS(Status)) {
  2053. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Setting SourcePath to %ws failed with 0x%x\n", Path, Status));
  2054. }
  2055. } else {
  2056. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: Couldn't set SourcePath to %ws\n", SysPrepDriversDevice));
  2057. Status = STATUS_OBJECT_PATH_INVALID;
  2058. }
  2059. ZwClose(DstHandle);
  2060. DstHandle = NULL;
  2061. } else {
  2062. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwOpenKey for SysPrepReg SOFTWARE failed %lx\n", Status));
  2063. }
  2064. } else {
  2065. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpPatchSysPrepImage: ZwLoadKey to SysPrepReg failed %lx\n", Status));
  2066. }
  2067. }
  2068. //
  2069. // patch boot.ini regardless of the status of the patching of everything
  2070. // else. if we don't patch boot.ini, the whole image has no hope of
  2071. // booting.
  2072. //
  2073. #if defined(_AMD64_) || defined(_X86_)
  2074. //
  2075. // Patch boot.ini if the ARC names have changed. Boot.ini will
  2076. // be on the active partition of disk 0.
  2077. //
  2078. for (volume = 0; volume < pMemoryData->NumberVolumes; volume++) {
  2079. volumeInfo = &pMemoryData->Volumes[volume];
  2080. if ((volumeInfo->DiskNumber == 0) &&
  2081. (volumeInfo->PartitionActive)) {
  2082. ULONG tmpLen;
  2083. wcscpy(Path, L"\\??\\");
  2084. tmpLen = wcslen(Path);
  2085. Path[tmpLen] = volumeInfo->DriveLetter;
  2086. Path[tmpLen+1] = L'\0';
  2087. wcscat(Path, L":\\boot.ini");
  2088. SpPatchBootIni(Path, pMemoryData);
  2089. break;
  2090. }
  2091. }
  2092. #endif // defined(_AMD64_) || defined(_X86_)
  2093. if (NeedToUnload) {
  2094. ZwUnloadKey(&DstObj);
  2095. }
  2096. if (Buffer != NULL) {
  2097. SpMemFree(Buffer);
  2098. }
  2099. return Status;
  2100. }
  2101. VOID
  2102. SpReplaceArcName(
  2103. IN PUCHAR CurrentArcName,
  2104. IN PMIRROR_CFG_INFO_MEMORY pMemoryData,
  2105. OUT PBOOLEAN Replaced
  2106. )
  2107. /*++
  2108. Routine Description:
  2109. This routine looks in pMemoryData to see if there is a partition
  2110. whose OriginalArcName is equal to CurrentArcName, and if so it
  2111. replaces CurrentArcName, adjusting the rest of the string that
  2112. follows CurrentArcName if needed.
  2113. Arguments:
  2114. CurrentArcName - The ARC name to check.
  2115. pMemoryData - A pointer to an in-memory copy of IMirror.Dat, modified to
  2116. match the specs of this computer (disk sizes etc).
  2117. Replaced - Returns TRUE if the name is replaced.
  2118. Return Value:
  2119. The NTSTATUS of the operation.
  2120. --*/
  2121. {
  2122. ULONG volume;
  2123. PMIRROR_VOLUME_INFO_MEMORY volumeInfo;
  2124. ULONG originalArcNameLength, newArcNameLength;
  2125. CHAR TmpArcName[128];
  2126. //
  2127. // Scan pMemoryData to see if any ARC names match.
  2128. //
  2129. *Replaced = FALSE;
  2130. for (volume = 0; volume < pMemoryData->NumberVolumes; volume++) {
  2131. volumeInfo = &pMemoryData->Volumes[volume];
  2132. originalArcNameLength = wcslen(volumeInfo->OriginalArcName);
  2133. wcstombs(TmpArcName, volumeInfo->OriginalArcName, originalArcNameLength+1);
  2134. if (RtlCompareMemory(TmpArcName, CurrentArcName, originalArcNameLength) == originalArcNameLength) {
  2135. //
  2136. // This is the partition that CurrentArcName refers to,
  2137. // see what the ARC name is now.
  2138. //
  2139. SpArcNameFromRegion(
  2140. volumeInfo->CreatedRegion,
  2141. TemporaryBuffer,
  2142. sizeof(TemporaryBuffer),
  2143. PartitionOrdinalOnDisk,
  2144. PrimaryArcPath);
  2145. //
  2146. // If we got an ARC name and it is different from what it was on
  2147. // the old machine, we need to replace.
  2148. //
  2149. if (*TemporaryBuffer &&
  2150. (wcscmp(volumeInfo->OriginalArcName, TemporaryBuffer) != 0)) {
  2151. //
  2152. // See if we need to adjust the buffer because the length
  2153. // of the ARC names is different.
  2154. //
  2155. newArcNameLength = wcslen(TemporaryBuffer);
  2156. if (newArcNameLength != originalArcNameLength) {
  2157. memmove(
  2158. CurrentArcName+newArcNameLength,
  2159. CurrentArcName+originalArcNameLength,
  2160. strlen(CurrentArcName+originalArcNameLength) + 1);
  2161. }
  2162. //
  2163. // Copy over the new ARC name.
  2164. //
  2165. wcstombs(TmpArcName, TemporaryBuffer, newArcNameLength);
  2166. memcpy(CurrentArcName, TmpArcName, newArcNameLength);
  2167. *Replaced = TRUE;
  2168. break; // no need to look at any other volumeInfo's.
  2169. }
  2170. }
  2171. }
  2172. }
  2173. NTSTATUS
  2174. SpPatchBootIni(
  2175. IN PWCHAR BootIniPath,
  2176. IN PMIRROR_CFG_INFO_MEMORY pMemoryData
  2177. )
  2178. /*++
  2179. Routine Description:
  2180. This routine modifies boot.ini to modify any ARC names that have
  2181. changed.
  2182. Arguments:
  2183. BootIniPath - The path to the local boot.ini.
  2184. pMemoryData - A pointer to an in-memory copy of IMirror.Dat, modified to
  2185. match the specs of this computer (disk sizes etc).
  2186. Return Value:
  2187. The NTSTATUS of the operation.
  2188. --*/
  2189. {
  2190. ULONG ulLen;
  2191. NTSTATUS Status = STATUS_SUCCESS;
  2192. UNICODE_STRING UnicodeString;
  2193. OBJECT_ATTRIBUTES Obja;
  2194. IO_STATUS_BLOCK IoStatusBlock;
  2195. HANDLE Handle;
  2196. PCHAR pFileData = NULL, pNewFileData = NULL;
  2197. PCHAR curLoc, endOfLine;
  2198. BOOLEAN changedFile = FALSE;
  2199. PWCHAR TmpBootIni = NULL;
  2200. //
  2201. // Read in the current boot.ini.
  2202. //
  2203. INIT_OBJA(&Obja, &UnicodeString, BootIniPath);
  2204. Status = ZwCreateFile(&Handle,
  2205. FILE_GENERIC_READ,
  2206. &Obja,
  2207. &IoStatusBlock,
  2208. NULL,
  2209. FILE_ATTRIBUTE_NORMAL,
  2210. FILE_SHARE_READ,
  2211. FILE_OPEN,
  2212. FILE_SYNCHRONOUS_IO_NONALERT,
  2213. NULL,
  2214. 0
  2215. );
  2216. if(!NT_SUCCESS(Status)) {
  2217. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not open %ws: %lx\n", BootIniPath, Status));
  2218. goto Cleanup;
  2219. }
  2220. Status = SpGetFileSize(Handle, &ulLen);
  2221. if(!NT_SUCCESS(Status)) {
  2222. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not SpGetFileSize: %lx\n", Status));
  2223. ZwClose(Handle);
  2224. goto Cleanup;
  2225. }
  2226. //
  2227. // Allocate memory and read in the file.
  2228. //
  2229. pFileData = SpMemAlloc(ulLen);
  2230. Status = ZwReadFile(Handle,
  2231. NULL,
  2232. NULL,
  2233. NULL,
  2234. &IoStatusBlock,
  2235. pFileData,
  2236. ulLen,
  2237. 0,
  2238. NULL
  2239. );
  2240. ZwClose(Handle);
  2241. if(!NT_SUCCESS(Status)) {
  2242. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not ZwReadFile: %lx\n", Status));
  2243. goto Cleanup;
  2244. }
  2245. //
  2246. // Allocate memory for the new copy of the file (we use twice the
  2247. // current size as a worst-case scenario).
  2248. //
  2249. pNewFileData = SpMemAlloc(ulLen * 2);
  2250. memcpy(pNewFileData, pFileData, ulLen);
  2251. pNewFileData[ulLen] = '\0'; // NULL-terminate to make replace easier.
  2252. //
  2253. // Run through each line of the file, looking for ARC names to
  2254. // replace. ARC names are either after the "default=" text or
  2255. // else they start a line.
  2256. //
  2257. curLoc = pNewFileData;
  2258. while (TRUE) {
  2259. BOOLEAN replaced = FALSE;
  2260. LONG adjustment;
  2261. //
  2262. // Replace if this is a "default=" line, or a line that does not
  2263. // start with "timeout=" or a '['.
  2264. //
  2265. if (RtlCompareMemory(curLoc, "default=", strlen("default=")) == strlen("default=")) {
  2266. SpReplaceArcName(curLoc + strlen("default="), pMemoryData, &replaced);
  2267. } else if ((*curLoc != '[') &&
  2268. (RtlCompareMemory(curLoc, "timeout=", strlen("timeout=")) != strlen("timeout="))) {
  2269. SpReplaceArcName(curLoc, pMemoryData, &replaced);
  2270. }
  2271. if (replaced) {
  2272. changedFile = TRUE;
  2273. }
  2274. //
  2275. // Look for a '\n' in the file.
  2276. //
  2277. endOfLine = strchr(curLoc, '\n');
  2278. if (endOfLine == NULL) {
  2279. break;
  2280. }
  2281. curLoc = endOfLine + 1;
  2282. if (*curLoc == L'\0') {
  2283. break;
  2284. }
  2285. }
  2286. //
  2287. // If we changed the file, write out the new one.
  2288. //
  2289. if (changedFile) {
  2290. //
  2291. // Replace the old boot.ini with the new one.
  2292. //
  2293. TmpBootIni = SpDupStringW(BootIniPath);
  2294. if (!TmpBootIni) {
  2295. goto Cleanup;
  2296. }
  2297. TmpBootIni[wcslen(TmpBootIni)-1] = L'$'; // make it boot.in$
  2298. INIT_OBJA(&Obja, &UnicodeString, TmpBootIni);
  2299. Status = ZwCreateFile(&Handle,
  2300. FILE_GENERIC_WRITE,
  2301. &Obja,
  2302. &IoStatusBlock,
  2303. NULL,
  2304. FILE_ATTRIBUTE_NORMAL,
  2305. 0, // no sharing
  2306. FILE_OVERWRITE_IF,
  2307. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_WRITE_THROUGH,
  2308. NULL,
  2309. 0
  2310. );
  2311. if(!NT_SUCCESS(Status)) {
  2312. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not create %ws: %lx\n", TmpBootIni, Status));
  2313. goto Cleanup;
  2314. }
  2315. Status = ZwWriteFile(Handle,
  2316. NULL,
  2317. NULL,
  2318. NULL,
  2319. &IoStatusBlock,
  2320. pNewFileData,
  2321. strlen(pNewFileData),
  2322. NULL,
  2323. NULL
  2324. );
  2325. ZwClose(Handle);
  2326. if(!NT_SUCCESS(Status)) {
  2327. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not ZwWriteFile: %lx\n", Status));
  2328. goto Cleanup;
  2329. }
  2330. //
  2331. // Now that we have written the tmp file, do the swap.
  2332. //
  2333. Status = SpDeleteFile(BootIniPath, NULL, NULL);
  2334. if(!NT_SUCCESS(Status)) {
  2335. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not SpDeleteFile(%ws): %lx\n", BootIniPath, Status));
  2336. goto Cleanup;
  2337. }
  2338. Status = SpRenameFile(TmpBootIni, BootIniPath, FALSE);
  2339. if(!NT_SUCCESS(Status)) {
  2340. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPatchBootIni could not SpRenameFile(%ws,%ws): %lx\n", TmpBootIni, BootIniPath, Status));
  2341. goto Cleanup;
  2342. }
  2343. }
  2344. Cleanup:
  2345. if (pFileData != NULL) {
  2346. SpMemFree(pFileData);
  2347. }
  2348. if (pNewFileData != NULL) {
  2349. SpMemFree(pNewFileData);
  2350. }
  2351. if (TmpBootIni != NULL) {
  2352. SpMemFree(TmpBootIni);
  2353. }
  2354. return Status;
  2355. }
  2356. NTSTATUS
  2357. SpCopyNicFiles(
  2358. IN PWCHAR SetupPath,
  2359. IN PWCHAR DestPath
  2360. )
  2361. /*++
  2362. Routine Description:
  2363. This routine packages up information and sends it to the BINL server, getting back
  2364. a list of files to copy to support the given NIC. It then copies those files.
  2365. Arguments:
  2366. SetupPath - Setup path that supports the SysPrep image.
  2367. DestPath - Path to the winnt directory.
  2368. Return Value:
  2369. The NTSTATUS of the operation.
  2370. --*/
  2371. {
  2372. PSPUDP_PACKET pUdpPacket = NULL;
  2373. WCHAR UNALIGNED * pPacketEnd;
  2374. PSP_NETCARD_INFO_REQ pReqPacket;
  2375. PSP_NETCARD_INFO_RSP pRspPacket;
  2376. ULONG PacketSize;
  2377. NTSTATUS Status = STATUS_SUCCESS;
  2378. ULONG i,j;
  2379. PWCHAR pSrc, pDst, pTmp;
  2380. WCHAR SrcFqn[MAX_PATH];
  2381. WCHAR DstFqn[MAX_PATH];
  2382. //
  2383. // BINL expects the path to be a UNC w/o the architecture type, so take the current
  2384. // setup path, in the form of "\device\lanmanredirector\server\share\...\i386" and
  2385. // make it "\\server\share\..."
  2386. //
  2387. // First remove the architecture type, and the the leading stuff.
  2388. //
  2389. wcscpy(SrcFqn, SetupPath);
  2390. pTmp = &(SrcFqn[wcslen(SrcFqn)]);
  2391. while ((*pTmp != L'\\') && (pTmp != SrcFqn)) {
  2392. pTmp--;
  2393. }
  2394. if (*pTmp == L'\\') {
  2395. *pTmp = UNICODE_NULL;
  2396. }
  2397. pTmp = SrcFqn;
  2398. pTmp++;
  2399. while ((*pTmp != UNICODE_NULL) && (*pTmp != L'\\')) {
  2400. pTmp++;
  2401. }
  2402. if (*pTmp == L'\\') {
  2403. pTmp++;
  2404. }
  2405. while ((*pTmp != UNICODE_NULL) && (*pTmp != L'\\')) {
  2406. pTmp++;
  2407. }
  2408. if (*pTmp == L'\\') {
  2409. pTmp--;
  2410. *pTmp = L'\\';
  2411. }
  2412. //
  2413. // Allocate the packet
  2414. //
  2415. PacketSize = FIELD_OFFSET(SPUDP_PACKET, Data[0]) +
  2416. FIELD_OFFSET(SP_NETCARD_INFO_REQ, SetupPath[0]) +
  2417. (wcslen(pTmp) + 1) * sizeof(WCHAR);
  2418. pUdpPacket = (PSPUDP_PACKET)SpMemAllocNonPagedPool(PacketSize);
  2419. //
  2420. // Fill in the packet
  2421. //
  2422. RtlCopyMemory(&(pUdpPacket->Signature[0]), SetupRequestSignature, 4);
  2423. pUdpPacket->Length = PacketSize - FIELD_OFFSET(SPUDP_PACKET, RequestType);
  2424. pUdpPacket->RequestType = 0;
  2425. pUdpPacket->Status = STATUS_SUCCESS;
  2426. pUdpPacket->SequenceNumber = 1;
  2427. pUdpPacket->FragmentNumber = 1;
  2428. pUdpPacket->FragmentTotal = 1;
  2429. pReqPacket = (PSP_NETCARD_INFO_REQ)(&(pUdpPacket->Data[0]));
  2430. pReqPacket->Version = OSCPKT_NETCARD_REQUEST_VERSION;
  2431. RtlCopyMemory(&(pReqPacket->CardInfo), &RemoteSysPrepNetCardInfo, sizeof(NET_CARD_INFO));
  2432. wcscpy(&(pReqPacket->SetupPath[0]), pTmp);
  2433. #if defined(_AMD64_)
  2434. pReqPacket->Architecture = PROCESSOR_ARCHITECTURE_AMD64;
  2435. #elif defined(_IA64_)
  2436. pReqPacket->Architecture = PROCESSOR_ARCHITECTURE_IA64;
  2437. #elif defined(_X86_)
  2438. pReqPacket->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
  2439. #else
  2440. #error "No Target Architecture"
  2441. #endif
  2442. //
  2443. // Open the Udp stack
  2444. //
  2445. Status = SpUdpConnect();
  2446. if (!NT_SUCCESS(Status)) {
  2447. goto CleanUp;
  2448. }
  2449. //
  2450. // Send the request
  2451. //
  2452. Status = SpUdpSendAndReceiveDatagram(pUdpPacket,
  2453. PacketSize,
  2454. RemoteServerIpAddress,
  2455. BINL_DEFAULT_PORT,
  2456. SpSysPrepNicRcvFunc
  2457. );
  2458. SpUdpDisconnect();
  2459. if (!NT_SUCCESS(Status)) {
  2460. goto CleanUp;
  2461. }
  2462. //
  2463. // Get the received packet
  2464. //
  2465. SpMemFree(pUdpPacket);
  2466. pUdpPacket = (PSPUDP_PACKET)pGlobalResponsePacket;
  2467. Status = pUdpPacket->Status;
  2468. if (!NT_SUCCESS(Status)) {
  2469. goto CleanUp;
  2470. }
  2471. if (GlobalResponsePacketLength <
  2472. (ULONG)(FIELD_OFFSET(SPUDP_PACKET, Data[0]) + FIELD_OFFSET(SP_NETCARD_INFO_RSP, MultiSzFiles[0]))) {
  2473. Status = STATUS_INVALID_PARAMETER;
  2474. goto CleanUp;
  2475. }
  2476. pRspPacket = (PSP_NETCARD_INFO_RSP)(&(pUdpPacket->Data[0]));
  2477. pPacketEnd = (WCHAR UNALIGNED *)(((PUCHAR)pGlobalResponsePacket) + GlobalResponsePacketLength);
  2478. //
  2479. // Now copy each file
  2480. //
  2481. pTmp = &(pRspPacket->MultiSzFiles[0]);
  2482. for (i = 0; i < pRspPacket->cFiles;) {
  2483. i++;
  2484. if (pTmp >= pPacketEnd) {
  2485. Status = STATUS_INVALID_PARAMETER;
  2486. goto CleanUp;
  2487. }
  2488. //
  2489. // Be careful about reading this data, since it's come in over the
  2490. // network. ie., make sure that the string length is reasonable
  2491. // before proceeding with processing the string.
  2492. //
  2493. pSrc = pTmp;
  2494. try {
  2495. j = wcslen(pSrc);
  2496. } except(EXCEPTION_EXECUTE_HANDLER) {
  2497. j = sizeof(SrcFqn)/sizeof(WCHAR) + 1;
  2498. }
  2499. if (j + wcslen(SetupPath) + 1 > sizeof(SrcFqn)/sizeof(WCHAR)) {
  2500. Status = STATUS_INVALID_PARAMETER;
  2501. goto CleanUp;
  2502. }
  2503. pDst = pTmp = pSrc + j + 1;
  2504. if (pTmp >= pPacketEnd) {
  2505. Status = STATUS_INVALID_PARAMETER;
  2506. goto CleanUp;
  2507. }
  2508. wcscpy(SrcFqn, SetupPath);
  2509. SpConcatenatePaths(SrcFqn, pSrc);
  2510. wcscpy(DstFqn, DestPath);
  2511. if (i == pRspPacket->cFiles) { // the last file in the list is the INF
  2512. SpConcatenatePaths(DstFqn, L"inf");
  2513. } else { // all the others go in system32\drivers
  2514. SpConcatenatePaths(DstFqn, L"system32\\drivers");
  2515. }
  2516. if (*pDst != UNICODE_NULL) {
  2517. try {
  2518. j = wcslen(pDst);
  2519. } except(EXCEPTION_EXECUTE_HANDLER) {
  2520. j = sizeof(DstFqn)/sizeof(WCHAR) + 1;
  2521. }
  2522. if (j+wcslen(DstFqn)+1 > sizeof(DstFqn)/sizeof(WCHAR)) {
  2523. Status = STATUS_INVALID_PARAMETER;
  2524. goto CleanUp;
  2525. }
  2526. pTmp = pDst + j + 1;
  2527. if (pTmp >= pPacketEnd) {
  2528. Status = STATUS_INVALID_PARAMETER;
  2529. goto CleanUp;
  2530. }
  2531. SpConcatenatePaths(DstFqn, pDst);
  2532. } else {
  2533. SpConcatenatePaths(DstFqn, pSrc);
  2534. pTmp = pDst + 1;
  2535. }
  2536. Status = SpCopyFileUsingNames(SrcFqn, DstFqn, 0, COPY_DECOMPRESS_SYSPREP );
  2537. if (!NT_SUCCESS(Status)) {
  2538. goto CleanUp;
  2539. }
  2540. }
  2541. CleanUp:
  2542. if (pUdpPacket != NULL) {
  2543. SpMemFree(pUdpPacket);
  2544. }
  2545. return Status;
  2546. }
  2547. NTSTATUS
  2548. SpSysPrepNicRcvFunc(
  2549. PVOID DataBuffer,
  2550. ULONG DataBufferLength
  2551. )
  2552. /*++
  2553. Routine Description:
  2554. This routine receives datagrams from the server into the global variable
  2555. pGlobalResponsePacket, iff it is NULL, otherwise it is presumed to hold data
  2556. and the incoming packet is assumed to be a duplicate response packet.
  2557. NOTE: spudp.c guarantees singly-threaded callbacks, so we don't have to spin lock
  2558. here.
  2559. Arguments:
  2560. DataBuffer - The incoming data.
  2561. DataBufferLength - Length of the data in bytes.
  2562. Return Value:
  2563. The NTSTATUS of the operation.
  2564. --*/
  2565. {
  2566. PSPUDP_PACKET pUdpPacket;
  2567. WCHAR UNALIGNED * pPacketEnd;
  2568. if ((pGlobalResponsePacket != NULL) || (DataBufferLength == 0)) {
  2569. return STATUS_UNSUCCESSFUL;
  2570. }
  2571. pUdpPacket = (PSPUDP_PACKET)DataBuffer;
  2572. if (RtlCompareMemory(&(pUdpPacket->Signature[0]), SetupResponseSignature, 4) != 4) {
  2573. return STATUS_UNSUCCESSFUL;
  2574. }
  2575. pGlobalResponsePacket = SpMemAlloc(DataBufferLength + sizeof(WCHAR));
  2576. RtlCopyMemory(pGlobalResponsePacket, DataBuffer, DataBufferLength);
  2577. pPacketEnd = (WCHAR UNALIGNED *)(((PUCHAR)pGlobalResponsePacket) + DataBufferLength);
  2578. *pPacketEnd = L'\0'; // NULL-terminate it
  2579. GlobalResponsePacketLength = DataBufferLength;
  2580. return STATUS_SUCCESS;
  2581. }
  2582. VOID
  2583. SpSysPrepFailure(
  2584. ULONG ReasonNumber,
  2585. PVOID Parameter1,
  2586. PVOID Parameter2
  2587. )
  2588. /*++
  2589. Routine Description:
  2590. Inform the user that we were unable to bring down the sysprep image
  2591. correctly.
  2592. This is a fatal condition.
  2593. Arguments:
  2594. None.
  2595. Return Value:
  2596. Does not return.
  2597. --*/
  2598. {
  2599. ULONG ValidKeys[2] = { KEY_F3, 0 };
  2600. PWCHAR MessageText = NULL;
  2601. WCHAR blankMessage[1];
  2602. if (ReasonNumber > 0) {
  2603. // Get the message text.
  2604. //
  2605. if (Parameter1 == NULL) {
  2606. MessageText = SpRetreiveMessageText(NULL,ReasonNumber,NULL,0);
  2607. } else {
  2608. SpFormatMessage( TemporaryBuffer,
  2609. sizeof(TemporaryBuffer),
  2610. ReasonNumber,
  2611. Parameter1,
  2612. Parameter2
  2613. );
  2614. MessageText = SpDupStringW(TemporaryBuffer);
  2615. }
  2616. if (MessageText == NULL) {
  2617. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpSysPrepFailure: SpRetreiveMessageText %u returned NULL\n",ReasonNumber));
  2618. }
  2619. }
  2620. if (MessageText == NULL) {
  2621. blankMessage[0] = L'\0';
  2622. MessageText = &blankMessage[0];
  2623. }
  2624. CLEAR_CLIENT_SCREEN();
  2625. SpStartScreen( SP_SCRN_SYSPREP_FATAL_FAILURE,
  2626. 3,
  2627. HEADER_HEIGHT+1,
  2628. FALSE,
  2629. FALSE,
  2630. DEFAULT_ATTRIBUTE,
  2631. MessageText
  2632. );
  2633. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  2634. SpWaitValidKey(ValidKeys,NULL,NULL);
  2635. SpDone(0,FALSE,FALSE);
  2636. }
  2637. NTSTATUS
  2638. SpSysPrepSetShortFileName (
  2639. PWCHAR Source,
  2640. PWCHAR Dest
  2641. )
  2642. /*++
  2643. Routine Description:
  2644. Try to set the short filename out of the sysprep image.
  2645. This should be considered non-fatal if it fails since not all
  2646. files will have this information set for them.
  2647. Arguments:
  2648. Source :
  2649. Return Value:
  2650. The status code from setting the info. May not return if we hit a failure
  2651. and the user specifies to abort the setup.
  2652. --*/
  2653. {
  2654. ULONG stringLength = 0;
  2655. ULONG FileNameInformationLength = 0;
  2656. PWCHAR fullName = NULL;
  2657. PWCHAR SFNBuffer = NULL;
  2658. HANDLE sourceHandle = NULL;
  2659. HANDLE streamHandle = NULL;
  2660. HANDLE destHandle = NULL;
  2661. OBJECT_ATTRIBUTES Obja;
  2662. IO_STATUS_BLOCK IoStatusBlock;
  2663. UNICODE_STRING UnicodeString;
  2664. NTSTATUS Status;
  2665. MIRROR_SFN_STREAM mirrorHeader;
  2666. LARGE_INTEGER byteOffset;
  2667. ULONG bytesRead;
  2668. BOOLEAN haveSFN = FALSE;
  2669. BOOLEAN haveStream = FALSE;
  2670. BOOLEAN haveSourceAttributes = FALSE;
  2671. PFILE_NAME_INFORMATION FileNameInformation;
  2672. if ((Source == NULL) || (Dest == NULL)) {
  2673. return STATUS_SUCCESS;
  2674. }
  2675. // alloc a buffer to hold the full file of the source including stream
  2676. while (*(Source+stringLength) != L'\0') {
  2677. stringLength++;
  2678. }
  2679. stringLength += sizeof( IMIRROR_SFN_STREAM_NAME ) + 1; // + 1 for size of null
  2680. stringLength *= sizeof(WCHAR);
  2681. fullName = SpMemAlloc( stringLength );
  2682. if (!fullName) {
  2683. Status = STATUS_SUCCESS;
  2684. goto exit;
  2685. }
  2686. wcscpy( fullName, Source );
  2687. wcscat( fullName, IMIRROR_SFN_STREAM_NAME );
  2688. //
  2689. // Open the source stream.
  2690. //
  2691. INIT_OBJA(&Obja,&UnicodeString,fullName);
  2692. Status = ZwCreateFile(
  2693. &streamHandle,
  2694. GENERIC_READ | SYNCHRONIZE,
  2695. &Obja,
  2696. &IoStatusBlock,
  2697. NULL,
  2698. 0,
  2699. FILE_SHARE_READ,
  2700. FILE_OPEN,
  2701. FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  2702. NULL,
  2703. 0
  2704. );
  2705. if ( ! NT_SUCCESS(Status) ) {
  2706. //
  2707. // for now, if a directory or file doesn't have our stream, it's ok.
  2708. // we'll just skip it.
  2709. //
  2710. Status = STATUS_SUCCESS;
  2711. goto exit;
  2712. }
  2713. byteOffset.QuadPart = 0;
  2714. Status = ZwReadFile(streamHandle,
  2715. NULL,
  2716. NULL,
  2717. NULL,
  2718. &IoStatusBlock,
  2719. (PCHAR) &mirrorHeader,
  2720. sizeof( mirrorHeader ),
  2721. &byteOffset,
  2722. NULL
  2723. );
  2724. if (!NT_SUCCESS(Status) ||
  2725. (IoStatusBlock.Information < sizeof( mirrorHeader ))) {
  2726. //
  2727. // we can't read the header correctly. just skip setting SFN.
  2728. //
  2729. Status = STATUS_SUCCESS;
  2730. goto exit;
  2731. }
  2732. if (mirrorHeader.StreamVersion != IMIRROR_SFN_STREAM_VERSION) {
  2733. //
  2734. // we can't read the header correctly. just skip setting SFN.
  2735. //
  2736. Status = STATUS_SUCCESS;
  2737. goto exit;
  2738. }
  2739. haveStream = TRUE;
  2740. //
  2741. // allocate a buffer to hold the SFN. The size is embedded in the header.
  2742. // take off room for the structure and tack on two for a UNICODE_NULL at
  2743. // the end, just in case the stream doesn't have one.
  2744. //
  2745. if (mirrorHeader.StreamLength) {
  2746. SFNBuffer = SpMemAlloc( mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM) + 2 );
  2747. if (!SFNBuffer) {
  2748. Status = STATUS_SUCCESS;
  2749. goto exit;
  2750. }
  2751. byteOffset.QuadPart += sizeof( mirrorHeader );
  2752. //
  2753. // now we read the SFN since we know how long it is.
  2754. //
  2755. Status = ZwReadFile(streamHandle,
  2756. NULL,
  2757. NULL,
  2758. NULL,
  2759. &IoStatusBlock,
  2760. SFNBuffer,
  2761. mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM),
  2762. &byteOffset,
  2763. NULL
  2764. );
  2765. if (!NT_SUCCESS(Status) ||
  2766. (IoStatusBlock.Information < (mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM)))) {
  2767. //
  2768. // oh joy, we can't read the SFN correctly
  2769. //
  2770. Status = STATUS_SUCCESS;
  2771. goto exit;
  2772. }
  2773. haveSFN = TRUE;
  2774. //
  2775. // tack on a unicode NULL just in case.
  2776. //
  2777. SFNBuffer[(mirrorHeader.StreamLength - sizeof(MIRROR_SFN_STREAM))/sizeof(WCHAR)] = UNICODE_NULL;
  2778. } else {
  2779. ASSERT(FALSE);
  2780. Status = STATUS_SUCCESS;
  2781. goto exit;
  2782. }
  2783. INIT_OBJA(&Obja,&UnicodeString,Dest);
  2784. Status = ZwCreateFile(
  2785. &destHandle,
  2786. FILE_READ_ATTRIBUTES |
  2787. FILE_WRITE_ATTRIBUTES |
  2788. FILE_READ_DATA |
  2789. FILE_WRITE_DATA |
  2790. DELETE,
  2791. &Obja,
  2792. &IoStatusBlock,
  2793. NULL,
  2794. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
  2795. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2796. FILE_OPEN,
  2797. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  2798. NULL,
  2799. 0
  2800. );
  2801. if (!NT_SUCCESS(Status)) {
  2802. //
  2803. // Maybe it's not a directory... Try for a file.
  2804. //
  2805. Status = ZwCreateFile(
  2806. &destHandle,
  2807. FILE_READ_ATTRIBUTES |
  2808. FILE_WRITE_ATTRIBUTES |
  2809. FILE_READ_DATA |
  2810. FILE_WRITE_DATA |
  2811. DELETE,
  2812. &Obja,
  2813. &IoStatusBlock,
  2814. NULL,
  2815. FILE_ATTRIBUTE_NORMAL,
  2816. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2817. FILE_OPEN,
  2818. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  2819. NULL,
  2820. 0
  2821. );
  2822. if( !NT_SUCCESS(Status) ) {
  2823. Status = STATUS_SUCCESS;
  2824. goto exit;
  2825. }
  2826. }
  2827. FileNameInformationLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + ((wcslen(SFNBuffer)+1)*sizeof(WCHAR));
  2828. FileNameInformation = SpMemAlloc( FileNameInformationLength );
  2829. if (FileNameInformation) {
  2830. FileNameInformation->FileNameLength = wcslen(SFNBuffer) * sizeof(WCHAR);
  2831. wcscpy( FileNameInformation->FileName, SFNBuffer );
  2832. Status = ZwSetInformationFile( destHandle,
  2833. &IoStatusBlock,
  2834. FileNameInformation,
  2835. FileNameInformationLength,
  2836. FileShortNameInformation
  2837. );
  2838. SpMemFree( FileNameInformation );
  2839. // Keep quiet.
  2840. Status = STATUS_SUCCESS;
  2841. }
  2842. exit:
  2843. if (fullName) {
  2844. SpMemFree( fullName );
  2845. }
  2846. if (SFNBuffer) {
  2847. SpMemFree( SFNBuffer );
  2848. }
  2849. if (streamHandle) {
  2850. ZwClose( streamHandle );
  2851. }
  2852. if (sourceHandle) {
  2853. ZwClose( sourceHandle );
  2854. }
  2855. if (destHandle) {
  2856. ZwClose( destHandle );
  2857. }
  2858. return(Status);
  2859. }
  2860. NTSTATUS
  2861. SpSysPrepSetExtendedInfo (
  2862. PWCHAR Source,
  2863. PWCHAR Dest,
  2864. BOOLEAN Directory,
  2865. BOOLEAN RootDir
  2866. )
  2867. /*++
  2868. Routine Description:
  2869. Try to set the extended information out of the sysprep image. This
  2870. includes the acl and the compression info. If we encounter an error,
  2871. we may not only fail the operation but also reboot if the user chooses
  2872. to abandon the setup.
  2873. Arguments:
  2874. Source :
  2875. Return Value:
  2876. The status code from setting the info. May not return if we hit a failure
  2877. and the user specifies to abort the setup.
  2878. --*/
  2879. {
  2880. ULONG stringLength = 0;
  2881. PWCHAR fullName = NULL;
  2882. PWCHAR rootWithSlash = NULL;
  2883. HANDLE sourceHandle = NULL;
  2884. HANDLE streamHandle = NULL;
  2885. HANDLE destHandle = NULL;
  2886. PCHAR sdBuffer = NULL;
  2887. OBJECT_ATTRIBUTES Obja;
  2888. IO_STATUS_BLOCK IoStatusBlock;
  2889. UNICODE_STRING UnicodeString;
  2890. NTSTATUS Status;
  2891. MIRROR_ACL_STREAM mirrorHeader;
  2892. LARGE_INTEGER byteOffset;
  2893. ULONG bytesRead;
  2894. ULONG ValidKeys[4] = { ASCI_ESC, KEY_F3, 0 };
  2895. ULONG WarnKeys[2] = { KEY_F3, 0 };
  2896. ULONG MnemonicKeys[] = { MnemonicContinueSetup, 0 };
  2897. BOOLEAN haveSecurityDescriptor = FALSE;
  2898. BOOLEAN haveStream = FALSE;
  2899. BOOLEAN haveSourceAttributes = FALSE;
  2900. FILE_BASIC_INFORMATION BasicFileInfo;
  2901. USHORT CompressionState;
  2902. if ((Source == NULL) || (Dest == NULL)) {
  2903. return STATUS_SUCCESS;
  2904. }
  2905. if (!RootDir) {
  2906. SpSysPrepSetShortFileName(Source, Dest);
  2907. }
  2908. mirrorHeader.ExtendedAttributes = 0;
  2909. // alloc a buffer to hold the full file of the source including stream
  2910. while (*(Source+stringLength) != L'\0') {
  2911. stringLength++;
  2912. }
  2913. stringLength += sizeof( IMIRROR_ACL_STREAM_NAME ) + 1; // + 1 for size of null
  2914. stringLength *= sizeof(WCHAR);
  2915. fullName = SpMemAlloc( stringLength );
  2916. wcscpy( fullName, Source );
  2917. wcscat( fullName, IMIRROR_ACL_STREAM_NAME );
  2918. //
  2919. // Open the source stream.
  2920. //
  2921. INIT_OBJA(&Obja,&UnicodeString,fullName);
  2922. Status = ZwCreateFile(
  2923. &streamHandle,
  2924. GENERIC_READ | SYNCHRONIZE,
  2925. &Obja,
  2926. &IoStatusBlock,
  2927. NULL,
  2928. 0,
  2929. FILE_SHARE_READ,
  2930. FILE_OPEN,
  2931. FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  2932. NULL,
  2933. 0
  2934. );
  2935. if ( ! NT_SUCCESS(Status) ) {
  2936. //
  2937. // for now, if a directory or file doesn't have our stream, it's ok.
  2938. // we'll just copy the attributes from the source.
  2939. //
  2940. Status = STATUS_SUCCESS;
  2941. goto setFileAttributes;
  2942. }
  2943. byteOffset.QuadPart = 0;
  2944. Status = ZwReadFile(streamHandle,
  2945. NULL,
  2946. NULL,
  2947. NULL,
  2948. &IoStatusBlock,
  2949. (PCHAR) &mirrorHeader,
  2950. sizeof( mirrorHeader ),
  2951. &byteOffset,
  2952. NULL
  2953. );
  2954. if (!NT_SUCCESS(Status) ||
  2955. (IoStatusBlock.Information < sizeof( mirrorHeader ))) {
  2956. //
  2957. // oh joy, we can't read the header correctly. Let's ask the user
  2958. // if he wants to continue or abort.
  2959. //
  2960. failSetInfo:
  2961. SpStartScreen(
  2962. SP_SCRN_SYSPREP_SETACL_FAILED,
  2963. 3,
  2964. HEADER_HEIGHT+1,
  2965. FALSE,
  2966. FALSE,
  2967. DEFAULT_ATTRIBUTE,
  2968. Dest
  2969. );
  2970. SpDisplayStatusOptions(
  2971. DEFAULT_STATUS_ATTRIBUTE,
  2972. SP_STAT_ESC_EQUALS_SKIP_FILE,
  2973. SP_STAT_F3_EQUALS_EXIT,
  2974. 0
  2975. );
  2976. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  2977. case ASCI_ESC: // skip file
  2978. break;
  2979. case KEY_F3: // exit setup
  2980. SpConfirmExit();
  2981. goto failSetInfo;
  2982. }
  2983. CLEAR_CLIENT_SCREEN();
  2984. //
  2985. // we're skipping the file, delete it if it's not a directory since
  2986. // it isn't correctly formed.
  2987. //
  2988. if (destHandle) {
  2989. ZwClose( destHandle );
  2990. destHandle = NULL;
  2991. }
  2992. if ( ! Directory ) {
  2993. SpDeleteFile(Dest,NULL,NULL);
  2994. } else {
  2995. if (!RootDir) {
  2996. SpDeleteFileEx( Dest, NULL, NULL,
  2997. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  2998. FILE_OPEN_FOR_BACKUP_INTENT );
  2999. }
  3000. }
  3001. return Status;
  3002. }
  3003. if (mirrorHeader.StreamVersion != IMIRROR_ACL_STREAM_VERSION) {
  3004. //
  3005. // oh joy, we've hit a file we don't support.
  3006. //
  3007. goto failSetInfo;
  3008. }
  3009. haveStream = TRUE;
  3010. //
  3011. // allocate a buffer to hold the security descriptor.
  3012. //
  3013. if (mirrorHeader.SecurityDescriptorLength) {
  3014. sdBuffer = SpMemAlloc( mirrorHeader.SecurityDescriptorLength );
  3015. byteOffset.QuadPart += sizeof( mirrorHeader );
  3016. //
  3017. // now we read the security descriptor since we know how long it is.
  3018. //
  3019. Status = ZwReadFile(streamHandle,
  3020. NULL,
  3021. NULL,
  3022. NULL,
  3023. &IoStatusBlock,
  3024. sdBuffer,
  3025. mirrorHeader.SecurityDescriptorLength,
  3026. &byteOffset,
  3027. NULL
  3028. );
  3029. if (!NT_SUCCESS(Status) ||
  3030. (IoStatusBlock.Information < mirrorHeader.SecurityDescriptorLength)) {
  3031. //
  3032. // oh joy, we can't read the SD correctly
  3033. //
  3034. goto failSetInfo;
  3035. }
  3036. haveSecurityDescriptor = TRUE;
  3037. }
  3038. setFileAttributes:
  3039. //
  3040. // we first open the source to get the file attributes and times that we're
  3041. // going to copy over to the dest.
  3042. //
  3043. INIT_OBJA(&Obja,&UnicodeString,Source);
  3044. Status = ZwCreateFile(
  3045. &sourceHandle,
  3046. FILE_READ_ATTRIBUTES,
  3047. &Obja,
  3048. &IoStatusBlock,
  3049. NULL,
  3050. 0,
  3051. FILE_SHARE_READ,
  3052. FILE_OPEN,
  3053. Directory ? ( FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT ) : FILE_NON_DIRECTORY_FILE,
  3054. NULL,
  3055. 0
  3056. );
  3057. if ( NT_SUCCESS(Status) ) {
  3058. Status = ZwQueryInformationFile( sourceHandle,
  3059. &IoStatusBlock,
  3060. &BasicFileInfo,
  3061. sizeof(BasicFileInfo),
  3062. FileBasicInformation
  3063. );
  3064. if (NT_SUCCESS(Status)) {
  3065. haveSourceAttributes = TRUE;
  3066. }
  3067. }
  3068. //
  3069. // Now we open the target to write out the security descriptor and
  3070. // attributes.
  3071. //
  3072. if (RootDir) {
  3073. //
  3074. // append a \ to the end of the dest path
  3075. //
  3076. stringLength = 0;
  3077. while (*(Dest+stringLength) != L'\0') {
  3078. stringLength++;
  3079. }
  3080. stringLength += 2; // one for null, one for backslash
  3081. stringLength *= sizeof(WCHAR);
  3082. rootWithSlash = SpMemAlloc( stringLength );
  3083. wcscpy( rootWithSlash, Dest );
  3084. wcscat( rootWithSlash, L"\\" );
  3085. INIT_OBJA(&Obja,&UnicodeString,rootWithSlash);
  3086. } else {
  3087. INIT_OBJA(&Obja,&UnicodeString,Dest);
  3088. }
  3089. Status = ZwCreateFile(
  3090. &destHandle,
  3091. WRITE_OWNER |
  3092. WRITE_DAC |
  3093. ACCESS_SYSTEM_SECURITY |
  3094. FILE_READ_ATTRIBUTES |
  3095. FILE_WRITE_ATTRIBUTES |
  3096. FILE_READ_DATA |
  3097. FILE_WRITE_DATA,
  3098. &Obja,
  3099. &IoStatusBlock,
  3100. NULL,
  3101. 0,
  3102. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3103. FILE_OPEN,
  3104. FILE_SYNCHRONOUS_IO_NONALERT,
  3105. NULL,
  3106. 0
  3107. );
  3108. if (!NT_SUCCESS(Status)) {
  3109. //
  3110. // oh joy, we can't open the target correctly.
  3111. //
  3112. goto failSetInfo;
  3113. }
  3114. // NOTE: figure out what to do about reparse points and encrypted files
  3115. // if (mirrorHeader.ExtendedAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  3116. // }
  3117. // if (mirrorHeader.ExtendedAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  3118. // }
  3119. if (mirrorHeader.ExtendedAttributes & FILE_ATTRIBUTE_COMPRESSED) {
  3120. CompressionState = COMPRESSION_FORMAT_DEFAULT;
  3121. } else {
  3122. CompressionState = COMPRESSION_FORMAT_NONE;
  3123. }
  3124. try {
  3125. Status = ZwFsControlFile( destHandle,
  3126. NULL,
  3127. NULL,
  3128. NULL,
  3129. &IoStatusBlock,
  3130. FSCTL_SET_COMPRESSION,
  3131. &CompressionState,
  3132. sizeof(CompressionState),
  3133. NULL,
  3134. 0
  3135. );
  3136. if (Status == STATUS_INVALID_DEVICE_REQUEST) {
  3137. //
  3138. // if this file system doesn't support compression for this
  3139. // object, we'll just ignore the error.
  3140. //
  3141. Status = STATUS_SUCCESS;
  3142. }
  3143. } except(EXCEPTION_EXECUTE_HANDLER) {
  3144. Status = STATUS_IN_PAGE_ERROR;
  3145. }
  3146. if ( NT_SUCCESS(Status) && ! haveSourceAttributes ) {
  3147. //
  3148. // if we don't have the source attributes, just grab them from the
  3149. // destination so that we have some attributes to manipulate.
  3150. //
  3151. Status = ZwQueryInformationFile( destHandle,
  3152. &IoStatusBlock,
  3153. &BasicFileInfo,
  3154. sizeof(BasicFileInfo),
  3155. FileBasicInformation
  3156. );
  3157. }
  3158. if (haveStream) {
  3159. //
  3160. // If this file has our stream, use the stream fields as the overriding
  3161. // values. They even override the source file's attributes on the server.
  3162. //
  3163. BasicFileInfo.FileAttributes = mirrorHeader.ExtendedAttributes;
  3164. BasicFileInfo.ChangeTime.QuadPart = mirrorHeader.ChangeTime.QuadPart;
  3165. }
  3166. if ( NT_SUCCESS(Status) ) {
  3167. if (Directory) {
  3168. BasicFileInfo.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  3169. } else if (BasicFileInfo.FileAttributes == 0) {
  3170. BasicFileInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  3171. }
  3172. Status = ZwSetInformationFile( destHandle,
  3173. &IoStatusBlock,
  3174. &BasicFileInfo,
  3175. sizeof(BasicFileInfo),
  3176. FileBasicInformation
  3177. );
  3178. if (Status == STATUS_INVALID_PARAMETER && RootDir) {
  3179. //
  3180. // if this file system doesn't support setting attributes on the
  3181. // root of the volume, we'll ignore the error.
  3182. //
  3183. Status = STATUS_SUCCESS;
  3184. }
  3185. }
  3186. if (!NT_SUCCESS(Status)) {
  3187. //
  3188. // post a warning that we couldn't set it. shouldn't be fatal.
  3189. //
  3190. SpStartScreen(
  3191. SP_SCRN_SYSPREP_COPY_FAILURE,
  3192. 3,
  3193. HEADER_HEIGHT+1,
  3194. FALSE,
  3195. FALSE,
  3196. DEFAULT_ATTRIBUTE,
  3197. Status,
  3198. Dest
  3199. );
  3200. SpDisplayStatusOptions(
  3201. DEFAULT_STATUS_ATTRIBUTE,
  3202. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  3203. SP_STAT_F3_EQUALS_EXIT,
  3204. 0
  3205. );
  3206. switch(SpWaitValidKey(WarnKeys,NULL,MnemonicKeys)) {
  3207. case KEY_F3: // exit setup
  3208. SpConfirmExit();
  3209. break;
  3210. default:
  3211. break;
  3212. }
  3213. }
  3214. if (haveSecurityDescriptor) {
  3215. try {
  3216. // the state of the security descriptor is unknown, let's protect
  3217. // ourselves
  3218. Status = ZwSetSecurityObject( destHandle,
  3219. OWNER_SECURITY_INFORMATION |
  3220. GROUP_SECURITY_INFORMATION |
  3221. DACL_SECURITY_INFORMATION |
  3222. SACL_SECURITY_INFORMATION,
  3223. (PSECURITY_DESCRIPTOR) sdBuffer
  3224. );
  3225. } except(EXCEPTION_EXECUTE_HANDLER) {
  3226. Status = STATUS_IN_PAGE_ERROR;
  3227. }
  3228. if (!NT_SUCCESS(Status)) {
  3229. //
  3230. // oh joy, we can't write the SD correctly.
  3231. //
  3232. goto failSetInfo;
  3233. }
  3234. }
  3235. // endSetExtended:
  3236. if (rootWithSlash) {
  3237. SpMemFree( rootWithSlash );
  3238. }
  3239. if (fullName) {
  3240. SpMemFree( fullName );
  3241. }
  3242. if (sdBuffer) {
  3243. SpMemFree( sdBuffer );
  3244. }
  3245. if (streamHandle) {
  3246. ZwClose( streamHandle );
  3247. }
  3248. if (sourceHandle) {
  3249. ZwClose( sourceHandle );
  3250. }
  3251. if (destHandle) {
  3252. ZwClose( destHandle );
  3253. }
  3254. return STATUS_SUCCESS;
  3255. }
  3256. NTSTATUS
  3257. SpCopyEAsAndStreams (
  3258. PWCHAR SourceFile,
  3259. HANDLE SourceHandle OPTIONAL,
  3260. PWCHAR TargetFile,
  3261. HANDLE TargetHandle OPTIONAL,
  3262. BOOLEAN Directory
  3263. )
  3264. //
  3265. // This copies the EAs and streams from the source to the target. The
  3266. // source and dest handles are specified for files and optional for
  3267. // directories.
  3268. //
  3269. {
  3270. NTSTATUS Status;
  3271. IO_STATUS_BLOCK IoStatusBlock;
  3272. ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  3273. FILE_EA_INFORMATION eaInfo;
  3274. HANDLE tempSourceHandle = SourceHandle;
  3275. HANDLE tempTargetHandle = TargetHandle;
  3276. HANDLE StreamHandle;
  3277. HANDLE newStreamHandle;
  3278. OBJECT_ATTRIBUTES Obja;
  3279. UNICODE_STRING UnicodeString;
  3280. ULONG StreamInfoSize = 4096-8; // alloc a whole page. spmemalloc reserves 8 bytes
  3281. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  3282. PFILE_STREAM_INFORMATION StreamInfo;
  3283. PUCHAR StreamBuffer = NULL;
  3284. UNICODE_STRING StreamName;
  3285. retryCopyEAs:
  3286. if (tempSourceHandle == NULL) {
  3287. INIT_OBJA(&Obja,&UnicodeString,SourceFile);
  3288. Status = ZwCreateFile(
  3289. &tempSourceHandle,
  3290. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  3291. &Obja,
  3292. &IoStatusBlock,
  3293. NULL,
  3294. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
  3295. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3296. FILE_OPEN_IF,
  3297. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  3298. NULL,
  3299. 0
  3300. );
  3301. if (!NT_SUCCESS(Status)) {
  3302. goto EndCopyEAs;
  3303. }
  3304. }
  3305. if (tempTargetHandle == NULL) {
  3306. INIT_OBJA(&Obja,&UnicodeString,TargetFile);
  3307. Status = ZwCreateFile(
  3308. &tempTargetHandle,
  3309. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  3310. &Obja,
  3311. &IoStatusBlock,
  3312. NULL,
  3313. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
  3314. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3315. FILE_OPEN_IF,
  3316. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  3317. NULL,
  3318. 0
  3319. );
  3320. if(!NT_SUCCESS(Status)) {
  3321. goto EndCopyEAs;
  3322. }
  3323. }
  3324. //
  3325. // EAs can be on either FAT or NTFS.
  3326. //
  3327. Status = ZwQueryInformationFile( tempSourceHandle,
  3328. &IoStatusBlock,
  3329. &eaInfo,
  3330. sizeof( eaInfo ),
  3331. FileEaInformation
  3332. );
  3333. if (Status == STATUS_SUCCESS && eaInfo.EaSize > 0) {
  3334. //
  3335. // FileEaInformation, oddly enough, doesn't tell you how big a
  3336. // buffer you need to retrieve the EAs. Instead, it tells you
  3337. // how much room the EAs take up on the disk (in OS/2 format)!
  3338. // So we use the OS/2 size as a rough approximation of how large
  3339. // a buffer we need.
  3340. //
  3341. ULONG actualEaSize = eaInfo.EaSize;
  3342. PCHAR eaBuffer;
  3343. do {
  3344. actualEaSize *= 2;
  3345. eaBuffer = SpMemAlloc( actualEaSize );
  3346. Status = ZwQueryEaFile( tempSourceHandle,
  3347. &IoStatusBlock,
  3348. eaBuffer,
  3349. actualEaSize,
  3350. FALSE,
  3351. NULL,
  3352. 0,
  3353. NULL,
  3354. TRUE );
  3355. if ( !NT_SUCCESS(Status) ) {
  3356. SpMemFree( eaBuffer );
  3357. IoStatusBlock.Information = 0;
  3358. }
  3359. } while ( (Status == STATUS_BUFFER_OVERFLOW) ||
  3360. (Status == STATUS_BUFFER_TOO_SMALL) );
  3361. actualEaSize = (ULONG)IoStatusBlock.Information;
  3362. if (NT_SUCCESS( Status )) {
  3363. Status = ZwSetEaFile( tempTargetHandle,
  3364. &IoStatusBlock,
  3365. eaBuffer,
  3366. actualEaSize
  3367. );
  3368. }
  3369. SpMemFree( eaBuffer );
  3370. if (! NT_SUCCESS( Status )) {
  3371. goto EndCopyEAs;
  3372. }
  3373. }
  3374. //
  3375. // Streams are only on NTFS and they're also only on files, not directories.
  3376. //
  3377. if (( RemoteSysPrepVolumeIsNtfs != TRUE ) || Directory ) {
  3378. goto EndCopyEAs;
  3379. }
  3380. do {
  3381. if (StreamInfoBase == NULL) {
  3382. StreamInfoBase = SpMemAlloc( StreamInfoSize );
  3383. }
  3384. Status = ZwQueryInformationFile(
  3385. tempSourceHandle,
  3386. &IoStatusBlock,
  3387. (PVOID) StreamInfoBase,
  3388. StreamInfoSize,
  3389. FileStreamInformation
  3390. );
  3391. if ( !NT_SUCCESS(Status) ) {
  3392. SpMemFree( StreamInfoBase );
  3393. StreamInfoBase = NULL;
  3394. StreamInfoSize *= 2;
  3395. }
  3396. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  3397. Status == STATUS_BUFFER_TOO_SMALL );
  3398. if ( NT_SUCCESS(Status) && IoStatusBlock.Information ) {
  3399. StreamInfo = StreamInfoBase;
  3400. for (;;) {
  3401. PWCHAR streamPtr;
  3402. USHORT remainingLength;
  3403. PWCHAR streamName;
  3404. //
  3405. // Build a string descriptor for the name of the stream.
  3406. //
  3407. StreamName.Buffer = &StreamInfo->StreamName[0];
  3408. StreamName.Length = (USHORT) StreamInfo->StreamNameLength;
  3409. StreamName.MaximumLength = StreamName.Length;
  3410. streamPtr = StreamName.Buffer;
  3411. if ((StreamName.Length > 0) && *streamPtr == L':') {
  3412. streamPtr++; // skip leading ":"
  3413. streamName = streamPtr; // remember start of stream name
  3414. remainingLength = StreamName.Length - sizeof(WCHAR);
  3415. while (remainingLength > 0 && *streamPtr != L':') {
  3416. streamPtr++;
  3417. remainingLength -= sizeof(WCHAR);
  3418. }
  3419. if (remainingLength > 0) {
  3420. if ((remainingLength == (sizeof(L":$DATA")-sizeof(WCHAR))) &&
  3421. (RtlCompareMemory( streamPtr, L":$DATA", remainingLength )
  3422. == remainingLength)) {
  3423. //
  3424. // the attribute type on this is of type data so we
  3425. // have a data stream here. Now check that it is not
  3426. // the unnamed primary data stream and our own acl stream
  3427. // or the short file name stream.
  3428. //
  3429. if ((*streamName != L':') &&
  3430. ((RtlCompareMemory(StreamName.Buffer,
  3431. IMIRROR_ACL_STREAM_NAME,
  3432. (sizeof(IMIRROR_ACL_STREAM_NAME)-sizeof(WCHAR)))
  3433. != (sizeof(IMIRROR_ACL_STREAM_NAME)-sizeof(WCHAR))) &&
  3434. (RtlCompareMemory(StreamName.Buffer,
  3435. IMIRROR_SFN_STREAM_NAME,
  3436. (sizeof(IMIRROR_SFN_STREAM_NAME)-sizeof(WCHAR)))
  3437. != (sizeof(IMIRROR_SFN_STREAM_NAME)-sizeof(WCHAR))))) {
  3438. //
  3439. // allocate a buffer to hold the stream data.
  3440. // Can't use TemporaryBuffer as it's used by
  3441. // SpCopyDirRecursiveCallback et al.
  3442. //
  3443. if (StreamBuffer == NULL) {
  3444. StreamBuffer = SpMemAlloc( StreamInfoSize );
  3445. }
  3446. //
  3447. // we chop off the ":DATA" suffix from the stream name
  3448. //
  3449. StreamName.Length -= remainingLength;
  3450. //
  3451. // Open the source stream.
  3452. //
  3453. InitializeObjectAttributes(
  3454. &Obja,
  3455. &StreamName,
  3456. 0,
  3457. tempSourceHandle,
  3458. NULL
  3459. );
  3460. Status = ZwCreateFile(
  3461. &StreamHandle,
  3462. GENERIC_READ | SYNCHRONIZE,
  3463. &Obja,
  3464. &IoStatusBlock,
  3465. NULL,
  3466. 0,
  3467. FILE_SHARE_READ,
  3468. FILE_OPEN,
  3469. FILE_SYNCHRONOUS_IO_NONALERT,
  3470. NULL,
  3471. 0
  3472. );
  3473. if ( ! NT_SUCCESS(Status) ) {
  3474. break;
  3475. }
  3476. //
  3477. // Open the source stream.
  3478. //
  3479. InitializeObjectAttributes(
  3480. &Obja,
  3481. &StreamName,
  3482. 0,
  3483. tempTargetHandle,
  3484. NULL
  3485. );
  3486. Status = ZwCreateFile(
  3487. &newStreamHandle,
  3488. GENERIC_WRITE,
  3489. &Obja,
  3490. &IoStatusBlock,
  3491. NULL,
  3492. 0,
  3493. FILE_SHARE_READ,
  3494. FILE_CREATE,
  3495. FILE_SYNCHRONOUS_IO_NONALERT,
  3496. NULL,
  3497. 0
  3498. );
  3499. if ( NT_SUCCESS(Status) ) {
  3500. LARGE_INTEGER byteOffset;
  3501. ULONG bytesRead;
  3502. byteOffset.QuadPart = 0;
  3503. while (NT_SUCCESS(Status)) {
  3504. Status = ZwReadFile(StreamHandle,
  3505. NULL,
  3506. NULL,
  3507. NULL,
  3508. &IoStatusBlock,
  3509. StreamBuffer,
  3510. StreamInfoSize,
  3511. &byteOffset,
  3512. NULL
  3513. );
  3514. if ( ! NT_SUCCESS(Status) ) {
  3515. if (Status == STATUS_END_OF_FILE) {
  3516. Status = STATUS_SUCCESS;
  3517. }
  3518. break;
  3519. }
  3520. bytesRead = (ULONG)IoStatusBlock.Information;
  3521. try {
  3522. Status = ZwWriteFile(newStreamHandle,
  3523. NULL,
  3524. NULL,
  3525. NULL,
  3526. &IoStatusBlock,
  3527. StreamBuffer,
  3528. bytesRead,
  3529. &byteOffset,
  3530. NULL
  3531. );
  3532. } except(EXCEPTION_EXECUTE_HANDLER) {
  3533. Status = STATUS_IN_PAGE_ERROR;
  3534. }
  3535. byteOffset.QuadPart += bytesRead;
  3536. }
  3537. ZwClose(newStreamHandle);
  3538. }
  3539. ZwClose(StreamHandle);
  3540. }
  3541. }
  3542. }
  3543. }
  3544. if ( NT_SUCCESS(Status) && StreamInfo->NextEntryOffset ) {
  3545. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  3546. } else {
  3547. break;
  3548. }
  3549. }
  3550. }
  3551. EndCopyEAs:
  3552. if (tempSourceHandle != NULL && SourceHandle == NULL) {
  3553. ZwClose( tempSourceHandle );
  3554. }
  3555. if (tempTargetHandle != NULL && TargetHandle == NULL) {
  3556. ZwClose( tempTargetHandle );
  3557. }
  3558. if (!NT_SUCCESS(Status)) {
  3559. //
  3560. // this failed. let's ask the user if he wants to retry, skip, or
  3561. // abort.
  3562. //
  3563. repaint:
  3564. SpStartScreen(
  3565. SP_SCRN_COPY_FAILED,
  3566. 3,
  3567. HEADER_HEIGHT+1,
  3568. FALSE,
  3569. FALSE,
  3570. DEFAULT_ATTRIBUTE,
  3571. TargetFile
  3572. );
  3573. SpDisplayStatusOptions(
  3574. DEFAULT_STATUS_ATTRIBUTE,
  3575. SP_STAT_ENTER_EQUALS_RETRY,
  3576. SP_STAT_ESC_EQUALS_SKIP_FILE,
  3577. SP_STAT_F3_EQUALS_EXIT,
  3578. 0
  3579. );
  3580. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  3581. case ASCI_CR: // retry
  3582. SpCopyFilesScreenRepaint(SourceFile,TargetFile,TRUE);
  3583. goto retryCopyEAs;
  3584. case ASCI_ESC: // skip file
  3585. break;
  3586. case KEY_F3: // exit setup
  3587. SpConfirmExit();
  3588. goto repaint;
  3589. }
  3590. //
  3591. // we're skipping the file, delete it if it's not a directory since
  3592. // it isn't correctly formed.
  3593. //
  3594. if ( ! Directory ) {
  3595. SpDeleteFile(TargetFile,NULL,NULL);
  3596. }
  3597. //
  3598. // Need to completely repaint gauge, etc.
  3599. //
  3600. SpCopyFilesScreenRepaint(SourceFile,TargetFile,TRUE);
  3601. }
  3602. if (StreamInfoBase != NULL) {
  3603. SpMemFree(StreamInfoBase);
  3604. }
  3605. if (StreamBuffer != NULL) {
  3606. SpMemFree(StreamBuffer);
  3607. }
  3608. return Status;
  3609. }