Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8945 lines
258 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spcopy.c
  5. Abstract:
  6. File copy/decompression routines for text setup.
  7. Author:
  8. Ted Miller (tedm) 2-Aug-1993
  9. Revision History:
  10. 02-Oct-1996 jimschm Added SpMoveWin9xFiles
  11. 12-Dec-1996 jimschm SpMoveWin9xFiles now moves paths
  12. based on WINNT.SIF instructions
  13. 24-Feb-1997 jimschm Added SpDeleteWin9xFiles
  14. --*/
  15. #include "spprecmp.h"
  16. #pragma hdrstop
  17. #include "spcmdcon.h"
  18. //
  19. // This structure is used during an OEM preinstall.
  20. // It is used to form the list of files that were installed in the system, that
  21. // have a short target name, instead of the corresponding long target name.
  22. //
  23. typedef struct _FILE_TO_RENAME {
  24. struct _FILE_TO_RENAME *Next;
  25. //
  26. // Name of the file to be copied, as it exists on the source media
  27. // (short file name part only -- no paths).
  28. //
  29. PWSTR SourceFilename;
  30. //
  31. // Directory to which this file is to be copied.
  32. //
  33. PWSTR TargetDirectory;
  34. //
  35. // Name of file as it should exist on the target (long name).
  36. //
  37. PWSTR TargetFilename;
  38. } FILE_TO_RENAME, *PFILE_TO_RENAME;
  39. //
  40. // Structures used to hold lists of files and directories for SpCopyDirRecursive.
  41. //
  42. typedef struct _COPYDIR_FILE_NODE {
  43. LIST_ENTRY SiblingListEntry;
  44. WCHAR Name[1];
  45. } COPYDIR_FILE_NODE, *PCOPYDIR_FILE_NODE;
  46. typedef struct _COPYDIR_DIRECTORY_NODE {
  47. LIST_ENTRY SiblingListEntry;
  48. LIST_ENTRY SubdirectoryList;
  49. LIST_ENTRY FileList;
  50. struct _COPYDIR_DIRECTORY_NODE *Parent;
  51. WCHAR Name[1];
  52. } COPYDIR_DIRECTORY_NODE, *PCOPYDIR_DIRECTORY_NODE;
  53. //
  54. // List used on an OEM preinstall.
  55. // It contains the name of the files that need to be added to $$RENAME.TXT
  56. //
  57. PFILE_TO_RENAME RenameList = NULL;
  58. //
  59. // Remember whether or not we write out an ntbootdd.sys
  60. //
  61. BOOLEAN ForceBIOSBoot = FALSE;
  62. HARDWAREIDLIST *HardwareIDList = NULL;
  63. //
  64. // global variables for delayed driver CAB opening during
  65. // repair
  66. //
  67. extern PWSTR gszDrvInfDeviceName;
  68. extern PWSTR gszDrvInfDirName;
  69. extern HANDLE ghSif;
  70. #define ATTR_RHS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
  71. PVOID FileCopyGauge;
  72. PVOID FileDeleteGauge;
  73. PVOID _SetupLogFile = NULL;
  74. PVOID _LoggedOemFiles = NULL;
  75. extern PCMDCON_BLOCK gpCmdConsBlock;
  76. //
  77. // List of oem inf files installed as part of the installation of third party drivers
  78. //
  79. POEM_INF_FILE OemInfFileList = NULL;
  80. //
  81. // Name of the directory where OEM files need to be copied, if a catalog file (.cat) is part of
  82. // the third party driver package that the user provide using the F6 or F5 key.
  83. //
  84. PWSTR OemDirName = L"OemDir";
  85. #if defined(REMOTE_BOOT)
  86. HANDLE SisRootHandle = NULL;
  87. #endif // defined(REMOTE_BOOT)
  88. VOID
  89. SpLogOneFile(
  90. IN PFILE_TO_COPY FileToCopy,
  91. IN PWSTR Sysroot,
  92. IN PWSTR DirectoryOnSourceDevice,
  93. IN PWSTR DiskDescription,
  94. IN PWSTR DiskTag,
  95. IN ULONG CheckSum
  96. );
  97. BOOLEAN
  98. SpRemoveEntryFromCopyList(
  99. IN PDISK_FILE_LIST DiskFileLists,
  100. IN ULONG DiskCount,
  101. IN PWSTR TargetDirectory,
  102. IN PWSTR TargetFilename,
  103. IN PWSTR TargetDevicePath,
  104. IN BOOLEAN AbsoluteTargetDirectory
  105. );
  106. PVOID
  107. SppRetrieveLoggedOemFiles(
  108. PVOID OldLogFile
  109. );
  110. VOID
  111. SppMergeLoggedOemFiles(
  112. IN PVOID DestLogHandle,
  113. IN PVOID OemLogHandle,
  114. IN PWSTR SystemPartition,
  115. IN PWSTR SystemPartitionDirectory,
  116. IN PWSTR NtPartition
  117. );
  118. BOOLEAN
  119. SppIsFileLoggedAsOemFile(
  120. IN PWSTR FilePath
  121. );
  122. BOOLEAN
  123. SpDelEnumFile(
  124. IN PCWSTR DirName,
  125. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  126. OUT PULONG ret,
  127. IN PVOID Pointer
  128. );
  129. VOID
  130. SppMergeRenameFiles(
  131. IN PWSTR SourceDevicePath,
  132. IN PWSTR NtPartition,
  133. IN PWSTR Sysroot
  134. );
  135. VOID
  136. SppCopyOemDirectories(
  137. IN PWSTR SourceDevicePath,
  138. IN PWSTR NtPartition,
  139. IN PWSTR Sysroot
  140. );
  141. NTSTATUS
  142. SpOpenFileInDriverCab(
  143. IN PCWSTR SourceFileName,
  144. IN PVOID SifHandle,
  145. OUT HANDLE *SourceHandle
  146. );
  147. BOOLEAN
  148. pSpTimeFromDosTime(
  149. IN USHORT Date,
  150. IN USHORT Time,
  151. OUT PLARGE_INTEGER UtcTime
  152. );
  153. VOID
  154. SpInitializeDriverInf(
  155. IN HANDLE MasterSifHandle,
  156. IN PWSTR SetupSourceDevicePath,
  157. IN PWSTR DirectoryOnSourceDevice
  158. );
  159. BOOLEAN
  160. SpCreateDirectory(
  161. IN PCWSTR DevicePath, OPTIONAL
  162. IN PCWSTR RootDirectory, OPTIONAL
  163. IN PCWSTR Directory,
  164. IN ULONG DirAttrs OPTIONAL,
  165. IN ULONG CreateFlags OPTIONAL
  166. )
  167. /*++
  168. Routine Description:
  169. Create a directory. All containing directories are created to ensure
  170. that the directory can be created. For example, if the directory to be
  171. created is \a\b\c, then this routine will create \a, \a\b, and \a\b\c
  172. in that order.
  173. Arguments:
  174. DevicePath - supplies pathname to the device on which the directory
  175. is to be created.
  176. RootDirectory - if specified, supplies a fixed portion of the directory name,
  177. which may or may not have been already created. The directory being created will be
  178. concatenated to this value.
  179. Directory - supplies directory to be created on the device. You may use
  180. this to specify a full NT path (pass in NULL for DevicePath and
  181. RootDirectory).
  182. Return Value:
  183. None. Does not return if directry could not successfully be created.
  184. --*/
  185. {
  186. PWSTR p,q,r,EntirePath, z, NewName;
  187. OBJECT_ATTRIBUTES Obja;
  188. UNICODE_STRING UnicodeString;
  189. NTSTATUS Status;
  190. IO_STATUS_BLOCK IoStatusBlock;
  191. HANDLE Handle;
  192. ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
  193. ULONG DevicePartLen;
  194. BOOL TriedOnce;
  195. BOOLEAN SkippedFile = FALSE;
  196. static ULONG u = 0;
  197. ASSERT (Directory);
  198. NewName = NULL;
  199. //
  200. // Do not bother attempting to create the root directory.
  201. //
  202. if((Directory[0] == 0) || ((Directory[0] == L'\\') && (Directory[1] == 0))) {
  203. return TRUE;
  204. }
  205. //
  206. // Fill up TemporaryBuffer with the full pathname of the directory being
  207. // created. If DevicePath is NULL, TemporaryBuffer will be filled with one
  208. // backslash. Because Directory is required, this ensures the path starts
  209. // with a backslash.
  210. //
  211. p = TemporaryBuffer;
  212. *p = 0;
  213. SpConcatenatePaths(p,DevicePath);
  214. DevicePartLen = wcslen(p);
  215. if(RootDirectory) {
  216. SpConcatenatePaths(p,RootDirectory);
  217. }
  218. SpConcatenatePaths(p,Directory);
  219. //
  220. // Make a duplicate of the path being created.
  221. //
  222. EntirePath = SpDupStringW(p);
  223. if (!EntirePath) {
  224. return FALSE; // ran out of memory
  225. }
  226. //
  227. // Make q point to the first character in the directory
  228. // part of the pathname (ie, 1 char past the end of the device name).
  229. //
  230. q = EntirePath + DevicePartLen;
  231. //
  232. // Note: It is possible for the device path to end in a '\', so we may need
  233. // to backup one character
  234. //
  235. if (*q != L'\\') {
  236. q--;
  237. }
  238. ASSERT(*q == L'\\');
  239. //
  240. // Make r point to the first character in the directory
  241. // part of the pathname. This will be used to keep the status
  242. // line updated with the directory being created.
  243. //
  244. r = q;
  245. //
  246. // Make p point to the first character following the first
  247. // \ in the directory part of the full path.
  248. //
  249. p = q+1;
  250. do {
  251. //
  252. // find the next \ or the terminating 0.
  253. //
  254. q = wcschr(p,L'\\');
  255. //
  256. // If we found \, terminate the string at that point.
  257. //
  258. if(q) {
  259. *q = 0;
  260. }
  261. do {
  262. if( !HeadlessTerminalConnected ) {
  263. SpDisplayStatusText(SP_STAT_CREATING_DIRS,DEFAULT_STATUS_ATTRIBUTE,r);
  264. } else {
  265. PWCHAR TempPtr = NULL;
  266. //
  267. // If we're headless, we need to be careful about displaying very long
  268. // file/directory names. For that reason, just display a little spinner.
  269. //
  270. switch( u % 4) {
  271. case 0:
  272. TempPtr = L"-";
  273. break;
  274. case 1:
  275. TempPtr = L"\\";
  276. break;
  277. case 2:
  278. TempPtr = L"|";
  279. break;
  280. default:
  281. TempPtr = L"/";
  282. break;
  283. }
  284. SpDisplayStatusText( SP_STAT_CREATING_DIRS,DEFAULT_STATUS_ATTRIBUTE, TempPtr );
  285. u++;
  286. }
  287. //
  288. // Create or open the directory whose name is in EntirePath.
  289. //
  290. INIT_OBJA(&Obja,&UnicodeString,EntirePath);
  291. Handle = NULL;
  292. TriedOnce = FALSE;
  293. tryagain:
  294. Status = ZwCreateFile(
  295. &Handle,
  296. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  297. &Obja,
  298. &IoStatusBlock,
  299. NULL,
  300. FILE_ATTRIBUTE_NORMAL | DirAttrs,
  301. FILE_SHARE_READ | FILE_SHARE_WRITE,
  302. FILE_OPEN_IF,
  303. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  304. NULL,
  305. 0
  306. );
  307. //
  308. // If it's an obdirectory, obsymlink, device, or directory, then they just didn't pass
  309. // a long enough DevicePath. Let this by.
  310. //
  311. if (Status == STATUS_NOT_A_DIRECTORY) {
  312. //
  313. //Could be that a file exists by that name. Rename it out of the way
  314. //
  315. if( SpFileExists( EntirePath, FALSE ) && !TriedOnce){
  316. z = TemporaryBuffer;
  317. wcscpy( z, EntirePath );
  318. wcscat( z, L".SetupRenamedFile" );
  319. NewName = SpDupStringW( z );
  320. if( !NewName )
  321. return FALSE; //out of memory - bugcheck (never gets here) - but this keeps PREFIX happy
  322. Status = SpRenameFile( EntirePath, NewName, FALSE );
  323. if( NT_SUCCESS(Status)){
  324. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Renamed file %ws to %ws\n", r, NewName));
  325. TriedOnce = TRUE;
  326. goto tryagain;
  327. }else{
  328. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to rename file %ws (%lx)\n", r, Status));
  329. }
  330. }
  331. }
  332. if(!NT_SUCCESS(Status)) {
  333. BOOLEAN b = TRUE;
  334. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to create dir %ws (%lx)\n", r, Status));
  335. if (CreateFlags & CREATE_DIRECTORY_FLAG_SKIPPABLE) {
  336. SkippedFile = TRUE;
  337. goto SkippedFileQuit;
  338. }
  339. //
  340. // Tell user we couldn't do it. Options are to retry or exit.
  341. //
  342. while(b) {
  343. SpStartScreen(
  344. SP_SCRN_DIR_CREATE_ERR,
  345. 3,
  346. HEADER_HEIGHT+1,
  347. FALSE,
  348. FALSE,
  349. DEFAULT_ATTRIBUTE,
  350. r
  351. );
  352. SpDisplayStatusOptions(
  353. DEFAULT_STATUS_ATTRIBUTE,
  354. SP_STAT_ENTER_EQUALS_RETRY,
  355. SP_STAT_F3_EQUALS_EXIT,
  356. 0
  357. );
  358. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  359. case ASCI_CR:
  360. b = FALSE;
  361. break;
  362. case KEY_F3:
  363. SpConfirmExit();
  364. break;
  365. }
  366. }
  367. }
  368. } while(!NT_SUCCESS(Status));
  369. if (Handle != NULL)
  370. ZwClose(Handle);
  371. //
  372. // Unterminate the current string if necessary.
  373. //
  374. if(q) {
  375. *q = L'\\';
  376. p = q+1;
  377. }
  378. } while(*p && q); // *p catches string ending in '\'
  379. SkippedFileQuit:
  380. SpMemFree(EntirePath);
  381. if( NewName )
  382. SpMemFree(NewName);
  383. return !SkippedFile;
  384. }
  385. VOID
  386. SpCreateDirStructWorker(
  387. IN PVOID SifHandle,
  388. IN PWSTR SifSection,
  389. IN PWSTR DevicePath,
  390. IN PWSTR RootDirectory,
  391. IN BOOLEAN Fatal
  392. )
  393. /*++
  394. Routine Description:
  395. Create a set of directories that are listed in a setup information file
  396. section. The expected format is as follows:
  397. [SectionName]
  398. shortname = directory
  399. shortname = directory
  400. .
  401. .
  402. .
  403. Arguments:
  404. SifHandle - supplies handle to loaded setup information file.
  405. SifSection - supplies name of section in the setup information file
  406. containing directories to be created.
  407. DevicePath - supplies pathname to the device on which the directory
  408. structure is to be created.
  409. RootDirectory - supplies a root directory, relative to which the
  410. directory structure will be created.
  411. Return Value:
  412. None. Does not return if directory structure could not be created.
  413. --*/
  414. {
  415. ULONG Count;
  416. ULONG d;
  417. PWSTR Directory;
  418. //
  419. // Count the number of directories to be created.
  420. //
  421. Count = SpCountLinesInSection(SifHandle,SifSection);
  422. if(!Count) {
  423. if(Fatal) {
  424. SpFatalSifError(SifHandle,SifSection,NULL,0,0);
  425. } else {
  426. return;
  427. }
  428. }
  429. for(d=0; d<Count; d++) {
  430. Directory = SpGetSectionLineIndex(SifHandle,SifSection,d,0);
  431. if(!Directory) {
  432. SpFatalSifError(SifHandle,SifSection,NULL,d,0);
  433. }
  434. SpCreateDirectory(DevicePath,RootDirectory,Directory,0,0);
  435. }
  436. }
  437. VOID
  438. SpCreateDirectoryStructureFromSif(
  439. IN PVOID SifHandle,
  440. IN PWSTR SifSection,
  441. IN PWSTR DevicePath,
  442. IN PWSTR RootDirectory
  443. )
  444. /*++
  445. Routine Description:
  446. Create a set of directories that are listed in a setup information file
  447. section. The expected format is as follows:
  448. [SectionName]
  449. shortname = directory
  450. shortname = directory
  451. .
  452. .
  453. .
  454. [SectionName.<platform>]
  455. shortname = directory
  456. shortname = directory
  457. .
  458. .
  459. .
  460. Arguments:
  461. SifHandle - supplies handle to loaded setup information file.
  462. SifSection - supplies name of section in the setup information file
  463. containing directories to be created.
  464. DevicePath - supplies pathname to the device on which the directory
  465. structure is to be created.
  466. RootDirectory - supplies a root directory, relative to which the
  467. directory structure will be created.
  468. Return Value:
  469. None. Does not return if directory structure could not be created.
  470. --*/
  471. {
  472. PWSTR p;
  473. //
  474. // Create the root directory.
  475. //
  476. SpCreateDirectory(DevicePath,NULL,RootDirectory,HideWinDir?FILE_ATTRIBUTE_HIDDEN:0,0);
  477. //
  478. // Create platform-indepdenent directories
  479. //
  480. SpCreateDirStructWorker(SifHandle,SifSection,DevicePath,RootDirectory,TRUE);
  481. //
  482. // Create platform-depdenent directories
  483. //
  484. p = SpMakePlatformSpecificSectionName(SifSection);
  485. if (p) {
  486. SpCreateDirStructWorker(SifHandle,p,DevicePath,RootDirectory,FALSE);
  487. SpMemFree(p);
  488. }
  489. }
  490. VOID
  491. SpGetFileVersion(
  492. IN PVOID ImageBase,
  493. OUT PULONGLONG Version
  494. )
  495. /*++
  496. Routine Description:
  497. Get the version stamp out of the VS_FIXEDFILEINFO resource in a PE
  498. image.
  499. Arguments:
  500. ImageBase - supplies the address in memory where the file is mapped in.
  501. Version - receives 64bit version number, or 0 if the file is not
  502. a PE image or has no version data.
  503. Return Value:
  504. None.
  505. --*/
  506. {
  507. PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
  508. NTSTATUS Status;
  509. ULONG_PTR IdPath[3];
  510. ULONG ResourceSize;
  511. struct {
  512. USHORT TotalSize;
  513. USHORT DataSize;
  514. USHORT Type;
  515. WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul
  516. VS_FIXEDFILEINFO FixedFileInfo;
  517. } *Resource;
  518. *Version = 0;
  519. //
  520. // Do this to prevent the Ldr routines from faulting.
  521. //
  522. ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);
  523. IdPath[0] = (ULONG_PTR)RT_VERSION;
  524. IdPath[1] = (ULONG_PTR)MAKEINTRESOURCE(VS_VERSION_INFO);
  525. IdPath[2] = 0;
  526. try {
  527. Status = LdrFindResource_U(ImageBase,IdPath,3,&DataEntry);
  528. } except(EXCEPTION_EXECUTE_HANDLER) {
  529. Status = STATUS_UNSUCCESSFUL;
  530. }
  531. if(!NT_SUCCESS(Status)) {
  532. return;
  533. }
  534. try {
  535. Status = LdrAccessResource(ImageBase,DataEntry,&Resource,&ResourceSize);
  536. } except(EXCEPTION_EXECUTE_HANDLER) {
  537. Status = STATUS_UNSUCCESSFUL;
  538. }
  539. if(!NT_SUCCESS(Status)) {
  540. return;
  541. }
  542. try {
  543. if((ResourceSize >= sizeof(*Resource)) && !_wcsicmp(Resource->Name,L"VS_VERSION_INFO")) {
  544. *Version = ((ULONGLONG)Resource->FixedFileInfo.dwFileVersionMS << 32)
  545. | (ULONGLONG)Resource->FixedFileInfo.dwFileVersionLS;
  546. } else {
  547. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Warning: invalid version resource\n"));
  548. }
  549. } except(EXCEPTION_EXECUTE_HANDLER) {
  550. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Exception encountered processing bogus version resource\n"));
  551. }
  552. }
  553. #if defined(REMOTE_BOOT)
  554. NTSTATUS
  555. SpCopyFileForRemoteBoot(
  556. IN PWSTR SourceFilename,
  557. IN PWSTR TargetFilename,
  558. IN ULONG TargetAttributes,
  559. IN ULONG Flags,
  560. OUT PULONG Checksum
  561. )
  562. /*++
  563. Routine Description:
  564. Check to see if the target file already exists in the master tree on
  565. the remote boot server, and if it does, create a single-instance store
  566. link to the existing file instead of doing the copy.
  567. Arguments:
  568. SourceFilename - supplies fully qualified name of file
  569. in the NT namespace.
  570. TargetFilename - supplies fully qualified name of file
  571. in the NT namespace.
  572. TargetAttributes - if supplied (ie, non-0) supplies the attributes
  573. to be placed on the target on successful copy (ie, readonly, etc).
  574. Flags - bit mask specifying any special treatment necessary
  575. for the file.
  576. CheckSum - checksum of the file
  577. Return Value:
  578. NT Status value indicating outcome of NtWriteFile of the data.
  579. --*/
  580. {
  581. NTSTATUS status;
  582. IO_STATUS_BLOCK ioStatusBlock;
  583. PSI_COPYFILE copyFile;
  584. ULONG copyFileSize;
  585. ULONG sourceLength;
  586. ULONG targetLength;
  587. HANDLE targetHandle;
  588. OBJECT_ATTRIBUTES objectAttributes;
  589. UNICODE_STRING unicodeString;
  590. //
  591. // If the target file is not remote, then it must be on the local system
  592. // partition, and there's no use in trying an SIS copy.
  593. //
  594. // If there is no SIS root handle, there's no handle on which to issue the
  595. // SIS FSCTL.
  596. //
  597. if ( (_wcsnicmp(TargetFilename, L"\\Device\\LanmanRedirector", 24) != 0 ) ||
  598. (SisRootHandle == NULL) ) {
  599. return STATUS_UNSUCCESSFUL;
  600. }
  601. //
  602. // Build the FSCTL command buffer.
  603. //
  604. sourceLength = (wcslen(SourceFilename) + 1) * sizeof(WCHAR);
  605. targetLength = (wcslen(TargetFilename) + 1) * sizeof(WCHAR);
  606. copyFileSize = FIELD_OFFSET(SI_COPYFILE, FileNameBuffer) + sourceLength + targetLength;
  607. copyFile = SpMemAlloc( copyFileSize );
  608. copyFile->SourceFileNameLength = sourceLength;
  609. copyFile->DestinationFileNameLength = targetLength;
  610. copyFile->Flags = COPYFILE_SIS_REPLACE;
  611. RtlCopyMemory(
  612. copyFile->FileNameBuffer,
  613. SourceFilename,
  614. sourceLength
  615. );
  616. RtlCopyMemory(
  617. copyFile->FileNameBuffer + (sourceLength / sizeof(WCHAR)),
  618. TargetFilename,
  619. targetLength
  620. );
  621. //
  622. // Invoke the SIS CopyFile FsCtrl.
  623. //
  624. status = ZwFsControlFile(
  625. SisRootHandle,
  626. NULL,
  627. NULL,
  628. NULL,
  629. &ioStatusBlock,
  630. FSCTL_SIS_COPYFILE,
  631. copyFile, // Input buffer
  632. copyFileSize, // Input buffer length
  633. NULL, // Output buffer
  634. 0 ); // Output buffer length
  635. if ( NT_SUCCESS(status) ) {
  636. //KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpCopyFileForRemoteBoot: SIS copy %ws->%ws succeeded\n", SourceFilename, TargetFilename ));
  637. //
  638. // Open the target file so that CSC knows about it and pins it.
  639. //
  640. INIT_OBJA(&objectAttributes, &unicodeString, TargetFilename);
  641. status = ZwOpenFile(
  642. &targetHandle,
  643. FILE_GENERIC_READ,
  644. &objectAttributes,
  645. &ioStatusBlock,
  646. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  647. 0
  648. );
  649. if ( NT_SUCCESS(status) ) {
  650. ZwClose(targetHandle);
  651. } else {
  652. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpCopyFileForRemoteBoot: SIS copy %ws->%ws succeeded, but open failed: %x\n", SourceFilename, TargetFilename, status ));
  653. }
  654. } else {
  655. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpCopyFileForRemoteBoot: SIS copy %ws->%ws failed: %x\n", SourceFilename, TargetFilename, status ));
  656. //
  657. // If it looks like SIS isn't active on the remote file system, close
  658. // the SIS root handle so that we can avoid repeatedly getting this
  659. // error.
  660. //
  661. // Note: NTFS returns STATUS_INVALID_PARAMETER. FAT returns
  662. // STATUS_INVALID_DEVICE_REQUEST.
  663. //
  664. if ( (status == STATUS_INVALID_PARAMETER) ||
  665. (status == STATUS_INVALID_DEVICE_REQUEST) ) {
  666. ZwClose( SisRootHandle );
  667. SisRootHandle = NULL;
  668. }
  669. }
  670. *Checksum = 0;
  671. SpMemFree( copyFile );
  672. return status;
  673. }
  674. #endif // defined(REMOTE_BOOT)
  675. NTSTATUS
  676. SpCopyFileUsingNames(
  677. IN PWSTR SourceFilename,
  678. IN PWSTR TargetFilename,
  679. IN ULONG TargetAttributes,
  680. IN ULONG Flags
  681. )
  682. /*++
  683. Routine Description:
  684. Attempt to copy or decompress a file based on filenames.
  685. Arguments:
  686. SourceFilename - supplies fully qualified name of file
  687. in the NT namespace.
  688. TargetFilename - supplies fully qualified name of file
  689. in the NT namespace.
  690. TargetAttributes - if supplied (ie, non-0) supplies the attributes
  691. to be placed on the target on successful copy (ie, readonly, etc).
  692. Flags - bit mask specifying any special treatment necessary
  693. for the file.
  694. Return Value:
  695. NT Status value indicating outcome of NtWriteFile of the data.
  696. --*/
  697. {
  698. NTSTATUS Status;
  699. HANDLE SourceHandle;
  700. HANDLE TargetHandle;
  701. BOOLEAN b;
  702. IO_STATUS_BLOCK IoStatusBlock;
  703. FILE_BASIC_INFORMATION BasicFileInfo;
  704. FILE_BASIC_INFORMATION BasicFileInfo2;
  705. BOOLEAN GotBasicInfo;
  706. ULONG FileSize;
  707. PVOID ImageBase;
  708. HANDLE SectionHandle;
  709. BOOLEAN IsCompressed;
  710. BOOLEAN InDriverCab;
  711. PWSTR TempFilename,TempSourcename;
  712. PFILE_RENAME_INFORMATION RenameFileInfo;
  713. OBJECT_ATTRIBUTES Obja;
  714. UNICODE_STRING UnicodeString;
  715. LARGE_INTEGER FileOffset;
  716. ULONGLONG SourceVersion;
  717. ULONGLONG TargetVersion;
  718. USHORT CompressionState;
  719. BOOLEAN Moved;
  720. BOOLEAN TargetExists;
  721. WCHAR SmashedSourceFilename[ACTUAL_MAX_PATH];
  722. ULONG pathSize;
  723. #if 0
  724. #ifdef _X86_
  725. BOOL bUniprocFile = FALSE;
  726. //
  727. // If this file is on the list of files whose locks need to be smashed,
  728. // copy a file who's been smashed. We do this by prepending our up
  729. // directory name infront of the filename in SourceFilename.
  730. //
  731. if((Flags & COPY_SMASHLOCKS) && !SpInstallingMp() && !RemoteSysPrepSetup) {
  732. WCHAR *char_ptr;
  733. //
  734. // Find the last '\\' in the name.
  735. //
  736. char_ptr = SourceFilename + (wcslen(SourceFilename)) - 1;
  737. while( (char_ptr > SourceFilename) &&
  738. (*char_ptr != L'\\') ) {
  739. char_ptr--;
  740. }
  741. //
  742. // Now insert our special directory name inside
  743. // the specified source file name.
  744. //
  745. if( *char_ptr == L'\\' ) {
  746. *char_ptr = 0;
  747. wcscpy( SmashedSourceFilename, SourceFilename );
  748. *char_ptr = L'\\';
  749. char_ptr++;
  750. wcscat( SmashedSourceFilename, L"\\UniProc\\" );
  751. wcscat( SmashedSourceFilename, char_ptr );
  752. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Copying:\n\t%ws\n\tinstead of:\n\t%ws\n", SmashedSourceFilename, SourceFilename));
  753. SourceFilename = SmashedSourceFilename;
  754. bUniprocFile = TRUE;
  755. } else {
  756. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Unable to generate smashed source path for %ws\n", SourceFilename));
  757. }
  758. }
  759. #endif // defined _x86_
  760. #endif // 0
  761. //
  762. // Open the source file if it's not open already.
  763. // Note that the name may not be the actual name on disk.
  764. // We also try to open the name with the _ appended.
  765. //
  766. InDriverCab = FALSE;
  767. if (RemoteSysPrepSetup && ((Flags & COPY_DECOMPRESS_SYSPREP) == 0)) {
  768. INIT_OBJA(&Obja,&UnicodeString,SourceFilename);
  769. Status = ZwCreateFile( &SourceHandle,
  770. FILE_GENERIC_READ,
  771. &Obja,
  772. &IoStatusBlock,
  773. NULL,
  774. FILE_ATTRIBUTE_NORMAL,
  775. FILE_SHARE_READ,
  776. FILE_OPEN,
  777. 0,
  778. NULL,
  779. 0
  780. );
  781. } else {
  782. if (!PrivateInfHandle && g_UpdatesSifHandle) {
  783. TempSourcename = wcsrchr(SourceFilename,L'\\');
  784. if (TempSourcename) {
  785. TempSourcename++;
  786. } else {
  787. TempSourcename = SourceFilename;
  788. }
  789. #if 0
  790. #ifdef _X86_
  791. //
  792. // If this file is on the list of files whose locks need to be smashed,
  793. // look in uniproc.cab first
  794. //
  795. if(bUniprocFile && g_UniprocSifHandle) {
  796. Status = SpOpenFileInDriverCab (
  797. TempSourcename,
  798. g_UniprocSifHandle,
  799. &SourceHandle
  800. );
  801. if (NT_SUCCESS(Status)) {
  802. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: using %ws from uniproc cab\n", TempSourcename));
  803. InDriverCab = TRUE;
  804. Flags &= ~COPY_DELETESOURCE;
  805. }
  806. }
  807. #endif // defined _X86_
  808. #endif // 0
  809. if (!InDriverCab) {
  810. //
  811. // look in updates cab first
  812. //
  813. Status = SpOpenFileInDriverCab (
  814. TempSourcename,
  815. g_UpdatesSifHandle,
  816. &SourceHandle
  817. );
  818. if (NT_SUCCESS(Status)) {
  819. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: using %ws from updates cab\n", TempSourcename));
  820. InDriverCab = TRUE;
  821. Flags &= ~COPY_DELETESOURCE;
  822. }
  823. }
  824. }
  825. if (!InDriverCab) {
  826. Status = SpOpenNameMayBeCompressed(
  827. SourceFilename,
  828. FILE_GENERIC_READ,
  829. FILE_ATTRIBUTE_NORMAL,
  830. FILE_SHARE_READ,
  831. FILE_OPEN,
  832. 0,
  833. &SourceHandle,
  834. &b
  835. );
  836. if (!NT_SUCCESS(Status)) {
  837. //
  838. // if it's not the actual name and it's not compressed, it may be in the driver cab-file
  839. //
  840. TempSourcename = wcsrchr(SourceFilename,L'\\');
  841. if (TempSourcename) {
  842. TempSourcename++;
  843. } else {
  844. TempSourcename = SourceFilename;
  845. }
  846. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: temp source name: %ws\n", TempSourcename));
  847. Status = SpOpenFileInDriverCab(
  848. TempSourcename,
  849. NULL,
  850. &SourceHandle
  851. );
  852. InDriverCab = TRUE;
  853. }
  854. }
  855. }
  856. if(!NT_SUCCESS(Status)) {
  857. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: Unable to open source file %ws (%x)\n",SourceFilename,Status));
  858. return(Status);
  859. }
  860. //
  861. // Gather basic file info about the file. We only use the timestamp info.
  862. // If this fails this isn't fatal (we assume that if this fails, then
  863. // the copy will also fail; it not, the worst case is that the timestamps
  864. // might be wrong).
  865. //
  866. Status = ZwQueryInformationFile(
  867. SourceHandle,
  868. &IoStatusBlock,
  869. &BasicFileInfo,
  870. sizeof(BasicFileInfo),
  871. FileBasicInformation
  872. );
  873. if(NT_SUCCESS(Status)) {
  874. GotBasicInfo = TRUE;
  875. } else {
  876. GotBasicInfo = FALSE;
  877. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: Warning: unable to get basic file info for %ws (%x)\n",SourceFilename,Status));
  878. }
  879. //
  880. // Get the source file size, map in the file, and determine whether it's compressed.
  881. //
  882. Status = SpGetFileSize(SourceHandle,&FileSize);
  883. if(!NT_SUCCESS(Status)) {
  884. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to get size of %ws (%x)\n",SourceFilename,Status));
  885. if (!InDriverCab) {
  886. ZwClose(SourceHandle);
  887. }
  888. return(Status);
  889. }
  890. if( FileSize == 0 ) {
  891. //
  892. // We'll soon indirectly call ZwCreateSection with a zero length.
  893. // This will fail, so let's deal with zero-length files up here so
  894. // they actually get copied.
  895. //
  896. // We know a couple of things that make our job much easier.
  897. // 1. We don't need to actually copy any data, just create an empty
  898. // file.
  899. // 2. The source file isn't compressed, so don't worry about
  900. // decompressing/renaming (by defintion, the smallest compressed
  901. // file is non-zero).
  902. //
  903. INIT_OBJA(&Obja,&UnicodeString,TargetFilename);
  904. Status = ZwCreateFile( &TargetHandle,
  905. FILE_GENERIC_WRITE,
  906. &Obja,
  907. &IoStatusBlock,
  908. NULL,
  909. FILE_ATTRIBUTE_NORMAL,
  910. 0, // no sharing
  911. FILE_OVERWRITE_IF,
  912. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  913. NULL,
  914. 0
  915. );
  916. if( NT_SUCCESS(Status) ) {
  917. //
  918. // if the source is off of a sysprep image, then we need to copy
  919. // EAs and alternate data streams too. we do this before setting
  920. // attributes so that read only bit isn't set.
  921. // Only do this if we're not grabbing additional drivers from the
  922. // flat image.
  923. //
  924. if (RemoteSysPrepSetup && ((Flags & COPY_DECOMPRESS_SYSPREP) == 0)) {
  925. Status = SpCopyEAsAndStreams( SourceFilename,
  926. SourceHandle,
  927. TargetFilename,
  928. TargetHandle,
  929. FALSE );
  930. }
  931. if ( NT_SUCCESS(Status) ) {
  932. //
  933. // Try and set attributes on target.
  934. //
  935. BasicFileInfo.FileAttributes = TargetAttributes;
  936. ZwSetInformationFile(
  937. TargetHandle,
  938. &IoStatusBlock,
  939. &BasicFileInfo,
  940. sizeof(BasicFileInfo),
  941. FileBasicInformation
  942. );
  943. }
  944. //
  945. // Close target file
  946. //
  947. ZwClose( TargetHandle );
  948. //
  949. // Do we need to delete Source?
  950. //
  951. if( (Flags & COPY_DELETESOURCE) && !RemoteSysPrepSetup && !InDriverCab) {
  952. ZwClose(SourceHandle);
  953. SourceHandle = NULL;
  954. SpDeleteFile(SourceFilename,NULL,NULL);
  955. }
  956. }
  957. else {
  958. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: Failed to create zero-length file %ws\n",TargetFilename));
  959. }
  960. //
  961. // Clean up this guy since we won't be needing him anymore.
  962. //
  963. if (SourceHandle != NULL) {
  964. if( !InDriverCab ) {
  965. ZwClose(SourceHandle);
  966. }
  967. }
  968. if (RemoteSysPrepSetup &&
  969. NT_SUCCESS(Status) &&
  970. ((Flags & COPY_DECOMPRESS_SYSPREP) == 0)) {
  971. Status = SpSysPrepSetExtendedInfo( SourceFilename,
  972. TargetFilename,
  973. FALSE,
  974. FALSE );
  975. }
  976. return(Status);
  977. }
  978. Status = SpMapEntireFile(SourceHandle,&SectionHandle,&ImageBase,FALSE);
  979. if(!NT_SUCCESS(Status)) {
  980. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to map file %ws (%x)\n",SourceFilename,Status));
  981. if (!InDriverCab) {
  982. ZwClose(SourceHandle);
  983. }
  984. return(Status);
  985. }
  986. //
  987. // If we were told not to decompress, then treat any file like it is
  988. // uncompressed.
  989. //
  990. if (Flags & COPY_NODECOMP) {
  991. IsCompressed = FALSE;
  992. } else {
  993. if (InDriverCab) {
  994. IsCompressed = TRUE;
  995. } else {
  996. IsCompressed = SpdIsCompressed(ImageBase,FileSize);
  997. }
  998. }
  999. //
  1000. // Create a temporary filename to be used for the target.
  1001. //
  1002. pathSize = (wcslen(TargetFilename)+12) * sizeof(WCHAR);
  1003. TempFilename = SpMemAlloc(pathSize);
  1004. wcscpy(TempFilename,TargetFilename);
  1005. wcscpy(wcsrchr(TempFilename,L'\\')+1,L"$$TEMP$$.~~~");
  1006. //
  1007. // Allocate some space for the rename buffer.
  1008. //
  1009. RenameFileInfo = SpMemAlloc(sizeof(FILE_RENAME_INFORMATION) + pathSize );
  1010. //
  1011. // Create the temporary file. We first try to do this via a move
  1012. // if the source isn't compressed and we're going to delete the source file.
  1013. //
  1014. if (!IsCompressed && (Flags & COPY_DELETESOURCE) && !RemoteSysPrepSetup) {
  1015. RenameFileInfo->ReplaceIfExists = TRUE;
  1016. RenameFileInfo->RootDirectory = NULL;
  1017. RenameFileInfo->FileNameLength = wcslen(TempFilename)*sizeof(WCHAR);
  1018. wcscpy(RenameFileInfo->FileName,TempFilename);
  1019. Status = ZwSetInformationFile(
  1020. SourceHandle,
  1021. &IoStatusBlock,
  1022. RenameFileInfo,
  1023. sizeof(FILE_RENAME_INFORMATION) + RenameFileInfo->FileNameLength,
  1024. FileRenameInformation
  1025. );
  1026. Moved = TRUE;
  1027. } else {
  1028. //
  1029. // Force us to fall into the copy case below.
  1030. //
  1031. Status = STATUS_UNSUCCESSFUL;
  1032. }
  1033. INIT_OBJA(&Obja,&UnicodeString,TempFilename);
  1034. if(!NT_SUCCESS(Status)) {
  1035. Moved = FALSE;
  1036. //
  1037. // OK, move failed, try decompress/copy instead.
  1038. // Start by creating the temporary file.
  1039. //
  1040. Status = ZwCreateFile(
  1041. &TargetHandle,
  1042. FILE_GENERIC_WRITE,
  1043. &Obja,
  1044. &IoStatusBlock,
  1045. NULL,
  1046. FILE_ATTRIBUTE_NORMAL,
  1047. 0, // no sharing
  1048. FILE_OVERWRITE_IF,
  1049. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  1050. NULL,
  1051. 0
  1052. );
  1053. if(NT_SUCCESS(Status)) {
  1054. if(IsCompressed &&
  1055. ( (!RemoteSysPrepSetup) ||
  1056. ((Flags & COPY_DECOMPRESS_SYSPREP) != 0))) {
  1057. if (InDriverCab) {
  1058. USHORT RealFileTime,RealFileDate;
  1059. LARGE_INTEGER RealTime;
  1060. ASSERT (TempSourcename != NULL );
  1061. //
  1062. // remove the file from the driver cab...
  1063. //
  1064. Status = SpdDecompressFileFromDriverCab(
  1065. TempSourcename,
  1066. ImageBase,
  1067. FileSize,
  1068. TargetHandle,
  1069. &RealFileDate,
  1070. &RealFileTime );
  1071. //
  1072. // ...now update the basic file information filetime...
  1073. //
  1074. if (GotBasicInfo) {
  1075. SpTimeFromDosTime(RealFileDate,RealFileTime,&RealTime);
  1076. BasicFileInfo.CreationTime = RealTime;
  1077. }
  1078. } else{
  1079. Status = SpdDecompressFile(ImageBase,FileSize,TargetHandle);
  1080. }
  1081. } else {
  1082. ULONG remainingLength;
  1083. ULONG writeLength;
  1084. PUCHAR base;
  1085. //
  1086. // Guard the write with a try/except because if there is an i/o error,
  1087. // memory management will raise an in-page exception.
  1088. //
  1089. FileOffset.QuadPart = 0;
  1090. base = ImageBase;
  1091. remainingLength = FileSize;
  1092. try {
  1093. while (remainingLength != 0) {
  1094. writeLength = 60 * 1024;
  1095. if (writeLength > remainingLength) {
  1096. writeLength = remainingLength;
  1097. }
  1098. Status = ZwWriteFile(
  1099. TargetHandle,
  1100. NULL,
  1101. NULL,
  1102. NULL,
  1103. &IoStatusBlock,
  1104. base,
  1105. writeLength,
  1106. &FileOffset,
  1107. NULL
  1108. );
  1109. base += writeLength;
  1110. FileOffset.LowPart += writeLength;
  1111. remainingLength -= writeLength;
  1112. if (!NT_SUCCESS(Status)) {
  1113. break;
  1114. }
  1115. }
  1116. } except(EXCEPTION_EXECUTE_HANDLER) {
  1117. Status = STATUS_IN_PAGE_ERROR;
  1118. }
  1119. }
  1120. //
  1121. // if the source is off of a sysprep image, then we need to copy
  1122. // EAs and alternate data streams too.
  1123. //
  1124. if ( NT_SUCCESS(Status) &&
  1125. RemoteSysPrepSetup &&
  1126. ((Flags & COPY_DECOMPRESS_SYSPREP) == 0)) {
  1127. Status = SpCopyEAsAndStreams( SourceFilename,
  1128. SourceHandle,
  1129. TargetFilename,
  1130. TargetHandle,
  1131. FALSE );
  1132. }
  1133. ZwClose(TargetHandle);
  1134. }
  1135. }
  1136. SpUnmapFile(SectionHandle,ImageBase);
  1137. if (!InDriverCab) {
  1138. ZwClose(SourceHandle);
  1139. }
  1140. if(!NT_SUCCESS(Status)) {
  1141. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to create temporary file %ws (%x)\n",TempFilename,Status));
  1142. SpMemFree(TempFilename);
  1143. SpMemFree(RenameFileInfo);
  1144. return(Status);
  1145. }
  1146. //
  1147. // At this point we have a temporary target file that is now the source.
  1148. // Open the file, map it in, and get its version.
  1149. //
  1150. Status = ZwCreateFile(
  1151. &SourceHandle,
  1152. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  1153. &Obja,
  1154. &IoStatusBlock,
  1155. NULL,
  1156. 0, // don't bother with attributes
  1157. 0, // no sharing
  1158. FILE_OPEN,
  1159. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1160. NULL,
  1161. 0
  1162. );
  1163. if((Status == STATUS_ACCESS_DENIED) && Moved) {
  1164. //
  1165. // The only way this could have happened is if the source file
  1166. // is uncompressed and the delete-source flag is set, since in
  1167. // that case we could have moved the source file to the temp file.
  1168. // In any other case we would have created the temp file by copying,
  1169. // and there's no problem reopening the file since we just created
  1170. // and closed it ourselves, above.
  1171. //
  1172. // Reset attributes and try again. The file might have been read-only.
  1173. // This can happen when doing a winnt32 directly from a CD since the
  1174. // RO attribute of files from the CD are preserved.
  1175. //
  1176. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpCopyFileUsingNames: for file %ws, can't reopen temp file (access deined), trying again\n",SourceFilename));
  1177. Status = ZwCreateFile(
  1178. &SourceHandle,
  1179. FILE_WRITE_ATTRIBUTES,
  1180. &Obja,
  1181. &IoStatusBlock,
  1182. NULL,
  1183. 0, // don't bother with attributes
  1184. FILE_SHARE_WRITE,
  1185. FILE_OPEN,
  1186. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1187. NULL,
  1188. 0
  1189. );
  1190. if(NT_SUCCESS(Status)) {
  1191. RtlZeroMemory(&BasicFileInfo2,sizeof(BasicFileInfo2));
  1192. BasicFileInfo2.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1193. Status = ZwSetInformationFile(
  1194. SourceHandle,
  1195. &IoStatusBlock,
  1196. &BasicFileInfo2,
  1197. sizeof(BasicFileInfo2),
  1198. FileBasicInformation
  1199. );
  1200. ZwClose(SourceHandle);
  1201. if(NT_SUCCESS(Status)) {
  1202. Status = ZwCreateFile(
  1203. &SourceHandle,
  1204. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  1205. &Obja,
  1206. &IoStatusBlock,
  1207. NULL,
  1208. 0, // don't bother with attributes
  1209. 0, // no sharing
  1210. FILE_OPEN,
  1211. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1212. NULL,
  1213. 0
  1214. );
  1215. }
  1216. }
  1217. }
  1218. //
  1219. // Read-only failured win out over sharing violations -- ie, we'll get back
  1220. // ACCESS_DEINED first for files that are both RO and in-use. So break out
  1221. // this block so it gets executed even if we tried again above because the
  1222. // file might be read-only.
  1223. //
  1224. if((Status == STATUS_SHARING_VIOLATION) && Moved) {
  1225. //
  1226. // The only way this can happen is if the source file is uncompressed
  1227. // and the delete-source flag is set. In this case we renamed the file
  1228. // to the temp filename and now we can't open it for write.
  1229. // In any other case we would have created the temp file by copying,
  1230. // and so there's no problem opening the file since we just closed it.
  1231. //
  1232. // Rename the temp file back to the source file and try again without
  1233. // the delete source flag set. This forces a copy instead of a move.
  1234. // The rename better work or else we're completely hosed -- because
  1235. // there's a file we can't overwrite with the name we want to use for
  1236. // the temp file for all our copy operations!
  1237. //
  1238. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpCopyFileUsingNames: temporary file %ws is in use -- trying recursive call\n",TempFilename));
  1239. Status = SpRenameFile(TempFilename,SourceFilename,FALSE);
  1240. if(!NT_SUCCESS(Status)) {
  1241. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpCopyFileUsingNames: unable to restore temp file to %ws (%x)\n",SourceFilename,Status));
  1242. }
  1243. SpMemFree(TempFilename);
  1244. SpMemFree(RenameFileInfo);
  1245. if(NT_SUCCESS(Status)) {
  1246. Status = SpCopyFileUsingNames(
  1247. SourceFilename,
  1248. TargetFilename,
  1249. TargetAttributes,
  1250. Flags & ~COPY_DELETESOURCE
  1251. );
  1252. }
  1253. return(Status);
  1254. }
  1255. if(!NT_SUCCESS(Status)) {
  1256. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to reopen temporary file %ws (%x)\n",TempFilename,Status));
  1257. if(Moved) {
  1258. SpRenameFile(TempFilename,SourceFilename,FALSE);
  1259. }
  1260. SpMemFree(TempFilename);
  1261. SpMemFree(RenameFileInfo);
  1262. return(Status);
  1263. }
  1264. Status = SpGetFileSize(SourceHandle,&FileSize);
  1265. if(!NT_SUCCESS(Status)) {
  1266. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to get size of %ws (%x)\n",TempFilename,Status));
  1267. ZwClose(SourceHandle);
  1268. if(Moved) {
  1269. SpRenameFile(TempFilename,SourceFilename,FALSE);
  1270. }
  1271. SpMemFree(TempFilename);
  1272. SpMemFree(RenameFileInfo);
  1273. return(Status);
  1274. }
  1275. Status = SpMapEntireFile(SourceHandle,&SectionHandle,&ImageBase,FALSE);
  1276. if(!NT_SUCCESS(Status)) {
  1277. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to map file %ws (%x)\n",TempFilename,Status));
  1278. ZwClose(SourceHandle);
  1279. if(Moved) {
  1280. SpRenameFile(TempFilename,SourceFilename,FALSE);
  1281. }
  1282. SpMemFree(TempFilename);
  1283. SpMemFree(RenameFileInfo);
  1284. return(Status);
  1285. }
  1286. SpGetFileVersion(ImageBase,&SourceVersion);
  1287. SpUnmapFile(SectionHandle,ImageBase);
  1288. //
  1289. // See if the target file is there by attempting to open it.
  1290. // If the file is there, get its version.
  1291. //
  1292. INIT_OBJA(&Obja,&UnicodeString,TargetFilename);
  1293. Status = ZwCreateFile(
  1294. &TargetHandle,
  1295. FILE_GENERIC_READ,
  1296. &Obja,
  1297. &IoStatusBlock,
  1298. NULL,
  1299. 0, // don't bother with attributes
  1300. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1301. FILE_OPEN, // open if exists, fail if not
  1302. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1303. NULL,
  1304. 0
  1305. );
  1306. TargetVersion = 0;
  1307. if(NT_SUCCESS(Status)) {
  1308. TargetExists = TRUE;
  1309. //
  1310. // If we're supposed to ignore versions, then keep the
  1311. // target version at 0. This will guarantee that we'll overwrite
  1312. // the target. We use the source filename here because it
  1313. // allows more flexibility (such as with HALs, which all have
  1314. // different source names but the same target name).
  1315. //
  1316. if(!(Flags & COPY_NOVERSIONCHECK)) {
  1317. Status = SpGetFileSize(TargetHandle,&FileSize);
  1318. if(NT_SUCCESS(Status)) {
  1319. Status = SpMapEntireFile(TargetHandle,&SectionHandle,&ImageBase,FALSE);
  1320. if(NT_SUCCESS(Status)) {
  1321. SpGetFileVersion(ImageBase,&TargetVersion);
  1322. SpUnmapFile(SectionHandle,ImageBase);
  1323. } else {
  1324. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: warning: unable to map file %ws (%x)\n",TargetFilename,Status));
  1325. }
  1326. } else {
  1327. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: warning: unable to get size of file %ws (%x)\n",TargetFilename,Status));
  1328. }
  1329. }
  1330. ZwClose(TargetHandle);
  1331. } else {
  1332. TargetExists = FALSE;
  1333. }
  1334. //
  1335. // OK, now we have a temporary source file and maybe an existing
  1336. // target file, and version numbers for both. We will replace or create
  1337. // the target file if:
  1338. //
  1339. // - The target file doesn't have version data (this also catches the case
  1340. // where the target file didn't exist)
  1341. //
  1342. // - The source version is newer than or equal to the target version.
  1343. //
  1344. // So that means we *won't* replace the target file only if both source and
  1345. // target have version info and the source is older than the target.
  1346. //
  1347. // If the target version is 0 then the source version is always >= the target
  1348. // so one simple test does everything we want.
  1349. //
  1350. #if 0
  1351. if(SourceVersion >= TargetVersion) {
  1352. #else
  1353. //
  1354. // Quit version-checking. We need to install a stable OS. If we
  1355. // version check, then we never know what we're going to end up with.
  1356. //
  1357. if(1) {
  1358. #endif // if 0
  1359. //
  1360. // Delete the existing target in preparation.
  1361. //
  1362. if(TargetExists) {
  1363. SpDeleteFile(TargetFilename,NULL,NULL);
  1364. }
  1365. //
  1366. // Rename temp file to actual target file.
  1367. //
  1368. RenameFileInfo->ReplaceIfExists = TRUE;
  1369. RenameFileInfo->RootDirectory = NULL;
  1370. RenameFileInfo->FileNameLength = wcslen(TargetFilename)*sizeof(WCHAR);
  1371. ASSERT( RenameFileInfo->FileNameLength < pathSize );
  1372. wcscpy(RenameFileInfo->FileName,TargetFilename);
  1373. Status = ZwSetInformationFile(
  1374. SourceHandle,
  1375. &IoStatusBlock,
  1376. RenameFileInfo,
  1377. sizeof(FILE_RENAME_INFORMATION) + RenameFileInfo->FileNameLength,
  1378. FileRenameInformation
  1379. );
  1380. SpMemFree(RenameFileInfo);
  1381. if(!NT_SUCCESS(Status)) {
  1382. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to rename temp file to target %ws (%x)\n",TargetFilename,Status));
  1383. ZwClose(SourceHandle);
  1384. if(Moved) {
  1385. SpRenameFile(TempFilename,SourceFilename,FALSE);
  1386. }
  1387. SpMemFree(TempFilename);
  1388. return(Status);
  1389. }
  1390. //
  1391. // If necessary, check if destination file is using NTFS compression, and
  1392. // if so, uncompress it.
  1393. //
  1394. if(NT_SUCCESS(Status) && (Flags & COPY_FORCENOCOMP)) {
  1395. Status = ZwQueryInformationFile(
  1396. SourceHandle,
  1397. &IoStatusBlock,
  1398. &BasicFileInfo2,
  1399. sizeof(BasicFileInfo2),
  1400. FileBasicInformation
  1401. );
  1402. if(!NT_SUCCESS(Status)) {
  1403. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to get basic file info on %ws (%x)\n",TargetFilename,Status));
  1404. ZwClose(SourceHandle);
  1405. if(Moved) {
  1406. SpRenameFile(TempFilename,SourceFilename,FALSE);
  1407. }
  1408. SpMemFree(TempFilename);
  1409. return(Status);
  1410. }
  1411. if(BasicFileInfo2.FileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
  1412. CompressionState = 0;
  1413. Status = ZwFsControlFile(
  1414. SourceHandle,
  1415. NULL,
  1416. NULL,
  1417. NULL,
  1418. &IoStatusBlock,
  1419. FSCTL_SET_COMPRESSION,
  1420. &CompressionState,
  1421. sizeof(CompressionState),
  1422. NULL,
  1423. 0
  1424. );
  1425. if(!NT_SUCCESS(Status)) {
  1426. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFileUsingNames: unable to make %ws uncompressed (%lx)\n",TargetFilename,Status));
  1427. ZwClose(SourceHandle);
  1428. if(Moved) {
  1429. SpRenameFile(TempFilename,SourceFilename,FALSE);
  1430. }
  1431. SpMemFree(TempFilename);
  1432. return(Status);
  1433. }
  1434. }
  1435. }
  1436. SpMemFree(TempFilename);
  1437. //
  1438. // Delete the source if necessary. If the source is not
  1439. // compressed and the deletesource flag is set, then we moved
  1440. // the source file and so the source file is already gone.
  1441. //
  1442. if(IsCompressed && (Flags & COPY_DELETESOURCE) && !RemoteSysPrepSetup && !InDriverCab) {
  1443. PWSTR compname;
  1444. //
  1445. // Assume that the source name is on its compressed form, and attempt to
  1446. // delete this file.
  1447. //
  1448. compname = SpGenerateCompressedName(SourceFilename);
  1449. Status = SpDeleteFile(compname,NULL,NULL);
  1450. SpMemFree(compname);
  1451. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  1452. //
  1453. // If we couldn't delete the file with the compressed name, then the file name
  1454. // was probably on its uncompressed format.
  1455. //
  1456. SpDeleteFile(SourceFilename,NULL,NULL);
  1457. }
  1458. }
  1459. //
  1460. // Apply attributes and timestamp.
  1461. // Ignore errors.
  1462. //
  1463. if(!GotBasicInfo) {
  1464. RtlZeroMemory(&BasicFileInfo,sizeof(BasicFileInfo));
  1465. }
  1466. //
  1467. // Set the file attributes. Note that if the caller didn't specify any,
  1468. // then 0 value will tell the I/O system to leave the attributes alone.
  1469. //
  1470. BasicFileInfo.FileAttributes = TargetAttributes;
  1471. ZwSetInformationFile(
  1472. SourceHandle,
  1473. &IoStatusBlock,
  1474. &BasicFileInfo,
  1475. sizeof(BasicFileInfo),
  1476. FileBasicInformation
  1477. );
  1478. ZwClose(SourceHandle);
  1479. Status = STATUS_SUCCESS;
  1480. } else {
  1481. //
  1482. // Delete the temporary source.
  1483. //
  1484. ZwClose(SourceHandle);
  1485. SpDeleteFile(TempFilename,NULL,NULL);
  1486. SpMemFree(TempFilename);
  1487. SpMemFree(RenameFileInfo);
  1488. Status = STATUS_SUCCESS;
  1489. }
  1490. if (RemoteSysPrepSetup &&
  1491. NT_SUCCESS(Status) &&
  1492. ((Flags & COPY_DECOMPRESS_SYSPREP) == 0)) {
  1493. Status = SpSysPrepSetExtendedInfo( SourceFilename,
  1494. TargetFilename,
  1495. FALSE,
  1496. FALSE );
  1497. }
  1498. return(Status);
  1499. }
  1500. VOID
  1501. SpValidateAndChecksumFile(
  1502. IN HANDLE FileHandle, OPTIONAL
  1503. IN PWSTR Filename, OPTIONAL
  1504. OUT PBOOLEAN IsNtImage,
  1505. OUT PULONG Checksum,
  1506. OUT PBOOLEAN Valid
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Calculate a checksum value for a file using the standard
  1511. nt image checksum method. If the file is an nt image, validate
  1512. the image using the partial checksum in the image header. If the
  1513. file is not an nt image, it is simply defined as valid.
  1514. If we encounter an i/o error while checksumming, then the file
  1515. is declared invalid.
  1516. Arguments:
  1517. FileHandle - supplies handle of file to check (if not present, then
  1518. Filename specifies the file to be opened and checked)
  1519. Filename - supplies full NT path of file to check (if not present, then
  1520. FileHandle must be specified)
  1521. IsNtImage = Receives flag indicating whether the file is an
  1522. NT image file.
  1523. Checksum - receives 32-bit checksum value.
  1524. Valid - receives flag indicating whether the file is a valid
  1525. image (for nt images) and that we can read the image.
  1526. Return Value:
  1527. None.
  1528. --*/
  1529. {
  1530. NTSTATUS Status;
  1531. PVOID BaseAddress;
  1532. ULONG FileSize;
  1533. HANDLE hFile = FileHandle, hSection;
  1534. PIMAGE_NT_HEADERS NtHeaders;
  1535. ULONG HeaderSum;
  1536. //
  1537. // Assume not an image and failure.
  1538. //
  1539. *IsNtImage = FALSE;
  1540. *Checksum = 0;
  1541. *Valid = FALSE;
  1542. //
  1543. // Open and map the file for read access.
  1544. //
  1545. Status = SpOpenAndMapFile(
  1546. Filename,
  1547. &hFile,
  1548. &hSection,
  1549. &BaseAddress,
  1550. &FileSize,
  1551. FALSE
  1552. );
  1553. if(!NT_SUCCESS(Status)) {
  1554. return;
  1555. }
  1556. NtHeaders = SpChecksumMappedFile(BaseAddress,FileSize,&HeaderSum,Checksum);
  1557. //
  1558. // If the file is not an image and we got this far (as opposed to encountering
  1559. // an i/o error) then the checksum is declared valid. If the file is an image,
  1560. // then its checksum may or may not be valid.
  1561. //
  1562. if(NtHeaders) {
  1563. *IsNtImage = TRUE;
  1564. *Valid = HeaderSum ? (*Checksum == HeaderSum) : TRUE;
  1565. } else {
  1566. *Valid = TRUE;
  1567. }
  1568. SpUnmapFile(hSection,BaseAddress);
  1569. if(!FileHandle) {
  1570. ZwClose(hFile);
  1571. }
  1572. }
  1573. VOID
  1574. SpCopyFileWithRetry(
  1575. IN PFILE_TO_COPY FileToCopy,
  1576. IN PWSTR SourceDevicePath,
  1577. IN PWSTR DirectoryOnSourceDevice,
  1578. IN PWSTR SourceDirectory, OPTIONAL
  1579. IN PWSTR TargetRoot, OPTIONAL
  1580. IN ULONG TargetFileAttributes, OPTIONAL
  1581. IN PCOPY_DRAW_ROUTINE DrawScreen,
  1582. IN PULONG FileCheckSum, OPTIONAL
  1583. IN PBOOLEAN FileSkipped, OPTIONAL
  1584. IN ULONG Flags
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. This routine copies a single file, allowing retry is an error occurs
  1589. during the copy. If the source file is LZ compressed, then it will
  1590. be decompressed as it is copied to the target.
  1591. If the file is not successfully copied, the user has the option
  1592. to retry to copy or to skip copying that file after a profuse warning
  1593. about how dangerous that is.
  1594. Arguments:
  1595. FileToCopy - supplies structure giving information about the file
  1596. being copied.
  1597. SourceDevicePath - supplies path to device on which the source media
  1598. is mounted (ie, \device\floppy0, \device\cdrom0, etc).
  1599. DirectoryOnSourceDevice - Supplies the directory on the source where
  1600. the file is to be found.
  1601. TargetRoot - if specified, supplies the directory on the target
  1602. to which the file is to be copied.
  1603. TargetFileAttributes - if supplied (ie, non-0) supplies the attributes
  1604. to be placed on the target on successful copy (ie, readonly, etc).
  1605. If not specified, the attributes will be set to FILE_ATTRIBUTE_NORMAL.
  1606. DrawScreen - supplies address of a routine to be called to refresh
  1607. the screen.
  1608. FileCheckSum - if specified, will contain the check sum of the file copied.
  1609. FileSkipped - if specified, will inform the caller if there was no attempt
  1610. to copy the file.
  1611. Flags - supplies flags to control special processing for this file, such as
  1612. deleting the source file on successful copy or skip; smashing locks;
  1613. specifying that the source file is oem; or to indicate that en oem file
  1614. with the same name should be overwritten on upgrade. This value is ORed
  1615. in with the Flags field of FileToCopy.
  1616. Return Value:
  1617. None.
  1618. --*/
  1619. {
  1620. PWSTR p = TemporaryBuffer;
  1621. PWSTR FullSourceName,FullTargetName;
  1622. NTSTATUS Status;
  1623. ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  1624. BOOLEAN IsNtImage,IsValid;
  1625. ULONG Checksum;
  1626. BOOLEAN Failure;
  1627. ULONG MsgId;
  1628. BOOLEAN DoCopy;
  1629. ULONG CopyFlags;
  1630. BOOLEAN PreinstallRememberFile;
  1631. //
  1632. // Form the full NT path of the source file.
  1633. //
  1634. wcscpy(p,SourceDevicePath);
  1635. SpConcatenatePaths(p,DirectoryOnSourceDevice);
  1636. if(SourceDirectory) {
  1637. SpConcatenatePaths(p,SourceDirectory);
  1638. }
  1639. SpConcatenatePaths(p,FileToCopy->SourceFilename);
  1640. FullSourceName = SpDupStringW(p);
  1641. //
  1642. // Form the full NT path of the target file.
  1643. //
  1644. wcscpy(p,FileToCopy->TargetDevicePath);
  1645. if(TargetRoot) {
  1646. SpConcatenatePaths(p,TargetRoot);
  1647. }
  1648. SpConcatenatePaths(p,FileToCopy->TargetDirectory);
  1649. //
  1650. // On an OEM preinstall, if the target name is a long name, then use
  1651. // the short name as a target name, and later on, if the copy succeeds,
  1652. // add the file to RenameList, so that it can be added to $$rename.txt
  1653. //
  1654. if( !PreInstall ||
  1655. ( wcslen( FileToCopy->TargetFilename ) <= 8 + 1 + 3 ) ) {
  1656. SpConcatenatePaths(p,FileToCopy->TargetFilename);
  1657. PreinstallRememberFile = FALSE;
  1658. } else {
  1659. SpConcatenatePaths(p,FileToCopy->SourceFilename);
  1660. PreinstallRememberFile = TRUE;
  1661. }
  1662. FullTargetName = SpDupStringW(p);
  1663. //
  1664. // Call out to the draw screen routine to indicate that
  1665. // a new file is being copied.
  1666. //
  1667. DrawScreen(FullSourceName,FullTargetName,FALSE);
  1668. //
  1669. // Build up the copy flags value.
  1670. //
  1671. CopyFlags = Flags | FileToCopy->Flags;
  1672. do {
  1673. DoCopy = TRUE;
  1674. //
  1675. // Check the copy options field. The valid values here are
  1676. //
  1677. // - COPY_ALWAYS
  1678. // - COPY_ONLY_IF_PRESENT
  1679. // - COPY_ONLY_IF_NOT_PRESENT
  1680. // - COPY_NEVER
  1681. switch(CopyFlags & COPY_DISPOSITION_MASK) {
  1682. case COPY_ONLY_IF_PRESENT:
  1683. DoCopy = SpFileExists(FullTargetName, FALSE);
  1684. break;
  1685. case COPY_ONLY_IF_NOT_PRESENT:
  1686. DoCopy = !SpFileExists(FullTargetName, FALSE);
  1687. break;
  1688. case COPY_NEVER:
  1689. DoCopy = FALSE;
  1690. case COPY_ALWAYS:
  1691. default:
  1692. break;
  1693. }
  1694. if(!DoCopy) {
  1695. break;
  1696. }
  1697. //
  1698. // In the upgrade case, check if the file being copied
  1699. // replaces a third party file.
  1700. // If it does, then ask what the user wants to do about it
  1701. //
  1702. if( !RepairWinnt &&
  1703. ( NTUpgrade == UpgradeFull ) &&
  1704. SpFileExists(FullTargetName, FALSE) ) {
  1705. //
  1706. // If necessary ask the user if he wants to overwrite the file.
  1707. // Otherwise go ahead and copy the file.
  1708. //
  1709. if(!(CopyFlags & COPY_OVERWRITEOEMFILE)) {
  1710. PWSTR TmpFilePath;
  1711. BOOLEAN OverwriteFile;
  1712. if(( TargetRoot == NULL ) ||
  1713. ( wcslen( FileToCopy->TargetDirectory ) == 0 ) ) {
  1714. wcscpy( p, FileToCopy->TargetFilename );
  1715. } else {
  1716. wcscpy( p, TargetRoot );
  1717. SpConcatenatePaths( p, FileToCopy->TargetDirectory );
  1718. SpConcatenatePaths(p,FileToCopy->TargetFilename);
  1719. }
  1720. TmpFilePath = SpDupStringW(p);
  1721. OverwriteFile = TRUE;
  1722. if( ( (CopyFlags & COPY_SOURCEISOEM) == 0 ) &&
  1723. SppIsFileLoggedAsOemFile( TmpFilePath ) ) {
  1724. if( !UnattendedOperation ) {
  1725. ULONG ValidKeys[3] = { ASCI_CR, ASCI_ESC, 0 };
  1726. BOOLEAN ActionSelected = FALSE;
  1727. // ULONG Mnemonics[] = { MnemonicOverwrite, 0 };
  1728. //
  1729. // Warn user that existing file is a third party file,
  1730. // and ask if user wants to over write the file
  1731. //
  1732. while( !ActionSelected ) {
  1733. SpStartScreen(
  1734. SP_SCRN_OVERWRITE_OEM_FILE,
  1735. 3,
  1736. HEADER_HEIGHT+1,
  1737. FALSE,
  1738. FALSE,
  1739. DEFAULT_ATTRIBUTE,
  1740. FileToCopy->TargetFilename
  1741. );
  1742. SpDisplayStatusOptions(
  1743. DEFAULT_STATUS_ATTRIBUTE,
  1744. SP_STAT_ENTER_EQUALS_REPLACE_FILE,
  1745. SP_STAT_ESC_EQUALS_SKIP_FILE,
  1746. 0
  1747. );
  1748. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1749. case ASCI_CR: // don't overwrite
  1750. OverwriteFile = TRUE;
  1751. ActionSelected = TRUE;
  1752. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: OEM file %ls, will be overwritten.\n", FullTargetName ));
  1753. break;
  1754. case ASCI_ESC: // skip file
  1755. OverwriteFile = FALSE;
  1756. ActionSelected = TRUE;
  1757. break;
  1758. }
  1759. }
  1760. //
  1761. // Need to completely repaint gauge, etc.
  1762. //
  1763. DrawScreen(FullSourceName,FullTargetName,TRUE);
  1764. } else {
  1765. //
  1766. // On unattended upgrade, do what is in the script file
  1767. //
  1768. OverwriteFile = UnattendedOverwriteOem;
  1769. }
  1770. }
  1771. SpMemFree( TmpFilePath );
  1772. if( !OverwriteFile ) {
  1773. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: OEM file %ls, will not be overwritten.\n", FullTargetName ));
  1774. if( ARGUMENT_PRESENT( FileSkipped ) ) {
  1775. *FileSkipped = TRUE;
  1776. }
  1777. //
  1778. // Free the source and target filenames.
  1779. //
  1780. SpMemFree(FullSourceName);
  1781. SpMemFree(FullTargetName);
  1782. return;
  1783. }
  1784. }
  1785. }
  1786. //
  1787. // Copy the file. If there is a target root specified, assume
  1788. // the file is being copied to the system partition and make
  1789. // the file readonly, system, hidden.
  1790. //
  1791. #if defined(REMOTE_BOOT)
  1792. // If this is a remote boot install, check to see if a copy of the
  1793. // file already exists on the server, and if so, just make a link
  1794. // to the file instead of copying it.
  1795. //
  1796. if (RemoteBootSetup) {
  1797. Status = SpCopyFileForRemoteBoot(
  1798. FullSourceName,
  1799. FullTargetName,
  1800. TargetFileAttributes,
  1801. CopyFlags,
  1802. &Checksum);
  1803. IsValid = TRUE; // Checksum is known
  1804. } else {
  1805. Status = STATUS_UNSUCCESSFUL;
  1806. }
  1807. if (!NT_SUCCESS(Status))
  1808. #endif // defined(REMOTE_BOOT)
  1809. {
  1810. Status = SpCopyFileUsingNames(
  1811. FullSourceName,
  1812. FullTargetName,
  1813. TargetFileAttributes,
  1814. CopyFlags
  1815. );
  1816. IsValid = FALSE; // Checksum is not known
  1817. }
  1818. //
  1819. // If the file copied OK, verify the copy.
  1820. //
  1821. if(NT_SUCCESS(Status)) {
  1822. if (!IsValid) {
  1823. SpValidateAndChecksumFile(NULL,FullTargetName,&IsNtImage,&Checksum,&IsValid);
  1824. }
  1825. if( ARGUMENT_PRESENT( FileCheckSum ) ) {
  1826. *FileCheckSum = Checksum;
  1827. }
  1828. //
  1829. // If the image is valid, then the file really did copy OK.
  1830. //
  1831. if(IsValid) {
  1832. Failure = FALSE;
  1833. } else {
  1834. //
  1835. // If it's an nt image, then the verify failed.
  1836. // If it's not an nt image, then the only way the verify
  1837. // can fail is if we get an i/o error reading the file back,
  1838. // which means it didn't really copy correctly.
  1839. //
  1840. MsgId = IsNtImage ? SP_SCRN_IMAGE_VERIFY_FAILED : SP_SCRN_COPY_FAILED;
  1841. Failure = TRUE;
  1842. PreinstallRememberFile = FALSE;
  1843. }
  1844. } else {
  1845. if((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (Flags & COPY_SKIPIFMISSING)) {
  1846. Failure = FALSE;
  1847. } else {
  1848. Failure = TRUE;
  1849. MsgId = SP_SCRN_COPY_FAILED;
  1850. }
  1851. PreinstallRememberFile = FALSE;
  1852. }
  1853. if(Failure) {
  1854. //
  1855. // The copy or verify failed. Give the user a message and allow retry.
  1856. //
  1857. repaint:
  1858. SpStartScreen(
  1859. MsgId,
  1860. 3,
  1861. HEADER_HEIGHT+1,
  1862. FALSE,
  1863. FALSE,
  1864. DEFAULT_ATTRIBUTE,
  1865. FileToCopy->SourceFilename
  1866. );
  1867. SpDisplayStatusOptions(
  1868. DEFAULT_STATUS_ATTRIBUTE,
  1869. SP_STAT_ENTER_EQUALS_RETRY,
  1870. SP_STAT_ESC_EQUALS_SKIP_FILE,
  1871. SP_STAT_F3_EQUALS_EXIT,
  1872. 0
  1873. );
  1874. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1875. case ASCI_CR: // retry
  1876. break;
  1877. case ASCI_ESC: // skip file
  1878. Failure = FALSE;
  1879. break;
  1880. case KEY_F3: // exit setup
  1881. SpConfirmExit();
  1882. goto repaint;
  1883. }
  1884. //
  1885. // Need to completely repaint gauge, etc.
  1886. //
  1887. DrawScreen(FullSourceName,FullTargetName,TRUE);
  1888. }
  1889. } while(Failure);
  1890. if( ARGUMENT_PRESENT( FileSkipped ) ) {
  1891. *FileSkipped = !DoCopy;
  1892. }
  1893. //
  1894. // Free the source and target filenames.
  1895. //
  1896. SpMemFree(FullSourceName);
  1897. SpMemFree(FullTargetName);
  1898. //
  1899. // In the preinstall mode, add the file to RenameList
  1900. //
  1901. if( PreInstall && PreinstallRememberFile ) {
  1902. PFILE_TO_RENAME File;
  1903. File = SpMemAlloc(sizeof(FILE_TO_RENAME));
  1904. File->SourceFilename = SpDupStringW(FileToCopy->SourceFilename);
  1905. wcscpy(TemporaryBuffer,L"\\");
  1906. if(TargetRoot) {
  1907. SpConcatenatePaths(TemporaryBuffer,TargetRoot);
  1908. }
  1909. SpConcatenatePaths(TemporaryBuffer,FileToCopy->TargetDirectory);
  1910. File->TargetDirectory = SpDupStringW(TemporaryBuffer);
  1911. File->TargetFilename = SpDupStringW((PWSTR)FileToCopy->TargetFilename);
  1912. File->Next = RenameList;
  1913. RenameList = File;
  1914. }
  1915. }
  1916. VOID
  1917. SpCopyFilesScreenRepaint(
  1918. IN PWSTR FullSourcename, OPTIONAL
  1919. IN PWSTR FullTargetname, OPTIONAL
  1920. IN BOOLEAN RepaintEntireScreen
  1921. )
  1922. {
  1923. static ULONG u = 0;
  1924. PWSTR p;
  1925. UNREFERENCED_PARAMETER(FullTargetname);
  1926. //
  1927. // Repaint the entire screen if necessary.
  1928. //
  1929. if(RepaintEntireScreen) {
  1930. SpStartScreen(SP_SCRN_SETUP_IS_COPYING,0,6,TRUE,FALSE,DEFAULT_ATTRIBUTE);
  1931. if(FileCopyGauge) {
  1932. SpDrawGauge(FileCopyGauge);
  1933. }
  1934. }
  1935. //
  1936. // Place the name of the file being copied on the rightmost
  1937. // area of the status line.
  1938. //
  1939. if(FullSourcename) {
  1940. if(RepaintEntireScreen) {
  1941. SpvidClearScreenRegion(
  1942. 0,
  1943. VideoVars.ScreenHeight-STATUS_HEIGHT,
  1944. VideoVars.ScreenWidth,
  1945. STATUS_HEIGHT,
  1946. DEFAULT_STATUS_BACKGROUND
  1947. );
  1948. SpDisplayStatusActionLabel(SP_STAT_COPYING,12);
  1949. }
  1950. //
  1951. // Isolate the filename part of the sourcename.
  1952. //
  1953. if(p = wcsrchr(FullSourcename,L'\\')) {
  1954. p++;
  1955. } else {
  1956. p = FullSourcename;
  1957. }
  1958. if( !HeadlessTerminalConnected ) {
  1959. SpDisplayStatusActionObject(p);
  1960. } else {
  1961. PWCHAR TempPtr = NULL;
  1962. //
  1963. // If we're headless, we need to be careful about displaying very long
  1964. // file/directory names. For that reason, just display a little spinner.
  1965. //
  1966. switch( u % 4) {
  1967. case 0:
  1968. TempPtr = L"-";
  1969. break;
  1970. case 1:
  1971. TempPtr = L"\\";
  1972. break;
  1973. case 2:
  1974. TempPtr = L"|";
  1975. break;
  1976. default:
  1977. TempPtr = L"/";
  1978. break;
  1979. }
  1980. SpDisplayStatusActionObject( TempPtr );
  1981. u++;
  1982. }
  1983. }
  1984. }
  1985. VOID
  1986. SpCopyFilesInCopyList(
  1987. IN PVOID SifHandle,
  1988. IN PDISK_FILE_LIST DiskFileLists,
  1989. IN ULONG DiskCount,
  1990. IN PWSTR SourceDevicePath,
  1991. IN PWSTR DirectoryOnSourceDevice,
  1992. IN PWSTR TargetRoot,
  1993. IN PINCOMPATIBLE_FILE_LIST CompatibilityExceptionList OPTIONAL
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. Iterate the copy list for each setup source disk and prompt for
  1998. the disk and copy/decompress all the files on it.
  1999. Arguments:
  2000. SifHandle - supplies handle to setup information file.
  2001. DiskFileLists - supplies the copy list, in the form of an array
  2002. of structures, one per disk.
  2003. DiskCount - supplies number of elements in the DiskFileLists array,
  2004. ie, the number of setup disks.
  2005. SourceDevicePath - supplies the path of the device from which files
  2006. are to be copied (ie, \device\floppy0, etc).
  2007. DirectoryOnSourceDevice - supplies the directory on the source device
  2008. where files are to be found.
  2009. TargetRoot - supplies root directory of target. All target directory
  2010. specifications are relative to this directory on the target.
  2011. CompatibilityExceptionList - Singly-linked list of
  2012. PINCOMPATIBLE_FILE_ENTRY objects that should be skipped during
  2013. copying. Optional, pass NULL if no exceptions are present.
  2014. Return Value:
  2015. None.
  2016. --*/
  2017. {
  2018. ULONG DiskNo;
  2019. PDISK_FILE_LIST pDisk;
  2020. PFILE_TO_COPY pFile;
  2021. ULONG TotalFileCount;
  2022. ULONG CheckSum;
  2023. BOOLEAN FileSkipped;
  2024. ULONG CopyFlags;
  2025. NTSTATUS status;
  2026. //
  2027. // Compute the total number of files.
  2028. //
  2029. for(TotalFileCount=DiskNo=0; DiskNo<DiskCount; DiskNo++) {
  2030. TotalFileCount += DiskFileLists[DiskNo].FileCount;
  2031. }
  2032. //
  2033. // If there are no files to copy, then we're done.
  2034. //
  2035. if( TotalFileCount == 0 ) {
  2036. return;
  2037. }
  2038. SendSetupProgressEvent(FileCopyEvent, FileCopyStartEvent, &TotalFileCount);
  2039. //
  2040. // Create a gas gauge.
  2041. //
  2042. SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_SETUP_IS_COPYING);
  2043. FileCopyGauge = SpCreateAndDisplayGauge(TotalFileCount,0,15,TemporaryBuffer,NULL,GF_PERCENTAGE,0);
  2044. ASSERT(FileCopyGauge);
  2045. CLEAR_CLIENT_SCREEN();
  2046. SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
  2047. //
  2048. // Copy files on each disk.
  2049. //
  2050. for(DiskNo=0; DiskNo<DiskCount; DiskNo++) {
  2051. pDisk = &DiskFileLists[DiskNo];
  2052. //
  2053. // Don't bother with this disk if there are no files
  2054. // to be copied from it.
  2055. //
  2056. if(pDisk->FileCount == 0) {
  2057. continue;
  2058. }
  2059. //
  2060. // Prompt the user to insert the disk.
  2061. //
  2062. SpPromptForDisk(
  2063. pDisk->Description,
  2064. SourceDevicePath,
  2065. pDisk->TagFile,
  2066. FALSE, // no ignore disk in drive
  2067. FALSE, // no allow escape
  2068. TRUE, // warn multiple prompts
  2069. NULL // don't care about redraw flag
  2070. );
  2071. //
  2072. // Passing the empty string as the first arg forces
  2073. // the action area of the status line to be set up.
  2074. // Not doing so results in the "Copying: xxxxx" to be
  2075. // flush left on the status line instead of where
  2076. // it belongs (flush right).
  2077. //
  2078. SpCopyFilesScreenRepaint(L"",NULL,TRUE);
  2079. //
  2080. // Copy each file on the source disk.
  2081. //
  2082. ASSERT(pDisk->FileList);
  2083. for(pFile=pDisk->FileList; pFile; pFile=pFile->Next) {
  2084. //
  2085. // Copy the file.
  2086. //
  2087. // If the file is listed for lock smashing then we need to smash it
  2088. // if installing UP on x86 (we don't bother with the latter
  2089. // qualifications here).
  2090. //
  2091. // If there is an absolute target root specified, assume the
  2092. // file is being copied to the system partition and make it
  2093. // readonly/hidden/system.
  2094. //
  2095. // On upgrade, we need to know if the file is listed for oem overwrite.
  2096. //
  2097. //
  2098. // "Copy" or "Move"??
  2099. //
  2100. if( (WinntSetup || RemoteInstallSetup) &&
  2101. (!WinntFromCd) &&
  2102. (!NoLs) &&
  2103. (NTUpgrade != UpgradeFull) &&
  2104. (!IsFileFlagSet(SifHandle,pFile->TargetFilename,FILEFLG_DONTDELETESOURCE)) ) {
  2105. //
  2106. // We can delete the source (i.e. do a 'move')
  2107. //
  2108. CopyFlags = COPY_DELETESOURCE;
  2109. } else {
  2110. //
  2111. // Do a 'copy'
  2112. //
  2113. CopyFlags = 0;
  2114. }
  2115. #if 0
  2116. #ifdef _X86_
  2117. //
  2118. // Copy out of \uniproc (which contains lock-smashed binaries)?
  2119. //
  2120. if( IsFileFlagSet(SifHandle,pFile->TargetFilename,FILEFLG_SMASHLOCKS) ) {
  2121. CopyFlags |= COPY_SMASHLOCKS;
  2122. }
  2123. #endif // defined _X86_
  2124. #endif // if 0
  2125. //
  2126. // What do we do if we can't find a file??
  2127. //
  2128. if( SkipMissingFiles ) {
  2129. CopyFlags |= COPY_SKIPIFMISSING;
  2130. }
  2131. //
  2132. // Do we overwrite files installed by the OEM?
  2133. //
  2134. if( (NTUpgrade == UpgradeFull) &&
  2135. (IsFileFlagSet(SifHandle,pFile->TargetFilename,FILEFLG_UPGRADEOVERWRITEOEM)) ) {
  2136. CopyFlags |= COPY_OVERWRITEOEMFILE;
  2137. }
  2138. //
  2139. // If the file is incompatible, and it's got the overwrite flag set,
  2140. // the blow it away with our own one instead.
  2141. //
  2142. if ( SpIsFileIncompatible(
  2143. CompatibilityExceptionList,
  2144. pFile,
  2145. pFile->AbsoluteTargetDirectory ? NULL : TargetRoot
  2146. ) )
  2147. {
  2148. if (IsFileFlagSet(SifHandle,pFile->SourceFilename,FILEFLG_UPGRADEOVERWRITEOEM) ||
  2149. ( pFile->Flags & FILEFLG_UPGRADEOVERWRITEOEM ) ) {
  2150. CopyFlags = (CopyFlags & ~(COPY_DISPOSITION_MASK|COPY_OVERWRITEOEMFILE));
  2151. CopyFlags |= COPY_ALWAYS | COPY_NOVERSIONCHECK;
  2152. KdPrintEx((
  2153. DPFLTR_SETUP_ID,
  2154. DPFLTR_INFO_LEVEL,
  2155. "SETUP: OEM (or preexsting) file %ws is incompatible with gui-mode, set flag %08lx, forcing copy\n",
  2156. pFile->TargetFilename,
  2157. CopyFlags
  2158. ));
  2159. }
  2160. }
  2161. //
  2162. // What about any privates? We don't want to ever 'move'
  2163. // privates because they might be in the driver cab, in which
  2164. // case, we want them in the ~LS directory when
  2165. // we go into gui-mode setup.
  2166. //
  2167. if( (pSpIsFileInPrivateInf(pFile->TargetFilename)) ) {
  2168. CopyFlags &= ~COPY_DELETESOURCE;
  2169. }
  2170. if(!WIN9X_OR_NT_UPGRADE || IsFileFlagSet(SifHandle,pFile->SourceFilename,FILEFLG_NOVERSIONCHECK)) {
  2171. CopyFlags |= COPY_NOVERSIONCHECK;
  2172. }
  2173. SpCopyFileWithRetry(
  2174. pFile,
  2175. SourceDevicePath,
  2176. DirectoryOnSourceDevice,
  2177. pDisk->Directory,
  2178. pFile->AbsoluteTargetDirectory ? NULL : TargetRoot,
  2179. pFile->AbsoluteTargetDirectory ? ATTR_RHS : 0,
  2180. SpCopyFilesScreenRepaint,
  2181. &CheckSum,
  2182. &FileSkipped,
  2183. CopyFlags
  2184. );
  2185. //
  2186. // Log the file
  2187. //
  2188. if( !FileSkipped ) {
  2189. SpLogOneFile( pFile,
  2190. pFile->AbsoluteTargetDirectory ? NULL : TargetRoot,
  2191. NULL, // DirectoryOnSourceDevice,
  2192. NULL,
  2193. NULL,
  2194. CheckSum );
  2195. }
  2196. //
  2197. // Advance the gauge.
  2198. //
  2199. SpTickGauge(FileCopyGauge);
  2200. SendSetupProgressEvent(FileCopyEvent,
  2201. OneFileCopyEvent,
  2202. &((PGAS_GAUGE)FileCopyGauge)->CurrentPercentage);
  2203. }
  2204. }
  2205. SendSetupProgressEvent(FileCopyEvent, FileCopyEndEvent, NULL);
  2206. SpDestroyGauge(FileCopyGauge);
  2207. FileCopyGauge = NULL;
  2208. }
  2209. NTSTATUS
  2210. SpCreateIncompatibleFileEntry(
  2211. OUT PINCOMPATIBLE_FILE_ENTRY *TargetEntry,
  2212. IN PWSTR FileName,
  2213. IN PWSTR VersionString, OPTIONAL
  2214. IN PWSTR TargetAbsolutePath, OPTIONAL
  2215. IN ULONG Flags OPTIONAL
  2216. )
  2217. /*++
  2218. Routine Description:
  2219. Allocates enough space to store the incompatible file entry data in
  2220. a contiguous blob, copies the values into it, and returns the blob
  2221. created. Layout (using null-terminated strings) is as follows:
  2222. [ Allocation ]
  2223. [ Header ][Filename][Version][TargetAbsolutePath]
  2224. Arguments:
  2225. TargetEntry - Pointer to a PINCOMPATIBLE_FILE_ENTRY that will be
  2226. returned to the caller.
  2227. FileName - Name of the file, no path
  2228. VersionString - Full version string of the file
  2229. TargetAbsolutePath - Absolute path on the target media that this
  2230. file will live in
  2231. Flags - Any flags to be stored
  2232. Returns:
  2233. STATUS_SUCCESS if TargetEntry contains a pointer to the allocated space
  2234. STATUS_NO_MEMORY if the allocation failed
  2235. STATUS_INVALID_PARAMETER_1 if TargetEntry was NULL
  2236. STATUS_INVALID_PARAMETER_2 if FileName was NULL
  2237. --*/
  2238. {
  2239. ULONG WCharsNeeded = 0;
  2240. ULONG ActualBytes = 0;
  2241. PINCOMPATIBLE_FILE_ENTRY LocalEntry;
  2242. PWSTR Cursor;
  2243. if ( TargetEntry )
  2244. *TargetEntry = NULL;
  2245. else
  2246. return STATUS_INVALID_PARAMETER_1;
  2247. //
  2248. // Gather required sizes
  2249. //
  2250. if ( FileName != NULL )
  2251. WCharsNeeded += wcslen(FileName) + 1;
  2252. else
  2253. return STATUS_INVALID_PARAMETER_2;
  2254. if ( VersionString != NULL )
  2255. WCharsNeeded += wcslen(VersionString) + 1;
  2256. if ( TargetAbsolutePath != NULL )
  2257. WCharsNeeded += wcslen(TargetAbsolutePath) + 1;
  2258. //
  2259. // Allocate the space, point the cursor at where we'll be copying
  2260. // the strings.
  2261. //
  2262. ActualBytes = ( sizeof(WCHAR) * WCharsNeeded ) + sizeof(INCOMPATIBLE_FILE_ENTRY);
  2263. LocalEntry = SpMemAlloc( ActualBytes );
  2264. if ( LocalEntry == NULL ) {
  2265. return STATUS_NO_MEMORY;
  2266. }
  2267. //
  2268. // Blank it out, point the write cursor at the end
  2269. //
  2270. ZeroMemory(LocalEntry, ActualBytes);
  2271. Cursor = (PWSTR)(LocalEntry + 1);
  2272. //
  2273. // Copy strings and set pointers
  2274. //
  2275. wcscpy(Cursor, FileName);
  2276. LocalEntry->IncompatibleFileName = Cursor;
  2277. Cursor += wcslen(FileName) + 1;
  2278. if ( VersionString != NULL ) {
  2279. wcscpy(Cursor, VersionString);
  2280. LocalEntry->VersionString = Cursor;
  2281. Cursor += wcslen(VersionString) + 1;
  2282. }
  2283. if ( TargetAbsolutePath != NULL ) {
  2284. wcscpy(Cursor, TargetAbsolutePath);
  2285. LocalEntry->FullPathOnTarget = Cursor;
  2286. }
  2287. *TargetEntry = LocalEntry;
  2288. return STATUS_SUCCESS;
  2289. }
  2290. NTSTATUS
  2291. SpFreeIncompatibleFileList(
  2292. IN PINCOMPATIBLE_FILE_LIST FileListHead
  2293. )
  2294. /*++
  2295. Routine Description:
  2296. Cleans out the list of incompatible entries by freeing all the space
  2297. that was allocated for the list.
  2298. Arguments:
  2299. FileListHead - Pointer to the list containing INCOMPATIBLE_FILE_ENTRY
  2300. items
  2301. Return values:
  2302. STATUS_SUCCESS if the operation succeeds.
  2303. STATUS_INVALID_PARAMETER if FileListHead is NULL
  2304. --*/
  2305. {
  2306. PINCOMPATIBLE_FILE_ENTRY IncListEntry;
  2307. if ( !FileListHead )
  2308. return STATUS_INVALID_PARAMETER;
  2309. while ( FileListHead->Head != NULL ) {
  2310. //
  2311. // Simple list removal, some bookkeeping
  2312. //
  2313. IncListEntry = FileListHead->Head;
  2314. FileListHead->Head = IncListEntry->Next;
  2315. FileListHead->EntryCount--;
  2316. SpMemFree( IncListEntry );
  2317. }
  2318. //
  2319. // Toast the list structure as well.
  2320. //
  2321. FileListHead->Head = NULL;
  2322. FileListHead->EntryCount = 0;
  2323. return STATUS_SUCCESS;
  2324. }
  2325. BOOLEAN
  2326. SpIsFileIncompatible(
  2327. IN PINCOMPATIBLE_FILE_LIST FileList,
  2328. IN PFILE_TO_COPY pFile,
  2329. IN PWSTR TargetRoot OPTIONAL
  2330. )
  2331. /*++
  2332. Routine Description:
  2333. Find out whether the given target media path and file name are listed
  2334. as "incompatible." Looks down FileList for an INCOMPATIBLE_FILE_ENTRY
  2335. that contains FileName and TargetMediaPath. If TargetMediaPath is not
  2336. specified, indicates TRUE if a member with the name FileName is listed
  2337. instead. (Dangerous.)
  2338. Arguments:
  2339. FileList - Header node of a list created with
  2340. SpInitializeCompatibilityOverwriteLists.
  2341. pFile - File to copy structure, containing all the relevant information
  2342. about this file to scan for.
  2343. TargetRoot - Copy target root directory, optional
  2344. Return Values:
  2345. TRUE if the file "FileName" (with the optional path TargetMediaPath)
  2346. is in the list of incompatible files.
  2347. FALSE otherwise, or if FileList or FileName is NULL.
  2348. Remarks:
  2349. This routine could be made more robust in the face of bad parameters,
  2350. but this was deemed superfluous, since there's exactly one caller of
  2351. this API whose values are already checked. This function will then
  2352. behave "properly" in all cases.
  2353. --*/
  2354. {
  2355. INCOMPATIBLE_FILE_ENTRY *Entry;
  2356. BOOLEAN Found = FALSE;
  2357. PWSTR TargetFileName;
  2358. if ( ( FileList == NULL ) || ( FileList->EntryCount == 0 ) )
  2359. goto Exit;
  2360. if ( pFile == NULL )
  2361. goto Exit;
  2362. Entry = FileList->Head;
  2363. //
  2364. // Cache locally
  2365. //
  2366. TargetFileName = pFile->TargetFilename;
  2367. //
  2368. // Generate the target media path from the file object
  2369. //
  2370. #if 0
  2371. VOID
  2372. SpCopyFileWithRetry( SpCopyFileWithRetry(
  2373. IN PFILE_TO_COPY FileToCopy, pFile,
  2374. IN PWSTR SourceDevicePath, SourceDevicePath,
  2375. IN PWSTR DirectoryOnSourceDevice, DirectoryOnSourceDevice,
  2376. IN PWSTR SourceDirectory, OPTIONAL pDisk->Directory,
  2377. IN PWSTR TargetRoot, OPTIONAL pFile->AbsoluteTargetDirectory ? NULL : TargetRoot,
  2378. IN ULONG TargetFileAttributes, OPTIONAL pFile->AbsoluteTargetDirectory ? ATTR_RHS : 0,
  2379. IN PCOPY_DRAW_ROUTINE DrawScreen, SpCopyFilesScreenRepaint,
  2380. IN PULONG FileCheckSum, OPTIONAL &CheckSum,
  2381. IN PBOOLEAN FileSkipped, OPTIONAL &FileSkipped,
  2382. IN ULONG Flags CopyFlags
  2383. );
  2384. VOID
  2385. SpCopyFileWithRetry(
  2386. IN PFILE_TO_COPY FileToCopy,
  2387. IN PWSTR SourceDevicePath,
  2388. IN PWSTR DirectoryOnSourceDevice,
  2389. IN PWSTR SourceDirectory, OPTIONAL
  2390. IN PWSTR TargetRoot, OPTIONAL
  2391. IN ULONG TargetFileAttributes, OPTIONAL
  2392. IN PCOPY_DRAW_ROUTINE DrawScreen,
  2393. IN PULONG FileCheckSum, OPTIONAL
  2394. IN PBOOLEAN FileSkipped, OPTIONAL
  2395. IN ULONG Flags
  2396. )
  2397. //
  2398. // Form the full NT path of the target file.
  2399. //
  2400. wcscpy(p,FileToCopy->TargetDevicePath);
  2401. if(TargetRoot) {
  2402. SpConcatenatePaths(p,TargetRoot);
  2403. }
  2404. SpConcatenatePaths(p,FileToCopy->TargetDirectory);
  2405. //
  2406. // On an OEM preinstall, if the target name is a long name, then use
  2407. // the short name as a target name, and later on, if the copy succeeds,
  2408. // add the file to RenameList, so that it can be added to $$rename.txt
  2409. //
  2410. if( !PreInstall ||
  2411. ( wcslen( FileToCopy->TargetFilename ) <= 8 + 1 + 3 ) ) {
  2412. SpConcatenatePaths(p,FileToCopy->TargetFilename);
  2413. PreinstallRememberFile = FALSE;
  2414. } else {
  2415. SpConcatenatePaths(p,FileToCopy->SourceFilename);
  2416. PreinstallRememberFile = TRUE;
  2417. }
  2418. FullTargetName = SpDupStringW(p);
  2419. #endif // if 0
  2420. //
  2421. // Cycle through the list of incompatible file names, looking
  2422. // for the one requested
  2423. //
  2424. while ( Entry != NULL ) {
  2425. //
  2426. // If the file names match, then check the media paths if
  2427. // specified
  2428. //
  2429. if (_wcsicmp(TargetFileName, Entry->IncompatibleFileName) == 0) {
  2430. //
  2431. // CUT&PASTE CUT&PASTE CUT&PASTE CUT&PASTE CUT&PASTE CUT&PASTE
  2432. //
  2433. // This was clipped from SpCopyFileWithRetry's code that generates the
  2434. // actual target path. I think the logic is supposed to look something
  2435. // like the following:
  2436. //
  2437. // Target =
  2438. // File.TargetDevicePath +
  2439. // (File.AbsoluteTargetDirectory ? "" : TargetRoot) +
  2440. // File.TargetDirectory +
  2441. // ( (PreInstall || File.TargetFileName.Length > 12 ) ? File.SourceFilename : File.TargetFilename )
  2442. //
  2443. PWSTR TargetMediaPath = (PWSTR)TemporaryBuffer;
  2444. wcscpy( TargetMediaPath, pFile->TargetDevicePath );
  2445. if ( !pFile->AbsoluteTargetDirectory && ( TargetRoot != NULL ) ) {
  2446. SpConcatenatePaths(TargetMediaPath, TargetRoot);
  2447. }
  2448. SpConcatenatePaths(TargetMediaPath,pFile->TargetDirectory);
  2449. if ( !PreInstall || ( wcslen( pFile->TargetFilename ) <= 8 + 1 + 3 ) ) {
  2450. SpConcatenatePaths(TargetMediaPath, pFile->TargetFilename);
  2451. } else {
  2452. SpConcatenatePaths(TargetMediaPath, pFile->SourceFilename);
  2453. }
  2454. //
  2455. // When requesting an exact match, check it
  2456. //
  2457. if (Entry->FullPathOnTarget != NULL) {
  2458. if (_wcsicmp(TargetMediaPath, Entry->FullPathOnTarget) == 0) {
  2459. Found = TRUE;
  2460. goto Exit;
  2461. }
  2462. //
  2463. // Otherwise, the target media path was NULL, so just care if
  2464. // the short names matched
  2465. //
  2466. } else {
  2467. Found = TRUE;
  2468. goto Exit;
  2469. }
  2470. }
  2471. Entry = Entry->Next;
  2472. }
  2473. Exit:
  2474. return Found;
  2475. }
  2476. NTSTATUS
  2477. SpInitializeCompatibilityOverwriteLists(
  2478. IN PVOID SifHandle,
  2479. OUT PINCOMPATIBLE_FILE_LIST IncompatibleFileList
  2480. )
  2481. /*++
  2482. Routine Description:
  2483. Reads the list of files that were marked as "incompatible" or "wrong
  2484. version" in Winnt32, and stored in the IncompatibleFilesToOverWrite
  2485. section of the sif file. The data should be in the format
  2486. [IncompatibleFilesToOverWrite]
  2487. <shortname> = <version>,<full file path>
  2488. Arguments:
  2489. SifHandle - Handle to the INF that this list will be loaded from.
  2490. IncompatibleFileLists - Filled out to
  2491. Returns:
  2492. STATUS_SUCCESS on good completion.
  2493. STATUS_INVALID_PARAMETER_1 if SifHandle is NULL.
  2494. STATUS_INVALID_PARAMETER_2 if IncompatibleFileList is NULL.
  2495. --*/
  2496. {
  2497. NTSTATUS status = STATUS_SUCCESS;
  2498. INCOMPATIBLE_FILE_LIST fileListHead;
  2499. PINCOMPATIBLE_FILE_ENTRY fileListSingle = NULL;
  2500. PWSTR SectionName = WINNT_OVERWRITE_EXISTING_W;
  2501. PWSTR VersionString;
  2502. PWSTR TargetMediaName;
  2503. PWSTR FileName;
  2504. PWSTR FullNtPathOfTargetName;
  2505. ULONG SectionItemCount;
  2506. ULONG i;
  2507. if ( !SifHandle )
  2508. return STATUS_INVALID_PARAMETER_1;
  2509. if ( !IncompatibleFileList )
  2510. return STATUS_INVALID_PARAMETER_2;
  2511. //
  2512. // Construct our local copy
  2513. //
  2514. IncompatibleFileList->Head = NULL;
  2515. IncompatibleFileList->EntryCount = 0;
  2516. fileListHead.Head = NULL;
  2517. fileListHead.EntryCount = 0;
  2518. SectionItemCount = SpCountLinesInSection(SifHandle, SectionName);
  2519. for ( i = 0; i < SectionItemCount; i++ ) {
  2520. FileName = SpGetKeyName( SifHandle, SectionName, i );
  2521. if (!FileName){
  2522. SpFatalSifError(SifHandle,SectionName,NULL,i,(ULONG)(-1));
  2523. }
  2524. //
  2525. // Get the version string
  2526. //
  2527. VersionString = SpGetSectionKeyIndex(
  2528. SifHandle,
  2529. SectionName,
  2530. FileName,
  2531. 0 );
  2532. //
  2533. // And name on the target media, if specified.
  2534. //
  2535. TargetMediaName = SpGetSectionKeyIndex(
  2536. SifHandle,
  2537. SectionName,
  2538. FileName,
  2539. 1 );
  2540. //
  2541. // We can't, unfortunately, just use the path we got from the sif
  2542. // file, as it's a Win32 path (c:\foo\bar\zot.foom). We need a full
  2543. // NT path (\Device\Harddisk0\Partition1\foo\bar\zot.foom) instead.
  2544. // So, we convert with SpNtPathFromDosPath, which has the side-
  2545. // effect of allocating space, which we don't necessarily care
  2546. // about.
  2547. //
  2548. FullNtPathOfTargetName = SpNtPathFromDosPath( TargetMediaName );
  2549. //
  2550. // Create the file list entry, and store it for
  2551. // later use.
  2552. //
  2553. status = SpCreateIncompatibleFileEntry(
  2554. &fileListSingle,
  2555. FileName,
  2556. VersionString,
  2557. FullNtPathOfTargetName,
  2558. 0 );
  2559. //
  2560. // If that failed and we have a full path, it should get freed
  2561. // before we fail this code path to avoid a leak.
  2562. //
  2563. if ( FullNtPathOfTargetName != NULL ) {
  2564. SpMemFree(FullNtPathOfTargetName);
  2565. FullNtPathOfTargetName = NULL;
  2566. }
  2567. if (!NT_SUCCESS(status))
  2568. goto Exit;
  2569. //
  2570. // Head insertion, indicate it was added
  2571. //
  2572. fileListSingle->Next = fileListHead.Head;
  2573. fileListHead.Head = fileListSingle;
  2574. fileListHead.EntryCount++;
  2575. fileListSingle = NULL;
  2576. }
  2577. //
  2578. // And store the list from here to there.
  2579. //
  2580. *IncompatibleFileList = fileListHead;
  2581. Exit:
  2582. //
  2583. // Did we accidentally create one but fail to insert it? Hmm...
  2584. //
  2585. if( fileListSingle != NULL ) {
  2586. SpMemFree(fileListSingle);
  2587. fileListSingle = NULL;
  2588. }
  2589. //
  2590. // If there was a failure and the list is nonempty, free its
  2591. // entries. It will not have been copied over to IncompatibleFileLists
  2592. // (the only point of failure is SpCreateIncompatibleFileEntry, which
  2593. // if it fails leaps out to Exit: without assigning IFL.)
  2594. //
  2595. if ( fileListHead.EntryCount != 0 && !NT_SUCCESS(status)) {
  2596. SpFreeIncompatibleFileList( &fileListHead );
  2597. }
  2598. return status;
  2599. }
  2600. VOID
  2601. SpInitializeFileLists(
  2602. IN PVOID SifHandle,
  2603. OUT PDISK_FILE_LIST *DiskFileLists,
  2604. OUT PULONG DiskCount
  2605. )
  2606. /*++
  2607. Routine Description:
  2608. Initialize disk file lists. This involves looking in a given section
  2609. in the sectup information file and fetching information for each
  2610. disk specified there. The data is expected to be in the format
  2611. [<SifSection>]
  2612. <MediaShortname> = <Description>,<TagFile>[,,<Directory>]
  2613. ...
  2614. (Note that <Directory> is the third field -- the 2 commas
  2615. are not a typo -- field 2 is unused.)
  2616. Arguments:
  2617. SifHandle - supplies handle to loaded setup information file.
  2618. DiskFileLists - receives pointer to an array of disk file list
  2619. structures, one per line in SifSection. The caller must free
  2620. this buffer when finished with it.
  2621. DiskCount - receives number of elements in DiskFileLists array.
  2622. Return Value:
  2623. None.
  2624. --*/
  2625. {
  2626. unsigned pass;
  2627. PWSTR mediaShortname,description,tagFile,directory;
  2628. PDISK_FILE_LIST diskFileLists;
  2629. PWSTR SectionName;
  2630. ULONG TotalCount;
  2631. ULONG SectionCount;
  2632. ULONG i,u;
  2633. BOOLEAN Found;
  2634. diskFileLists = SpMemAlloc(0);
  2635. TotalCount = 0;
  2636. for(pass=0; pass<2; pass++) {
  2637. //
  2638. // On first pass do the platform-specific section.
  2639. //
  2640. SectionName = pass
  2641. ? SIF_SETUPMEDIA
  2642. : SpMakePlatformSpecificSectionName(SIF_SETUPMEDIA);
  2643. //
  2644. // Determine the number of media specifications
  2645. // in the given section.
  2646. //
  2647. if (SectionName) {
  2648. SectionCount = SpCountLinesInSection(SifHandle,SectionName);
  2649. diskFileLists = SpMemRealloc(
  2650. diskFileLists,
  2651. (TotalCount+SectionCount) * sizeof(DISK_FILE_LIST)
  2652. );
  2653. //
  2654. // Zero out the new part of the buffer we just reallocated.
  2655. //
  2656. RtlZeroMemory(
  2657. diskFileLists + TotalCount,
  2658. SectionCount * sizeof(DISK_FILE_LIST)
  2659. );
  2660. for(i=0; i<SectionCount; i++) {
  2661. //
  2662. // Fetch parameters for this disk.
  2663. //
  2664. mediaShortname = SpGetKeyName(SifHandle,SectionName,i);
  2665. if(!mediaShortname) {
  2666. SpFatalSifError(SifHandle,SectionName,NULL,i,(ULONG)(-1));
  2667. }
  2668. //
  2669. // Ignore if we've already processed a media with this
  2670. // shortname. This lets the platform-specific one override
  2671. // the platform-independent one.
  2672. //
  2673. Found = FALSE;
  2674. for(u=0; u<TotalCount; u++) {
  2675. if(!_wcsicmp(mediaShortname,diskFileLists[u].MediaShortname)) {
  2676. Found = TRUE;
  2677. break;
  2678. }
  2679. }
  2680. if(!Found) {
  2681. SpGetSourceMediaInfo(SifHandle,mediaShortname,&description,&tagFile,&directory);
  2682. //
  2683. // Initialize the disk file list structure.
  2684. //
  2685. diskFileLists[TotalCount].MediaShortname = mediaShortname;
  2686. diskFileLists[TotalCount].Description = description;
  2687. diskFileLists[TotalCount].TagFile = tagFile;
  2688. diskFileLists[TotalCount].Directory = directory;
  2689. TotalCount++;
  2690. }
  2691. }
  2692. if(!pass) {
  2693. SpMemFree(SectionName);
  2694. }
  2695. }
  2696. }
  2697. *DiskFileLists = diskFileLists;
  2698. *DiskCount = TotalCount;
  2699. }
  2700. VOID
  2701. SpFreeCopyLists(
  2702. IN OUT PDISK_FILE_LIST *DiskFileLists,
  2703. IN ULONG DiskCount
  2704. )
  2705. {
  2706. ULONG u;
  2707. PFILE_TO_COPY Entry,Next;
  2708. //
  2709. // Free the copy list on each disk.
  2710. //
  2711. for(u=0; u<DiskCount; u++) {
  2712. for(Entry=(*DiskFileLists)[u].FileList; Entry; ) {
  2713. Next = Entry->Next;
  2714. SpMemFree(Entry);
  2715. Entry = Next;
  2716. }
  2717. }
  2718. SpMemFree(*DiskFileLists);
  2719. *DiskFileLists = NULL;
  2720. }
  2721. BOOLEAN
  2722. SpCreateEntryInCopyList(
  2723. IN PVOID SifHandle,
  2724. IN PDISK_FILE_LIST DiskFileLists,
  2725. IN ULONG DiskCount,
  2726. IN ULONG DiskNumber,
  2727. IN PWSTR SourceFilename,
  2728. IN PWSTR TargetDirectory,
  2729. IN PWSTR TargetFilename,
  2730. IN PWSTR TargetDevicePath,
  2731. IN BOOLEAN AbsoluteTargetDirectory,
  2732. IN ULONG CopyFlags
  2733. )
  2734. /*++
  2735. Routine Description:
  2736. Adds an entry to a disk's file copy list after first verifying that
  2737. the file is not already on the disk copy list.
  2738. Arguments:
  2739. SifHandle - supplies handle to loaded text setup information file
  2740. (txtsetup.sif).
  2741. DiskFileLists - supplies an array of file lists, one for each distribution
  2742. disk in the product.
  2743. DiskCount - supplies number of elements in the DiskFileLists array.
  2744. SourceFilename - supplies the name of the file as it exists on the
  2745. distribution media.
  2746. TargetDirectory - supplies the directory on the target media
  2747. into which the file will be copied.
  2748. TargetFilename - supplies the name of the file as it will exist
  2749. in the target tree.
  2750. TargetDevicePath - supplies the NT name of the device onto which the file
  2751. is to be copied (ie, \device\harddisk1\partition2, etc).
  2752. AbsoluteTargetDirectory - indicates whether TargetDirectory is a path from the
  2753. root, or relative to a root to specified later.
  2754. CopyFlags -
  2755. COPY_ALWAYS : always copied
  2756. COPY_ONLY_IF_PRESENT : copied only if present on the targetReturn Value:
  2757. COPY_ONLY_IF_NOT_PRESENT : not copied if present on the target
  2758. COPY_NEVER : never copied
  2759. Return Value:
  2760. TRUE if a new copy list entry was created; FALSE if not (ie, the file was
  2761. already on the copy list).
  2762. --*/
  2763. {
  2764. PDISK_FILE_LIST pDiskList;
  2765. PFILE_TO_COPY pListEntry;
  2766. PFILE_TO_COPY pLastEntry = NULL;
  2767. UNREFERENCED_PARAMETER(DiskCount);
  2768. #if defined(REMOTE_BOOT)
  2769. //
  2770. // If TargetDevicePath is NULL, this file is destined for the system
  2771. // partition on a diskless remote boot machine. In this case, we just
  2772. // skip this file.
  2773. //
  2774. if (TargetDevicePath == NULL) {
  2775. return FALSE;
  2776. }
  2777. #endif // defined(REMOTE_BOOT)
  2778. pDiskList = &DiskFileLists[DiskNumber];
  2779. for(pListEntry=pDiskList->FileList; pListEntry; pListEntry=pListEntry->Next) {
  2780. //
  2781. // Remember the last entry in the list.
  2782. //
  2783. pLastEntry = pListEntry;
  2784. if(!_wcsicmp(pListEntry->TargetFilename,TargetFilename)
  2785. && !_wcsicmp(pListEntry->SourceFilename,SourceFilename)
  2786. && !_wcsicmp(pListEntry->TargetDirectory,TargetDirectory)
  2787. && !_wcsicmp(pListEntry->TargetDevicePath,TargetDevicePath)
  2788. && (pListEntry->AbsoluteTargetDirectory == AbsoluteTargetDirectory)
  2789. // && ( (pListEntry->CopyOptions == COPY_ALWAYS)
  2790. // || (CopyOptions == COPY_ALWAYS)
  2791. // || (CopyOptions == pListEntry->CopyOptions)
  2792. // )
  2793. )
  2794. {
  2795. //
  2796. // Return code indicates that we did not add a new entry.
  2797. //
  2798. return(FALSE);
  2799. }
  2800. }
  2801. //
  2802. // File not already found; create new entry
  2803. // and link into relevent disk's file list.
  2804. //
  2805. pListEntry = SpMemAlloc(sizeof(FILE_TO_COPY));
  2806. pListEntry->SourceFilename = SourceFilename;
  2807. pListEntry->TargetDirectory = TargetDirectory;
  2808. pListEntry->TargetFilename = TargetFilename;
  2809. pListEntry->TargetDevicePath = TargetDevicePath;
  2810. pListEntry->AbsoluteTargetDirectory = AbsoluteTargetDirectory;
  2811. pListEntry->Flags = CopyFlags;
  2812. #if 0
  2813. pListEntry->Next = pDiskList->FileList;
  2814. pDiskList->FileList = pListEntry;
  2815. #else
  2816. if( pLastEntry ) {
  2817. pListEntry->Next = NULL;
  2818. pLastEntry->Next = pListEntry;
  2819. } else {
  2820. pListEntry->Next = pDiskList->FileList;
  2821. pDiskList->FileList = pListEntry;
  2822. }
  2823. #endif // if 0
  2824. pDiskList->FileCount++;
  2825. //
  2826. // Return code indicates that we added a new entry.
  2827. //
  2828. return(TRUE);
  2829. }
  2830. VOID
  2831. SpAddMasterFileSectionToCopyList(
  2832. IN PVOID SifHandle,
  2833. IN PDISK_FILE_LIST DiskFileLists,
  2834. IN ULONG DiskCount,
  2835. IN PWSTR TargetDevicePath,
  2836. IN PWSTR AbsoluteTargetDirectory,
  2837. IN ULONG CopyOptionsIndex
  2838. )
  2839. /*++
  2840. Routine Description:
  2841. Adds files listed in a setup information master file section to the
  2842. copy list.
  2843. Each line in the section is expected to be in a standard format:
  2844. [Section]
  2845. <source_filename> = <disk_ordinal>,
  2846. <target_directory_shortname>,
  2847. <copy_options_for_upgrade>,
  2848. <copy_options_for_textmode>,
  2849. <rename_name>
  2850. Arguments:
  2851. SifHandle - supplies handle to loaded setup information file.
  2852. DiskFileLists - supplies an array of file lists, one for each distribution
  2853. disk in the product.
  2854. DiskCount - supplies number of elements in the DiskFileLists array.
  2855. TargetDevicePath - supplies the NT name of the device onto which the files
  2856. are to be copied (ie, \device\harddisk1\partition2, etc).
  2857. AbsoluteTargetDirectory - If specified, supplies the directory into which the files
  2858. are to be copied on the target; overrides values specified on the lines
  2859. in [<SectionName>]. This allows the caller to specify an absolute directory
  2860. for the files instead of using indirection via a target directory shortname.
  2861. CopyOptionsIndex -
  2862. This specifies which index to look up to get the copy options field. If
  2863. the field is not present it is assumed that this this file is not to
  2864. be copied. Use:
  2865. INDEX_UPGRADE for upgrade copy options
  2866. INDEX_WINNTFILE for fresh installation copy options
  2867. --*/
  2868. {
  2869. ULONG Count,u,u1,CopyOptions;
  2870. PWSTR CopyOptionsString, sourceFilename,targetFilename,targetDirSpec,mediaShortname,TargetDirectory;
  2871. BOOLEAN fAbsoluteTargetDirectory;
  2872. PWSTR section;
  2873. unsigned i;
  2874. for(i=0; i<2; i++) {
  2875. section = i
  2876. ? SpMakePlatformSpecificSectionName(SIF_FILESONSETUPMEDIA)
  2877. : SIF_FILESONSETUPMEDIA;
  2878. //
  2879. // Determine the number of files listed in the section.
  2880. // This value may be zero.
  2881. //
  2882. Count = SpCountLinesInSection(SifHandle,section);
  2883. if (fAbsoluteTargetDirectory = (AbsoluteTargetDirectory != NULL)) {
  2884. TargetDirectory = AbsoluteTargetDirectory;
  2885. }
  2886. for(u=0; u<Count; u++) {
  2887. //
  2888. // Get the copy options using the index provided. If the field
  2889. // is not present, we don't need to add this to the copy list
  2890. //
  2891. CopyOptionsString = SpGetSectionLineIndex(SifHandle,section,u,CopyOptionsIndex);
  2892. if((CopyOptionsString == NULL) || (*CopyOptionsString == 0)) {
  2893. continue;
  2894. }
  2895. CopyOptions = (ULONG)SpStringToLong(CopyOptionsString,NULL,10);
  2896. if(CopyOptions == COPY_NEVER) {
  2897. continue;
  2898. }
  2899. //
  2900. // get the source file name
  2901. //
  2902. sourceFilename = SpGetKeyName(SifHandle,section, u);
  2903. if(!sourceFilename) {
  2904. SpFatalSifError(SifHandle,section,NULL,u,0);
  2905. }
  2906. //
  2907. // get the destination target dir spec
  2908. //
  2909. targetDirSpec = SpGetSectionLineIndex(SifHandle,section,u,INDEX_DESTINATION);
  2910. if(!targetDirSpec) {
  2911. SpFatalSifError(SifHandle,section,NULL,u,INDEX_DESTINATION);
  2912. }
  2913. targetFilename = SpGetSectionLineIndex(SifHandle,section,u,INDEX_TARGETNAME);
  2914. if(!targetFilename || !(*targetFilename)) {
  2915. targetFilename = sourceFilename;
  2916. }
  2917. //
  2918. // Look up the actual target directory if necessary.
  2919. //
  2920. if(!fAbsoluteTargetDirectory) {
  2921. TargetDirectory = SpLookUpTargetDirectory(SifHandle,targetDirSpec);
  2922. }
  2923. //
  2924. // get the media shortname
  2925. //
  2926. mediaShortname = SpGetSectionLineIndex(SifHandle,section,u,INDEX_WHICHMEDIA);
  2927. if(!mediaShortname) {
  2928. SpFatalSifError(SifHandle,section,NULL,u,INDEX_WHICHMEDIA);
  2929. }
  2930. //
  2931. // Look up the disk in the disk file lists array.
  2932. //
  2933. for(u1=0; u1<DiskCount; u1++) {
  2934. if(!_wcsicmp(mediaShortname,DiskFileLists[u1].MediaShortname)) {
  2935. break;
  2936. }
  2937. }
  2938. //
  2939. // If we didn't find the media descriptor, then it's invalid.
  2940. //
  2941. if(u1 == DiskCount) {
  2942. SpFatalSifError(SifHandle,section,sourceFilename,0,INDEX_WHICHMEDIA);
  2943. }
  2944. //
  2945. // Create a new file list entry if the file is not already being copied.
  2946. //
  2947. SpCreateEntryInCopyList(
  2948. SifHandle,
  2949. DiskFileLists,
  2950. DiskCount,
  2951. u1,
  2952. sourceFilename,
  2953. TargetDirectory,
  2954. targetFilename,
  2955. TargetDevicePath,
  2956. fAbsoluteTargetDirectory,
  2957. CopyOptions
  2958. );
  2959. }
  2960. if(i) {
  2961. SpMemFree(section);
  2962. }
  2963. }
  2964. }
  2965. VOID
  2966. SpAddSingleFileToCopyList(
  2967. IN PVOID SifHandle,
  2968. IN PDISK_FILE_LIST DiskFileLists,
  2969. IN ULONG DiskCount,
  2970. IN PWSTR SifSection,
  2971. IN PWSTR SifKey, OPTIONAL
  2972. IN ULONG SifLine,
  2973. IN PWSTR TargetDevicePath,
  2974. IN PWSTR TargetDirectory, OPTIONAL
  2975. IN ULONG CopyOptions,
  2976. IN BOOLEAN CheckForNoComp
  2977. )
  2978. /*++
  2979. Routine Description:
  2980. Adds a single file to the list of files to be copied.
  2981. The file, along with the directory into which it is to be copied
  2982. n the target and the name it is to receive on the target, is listed
  2983. in a section in the setup information file.
  2984. The filename is used to index the master file list to determine the
  2985. source media where it resides.
  2986. All this information is recorded in a structure associated with
  2987. the disk on which the file resides.
  2988. [SpecialFiles]
  2989. mpkernel = ntkrnlmp.exe,4,ntoskrnl.exe
  2990. upkernel = ntoskrnl.exe,4,ntoskrnl.exe
  2991. etc.
  2992. [MasterFileList]
  2993. ntkrnlmp.exe = d2
  2994. ntoskrnl.exe = d3
  2995. etc.
  2996. Arguments:
  2997. SifHandle - supplies handle to loaded setup information file.
  2998. DiskFileLists - supplies an array of file lists, one for each distribution
  2999. disk in the product.
  3000. DiskCount - supplies number of elements in the DiskFileLists array.
  3001. SifSection - supplies the name of the section that lists the file
  3002. being added to the copy list.
  3003. SifKey - if specified, supplies the keyname for the line in SifSection
  3004. that lists the file to be added to the copy list.
  3005. SifLine - if SifKey is not specified, this parameter supplies the 0-based
  3006. line number of the line in SifSection that lists the file to be added
  3007. to the copy list.
  3008. TargetDevicePath - supplies the NT name of the device onto which the file
  3009. is to be copied (ie, \device\harddisk1\partition2, etc).
  3010. TargetDirectory - If specified, supplies the directory into which the file
  3011. is to be copied on the target; overrides the value specified on the line
  3012. in SifSection. This allows the caller to specify an absolute directory
  3013. for the file instead of using indirection.
  3014. CopyOptions -
  3015. COPY_ALWAYS : always copied
  3016. COPY_ONLY_IF_PRESENT : copied only if present on the targetReturn Value:
  3017. COPY_ONLY_IF_NOT_PRESENT : not copied if present on the target
  3018. COPY_NEVER : never copied None.
  3019. CheckForNoComp - if true, check this file to see if it must remain uncompressed
  3020. on an NTFS system partition supporting compression.
  3021. If so, then OR the CopyOptions value with COPY_FORCENOCOMP.
  3022. Return Value:
  3023. None.
  3024. --*/
  3025. {
  3026. PWSTR sourceFilename,targetDirSpec,targetFilename;
  3027. ULONG u;
  3028. PWSTR mediaShortname;
  3029. BOOLEAN absoluteTargetDirectory;
  3030. //
  3031. // Get the source filename, target directory spec, and target filename.
  3032. //
  3033. if(SifKey) {
  3034. sourceFilename = SpGetSectionKeyIndex(SifHandle,SifSection,SifKey,0);
  3035. targetDirSpec = SpGetSectionKeyIndex(SifHandle,SifSection,SifKey,1);
  3036. targetFilename = SpGetSectionKeyIndex(SifHandle,SifSection,SifKey,2);
  3037. } else {
  3038. sourceFilename = SpGetSectionLineIndex(SifHandle,SifSection,SifLine,0);
  3039. targetDirSpec = SpGetSectionLineIndex(SifHandle,SifSection,SifLine,1);
  3040. targetFilename = SpGetSectionLineIndex(SifHandle,SifSection,SifLine,2);
  3041. }
  3042. //
  3043. // Validate source filename, target directory spec, and target filename.
  3044. //
  3045. if(!sourceFilename) {
  3046. SpFatalSifError(SifHandle,SifSection,SifKey,SifLine,0);
  3047. return;
  3048. }
  3049. if(!targetDirSpec) {
  3050. SpFatalSifError(SifHandle,SifSection,SifKey,SifLine,1);
  3051. return;
  3052. }
  3053. if(!targetFilename ||
  3054. (!_wcsicmp(SifSection, L"SCSI.Load") &&
  3055. !_wcsicmp(targetFilename,L"noload"))) {
  3056. targetFilename = sourceFilename;
  3057. }
  3058. //
  3059. // Look up the actual target directory if necessary.
  3060. //
  3061. if(TargetDirectory) {
  3062. absoluteTargetDirectory = TRUE;
  3063. } else {
  3064. absoluteTargetDirectory = FALSE;
  3065. TargetDirectory = SpLookUpTargetDirectory(SifHandle,targetDirSpec);
  3066. }
  3067. //
  3068. // Look up the file in the master file list to get
  3069. // the media shortname of the disk where the file is located.
  3070. //
  3071. mediaShortname = SpLookUpValueForFile(SifHandle,sourceFilename,INDEX_WHICHMEDIA,TRUE);
  3072. //
  3073. // Look up the disk in the disk file lists array.
  3074. //
  3075. for(u=0; u<DiskCount; u++) {
  3076. if(!_wcsicmp(mediaShortname,DiskFileLists[u].MediaShortname)) {
  3077. break;
  3078. }
  3079. }
  3080. //
  3081. // If we didn't find the media descriptor, then it's invalid.
  3082. //
  3083. if(u == DiskCount) {
  3084. SpFatalSifError(SifHandle,SIF_FILESONSETUPMEDIA,sourceFilename,0,INDEX_WHICHMEDIA);
  3085. }
  3086. //
  3087. // If necessary, check to see whether this file cannot use NTFS compression. If it cannot,
  3088. // then OR the CopyOptions with COPY_FORCENOCOMP.
  3089. //
  3090. if(CheckForNoComp && IsFileFlagSet(SifHandle,targetFilename,FILEFLG_FORCENOCOMP)) {
  3091. CopyOptions |= COPY_FORCENOCOMP;
  3092. }
  3093. //
  3094. // Create a new file list entry if the file is not already being copied.
  3095. //
  3096. SpCreateEntryInCopyList(
  3097. SifHandle,
  3098. DiskFileLists,
  3099. DiskCount,
  3100. u,
  3101. sourceFilename,
  3102. TargetDirectory,
  3103. targetFilename,
  3104. TargetDevicePath,
  3105. absoluteTargetDirectory,
  3106. CopyOptions
  3107. );
  3108. }
  3109. VOID
  3110. SpAddSectionFilesToCopyList(
  3111. IN PVOID SifHandle,
  3112. IN PDISK_FILE_LIST DiskFileLists,
  3113. IN ULONG DiskCount,
  3114. IN PWSTR SectionName,
  3115. IN PWSTR TargetDevicePath,
  3116. IN PWSTR TargetDirectory,
  3117. IN ULONG CopyOptions,
  3118. IN BOOLEAN CheckForNoComp
  3119. )
  3120. /*++
  3121. Routine Description:
  3122. Adds files listed in a setup information file section to the copy list.
  3123. Each line in the section is expected to be in a standard format:
  3124. [Section]
  3125. <source_filename>,<target_directory_shortname>[,<target_filename>]
  3126. Arguments:
  3127. SifHandle - supplies handle to loaded setup information file.
  3128. DiskFileLists - supplies an array of file lists, one for each distribution
  3129. disk in the product.
  3130. DiskCount - supplies number of elements in the DiskFileLists array.
  3131. SectionName - supplies the name of the section that lists the files
  3132. being added to the copy list.
  3133. TargetDevicePath - supplies the NT name of the device onto which the files
  3134. are to be copied (ie, \device\harddisk1\partition2, etc).
  3135. TargetDirectory - If specified, supplies the directory into which the files
  3136. are to be copied on the target; overrides values specified on the lines
  3137. in [<SectionName>]. This allows the caller to specify an absolute directory
  3138. for the files instead of using indirection via a target directory shortname.
  3139. CopyOptions -
  3140. COPY_ALWAYS : always copied
  3141. COPY_ONLY_IF_PRESENT : copied only if present on the targetReturn Value:
  3142. COPY_ONLY_IF_NOT_PRESENT : not copied if present on the target
  3143. COPY_NEVER : never copied
  3144. CheckForNoComp - if true, then check each file to see if it must exist uncompressed
  3145. on an NTFS partition supporting compression (ie, NTLDR on x86).
  3146. --*/
  3147. {
  3148. ULONG Count,u;
  3149. //
  3150. // Determine the number of files listed in the section.
  3151. // This value may be zero.
  3152. //
  3153. Count = SpCountLinesInSection(SifHandle,SectionName);
  3154. for(u=0; u<Count; u++) {
  3155. //
  3156. // Add this line to the copy list.
  3157. //
  3158. SpAddSingleFileToCopyList(
  3159. SifHandle,
  3160. DiskFileLists,
  3161. DiskCount,
  3162. SectionName,
  3163. NULL,
  3164. u,
  3165. TargetDevicePath,
  3166. TargetDirectory,
  3167. CopyOptions,
  3168. CheckForNoComp
  3169. );
  3170. }
  3171. }
  3172. VOID
  3173. SpAddHalKrnlDetToCopyList(
  3174. IN PVOID SifHandle,
  3175. IN PDISK_FILE_LIST DiskFileLists,
  3176. IN ULONG DiskCount,
  3177. IN PWSTR TargetDevicePath,
  3178. IN PWSTR SystemPartition,
  3179. IN PWSTR SystemPartitionDirectory,
  3180. IN BOOLEAN Uniprocessor
  3181. )
  3182. /*++
  3183. Routine Description:
  3184. Add the following files based on configuration:
  3185. - the up or mp kernel.
  3186. - the HAL
  3187. - the detect module [x86 only]
  3188. Arguments:
  3189. SifHandle - supplies handle to loaded setup information file.
  3190. DiskFileLists - supplies an array of file lists, one for each distribution
  3191. disk in the product.
  3192. DiskCount - supplies number of elements in the DiskFileLists array.
  3193. TargetDevicePath - supplies the NT name of the device that will hold the
  3194. nt tree.
  3195. SystemPartition - supplies the NT name of the device that will hold the
  3196. system partition.
  3197. SystemPartitionDirectoty - supplies the directory on the system partition
  3198. into which files that go on the system partition will be copied.
  3199. Uniprocessor - if true, then we are installing/upgrading a UP system.
  3200. Note that this a different question than the number of processors
  3201. in the system.
  3202. Return Value:
  3203. None.
  3204. --*/
  3205. {
  3206. PHARDWARE_COMPONENT pHw;
  3207. //
  3208. // Add the right kernel to the copy list.
  3209. //
  3210. SpAddSingleFileToCopyList(
  3211. SifHandle,
  3212. DiskFileLists,
  3213. DiskCount,
  3214. SIF_SPECIALFILES,
  3215. Uniprocessor ? SIF_UPKERNEL : SIF_MPKERNEL,
  3216. 0,
  3217. TargetDevicePath,
  3218. NULL,
  3219. COPY_ALWAYS,
  3220. FALSE
  3221. );
  3222. #ifdef _X86_
  3223. // Check to see if we should add the PAE kernel to the copy list.
  3224. // Since some skus like pro/per don't have these kernels, they should not list them in the txtsetup.sif.
  3225. if ( SpGetSectionKeyIndex(SifHandle,SIF_SPECIALFILES,Uniprocessor ? L"UPKrnlPa" : L"MPKrnlPa",0)) {
  3226. //
  3227. // Add the right PAE kernel to the copy list.
  3228. //
  3229. SpAddSingleFileToCopyList(
  3230. SifHandle,
  3231. DiskFileLists,
  3232. DiskCount,
  3233. SIF_SPECIALFILES,
  3234. Uniprocessor ? L"UPKrnlPa" : L"MPKrnlPa",
  3235. 0,
  3236. TargetDevicePath,
  3237. NULL,
  3238. COPY_ALWAYS,
  3239. FALSE
  3240. );
  3241. }
  3242. #endif // defined _X86_
  3243. //
  3244. // Add the hal to the file copy list.
  3245. //
  3246. if( !PreInstall ||
  3247. (PreinstallHardwareComponents[HwComponentComputer] == NULL) ) {
  3248. pHw = HardwareComponents[HwComponentComputer];
  3249. } else {
  3250. pHw = PreinstallHardwareComponents[HwComponentComputer];
  3251. }
  3252. if(!pHw->ThirdPartyOptionSelected) {
  3253. SpAddSingleFileToCopyList(
  3254. SifHandle,
  3255. DiskFileLists,
  3256. DiskCount,
  3257. SIF_HAL,
  3258. pHw->IdString,
  3259. 0,
  3260. TargetDevicePath,
  3261. NULL,
  3262. COPY_ALWAYS,
  3263. FALSE
  3264. );
  3265. }
  3266. #ifdef _X86_
  3267. if (SpIsArc()) {
  3268. SpAddSingleFileToCopyList(
  3269. SifHandle,
  3270. DiskFileLists,
  3271. DiskCount,
  3272. SIF_BOOTVID,
  3273. pHw->IdString,
  3274. 0,
  3275. TargetDevicePath,
  3276. NULL,
  3277. COPY_ALWAYS,
  3278. FALSE
  3279. );
  3280. }
  3281. //
  3282. // If a third party computer was not specified, then there will be a
  3283. // detect module specified in the [ntdetect] section of the inf file
  3284. // for the computer.
  3285. // If a third-party computer was specified, then there may or may not
  3286. // be a detect module. If there is no detect module specified, then
  3287. // copy the 'standard' one.
  3288. //
  3289. {
  3290. PWSTR NtDetectId = NULL;
  3291. if(!pHw->ThirdPartyOptionSelected) {
  3292. NtDetectId = pHw->IdString;
  3293. } else {
  3294. if(!IS_FILETYPE_PRESENT(pHw->FileTypeBits,HwFileDetect)) {
  3295. NtDetectId = SIF_STANDARD;
  3296. }
  3297. }
  3298. if(NtDetectId) {
  3299. SpAddSingleFileToCopyList(
  3300. SifHandle,
  3301. DiskFileLists,
  3302. DiskCount,
  3303. SIF_NTDETECT,
  3304. NtDetectId,
  3305. 0,
  3306. SystemPartition,
  3307. SystemPartitionDirectory,
  3308. COPY_ALWAYS,
  3309. FALSE
  3310. );
  3311. }
  3312. }
  3313. #endif
  3314. }
  3315. VOID
  3316. SpAddBusExtendersToCopyList(
  3317. IN PVOID SifHandle,
  3318. IN PDISK_FILE_LIST DiskFileLists,
  3319. IN ULONG DiskCount,
  3320. IN PWSTR TargetDevicePath
  3321. )
  3322. /*++
  3323. Routine Description:
  3324. Add to the copy list the bus extender related files and the mouse and keyboard related files,
  3325. that are copied based on the configuration of the machine.
  3326. Arguments:
  3327. SifHandle - supplies handle to loaded setup information file.
  3328. DiskFileLists - supplies an array of file lists, one for each distribution
  3329. disk in the product.
  3330. DiskCount - supplies number of elements in the DiskFileLists array.
  3331. TargetDevicePath - supplies the NT name of the device that will hold the
  3332. nt tree.
  3333. Return Value:
  3334. None.
  3335. --*/
  3336. {
  3337. ULONG i;
  3338. PHARDWARE_COMPONENT pHw;
  3339. PWSTR SectionName;
  3340. PHARDWARE_COMPONENT DeviceLists[] = {
  3341. BootBusExtenders,
  3342. BusExtenders,
  3343. InputDevicesSupport
  3344. };
  3345. PWSTR SectionNames[] = {
  3346. SIF_BOOTBUSEXTENDERS,
  3347. SIF_BUSEXTENDERS,
  3348. SIF_INPUTDEVICESSUPPORT
  3349. };
  3350. //
  3351. // Add the bus extender and input device drivers to the copy list
  3352. //
  3353. for( i = 0; i < sizeof(DeviceLists) / sizeof(PDETECTED_DEVICE); i++ ) {
  3354. for( pHw = DeviceLists[i]; pHw; pHw=pHw->Next) {
  3355. //
  3356. // Get the name of the section containing files for this device.
  3357. //
  3358. SectionName = SpGetSectionKeyIndex(
  3359. SifHandle,
  3360. SectionNames[i],
  3361. pHw->IdString,
  3362. INDEX_FILESECTION
  3363. );
  3364. if(!SectionName) {
  3365. SpFatalSifError(
  3366. SifHandle,
  3367. SectionNames[i],
  3368. pHw->IdString,
  3369. 0,
  3370. INDEX_FILESECTION
  3371. );
  3372. return; // for prefix
  3373. }
  3374. //
  3375. // Add that section's files to the copy list.
  3376. //
  3377. SpAddSectionFilesToCopyList(
  3378. SifHandle,
  3379. DiskFileLists,
  3380. DiskCount,
  3381. SectionName,
  3382. TargetDevicePath,
  3383. NULL,
  3384. COPY_ALWAYS,
  3385. FALSE
  3386. );
  3387. }
  3388. }
  3389. }
  3390. VOID
  3391. SpAddConditionalFilesToCopyList(
  3392. IN PVOID SifHandle,
  3393. IN PDISK_FILE_LIST DiskFileLists,
  3394. IN ULONG DiskCount,
  3395. IN PWSTR TargetDevicePath,
  3396. IN PWSTR SystemPartition,
  3397. IN PWSTR SystemPartitionDirectory,
  3398. IN BOOLEAN Uniprocessor
  3399. )
  3400. /*++
  3401. Routine Description:
  3402. Add files to the copy list that are copied based on the configuration
  3403. of the machine and user selections.
  3404. This may include:
  3405. - the up or mp kernel.
  3406. - abiosdsk
  3407. - vga files [x86 only]
  3408. - files for computer, keyboard, mouse, display, and layout
  3409. - scsi miniport drivers
  3410. - mouse and keyboard class drivers
  3411. - the HAL
  3412. - the detect module [x86 only]
  3413. - bus extender drivers
  3414. Arguments:
  3415. SifHandle - supplies handle to loaded setup information file.
  3416. DiskFileLists - supplies an array of file lists, one for each distribution
  3417. disk in the product.
  3418. DiskCount - supplies number of elements in the DiskFileLists array.
  3419. TargetDevicePath - supplies the NT name of the device that will hold the
  3420. nt tree.
  3421. SystemPartition - supplies the NT name of the device that will hold the
  3422. system partition.
  3423. SystemPartitionDirectoty - supplies the directory on the system partition
  3424. into which files that go on the system partition will be copied.
  3425. Uniprocessor - if true, then we are installing/upgrading a UP system.
  3426. Note that this a different question than the number of processors
  3427. in the system.
  3428. Return Value:
  3429. None.
  3430. --*/
  3431. {
  3432. ULONG i;
  3433. PHARDWARE_COMPONENT pHw;
  3434. PWSTR SectionName;
  3435. //
  3436. // Add the hal, kernel and ntdetect to the copy list
  3437. //
  3438. SpAddHalKrnlDetToCopyList(
  3439. SifHandle,
  3440. DiskFileLists,
  3441. DiskCount,
  3442. TargetDevicePath,
  3443. SystemPartition,
  3444. SystemPartitionDirectory,
  3445. Uniprocessor
  3446. );
  3447. //
  3448. // If there are any abios disks, copy the abios disk driver.
  3449. //
  3450. if(AbiosDisksExist) {
  3451. SpAddSingleFileToCopyList(
  3452. SifHandle,
  3453. DiskFileLists,
  3454. DiskCount,
  3455. SIF_SPECIALFILES,
  3456. SIF_ABIOSDISK,
  3457. 0,
  3458. TargetDevicePath,
  3459. NULL,
  3460. COPY_ALWAYS,
  3461. FALSE
  3462. );
  3463. }
  3464. //
  3465. // Always copy vga files.
  3466. //
  3467. SpAddSectionFilesToCopyList(
  3468. SifHandle,
  3469. DiskFileLists,
  3470. DiskCount,
  3471. SIF_VGAFILES,
  3472. TargetDevicePath,
  3473. NULL,
  3474. COPY_ALWAYS,
  3475. FALSE
  3476. );
  3477. //
  3478. // Add the correct device driver files to the copy list.
  3479. //
  3480. for(i=0; i<HwComponentMax; i++) {
  3481. //
  3482. // Layout is handled elsewhere.
  3483. //
  3484. if(i == HwComponentLayout) {
  3485. continue;
  3486. }
  3487. if( !PreInstall ||
  3488. ( PreinstallHardwareComponents[i] == NULL ) ) {
  3489. pHw = HardwareComponents[i];
  3490. } else {
  3491. pHw = PreinstallHardwareComponents[i];
  3492. }
  3493. for( ; pHw != NULL; pHw = pHw->Next ) {
  3494. //
  3495. // No files to copy here for third-party options.
  3496. // This is handled elsewhere.
  3497. //
  3498. if(pHw->ThirdPartyOptionSelected) {
  3499. continue;
  3500. }
  3501. //
  3502. // Get the name of the section containing files for this device.
  3503. //
  3504. SectionName = SpGetSectionKeyIndex(
  3505. SifHandle,
  3506. NonlocalizedComponentNames[i],
  3507. pHw->IdString,
  3508. INDEX_FILESECTION
  3509. );
  3510. if(!SectionName) {
  3511. SpFatalSifError(
  3512. SifHandle,
  3513. NonlocalizedComponentNames[i],
  3514. pHw->IdString,
  3515. 0,
  3516. INDEX_FILESECTION
  3517. );
  3518. return; // for prefix
  3519. }
  3520. //
  3521. // Add that section's files to the copy list.
  3522. //
  3523. SpAddSectionFilesToCopyList(
  3524. SifHandle,
  3525. DiskFileLists,
  3526. DiskCount,
  3527. SectionName,
  3528. TargetDevicePath,
  3529. NULL,
  3530. COPY_ALWAYS,
  3531. FALSE
  3532. );
  3533. }
  3534. }
  3535. //
  3536. // Add the keyboard layout dll to the copy list.
  3537. //
  3538. if( !PreInstall ||
  3539. (PreinstallHardwareComponents[HwComponentLayout] == NULL) ) {
  3540. pHw = HardwareComponents[HwComponentLayout];
  3541. } else {
  3542. pHw = PreinstallHardwareComponents[HwComponentLayout];
  3543. }
  3544. //
  3545. if(!pHw->ThirdPartyOptionSelected) {
  3546. SpAddSingleFileToCopyList(
  3547. SifHandle,
  3548. DiskFileLists,
  3549. DiskCount,
  3550. SIF_KEYBOARDLAYOUTFILES,
  3551. pHw->IdString,
  3552. 0,
  3553. TargetDevicePath,
  3554. NULL,
  3555. COPY_ALWAYS,
  3556. FALSE
  3557. );
  3558. }
  3559. //
  3560. // Add scsi miniport drivers to the copy list.
  3561. // Because miniport drivers are only a single file,
  3562. // we just use the filename specified in [SCSI.Load] --
  3563. // no need for separate [files.xxxx] sections.
  3564. //
  3565. if( !PreInstall ||
  3566. ( PreinstallScsiHardware == NULL ) ) {
  3567. pHw = ScsiHardware;
  3568. } else {
  3569. pHw = PreinstallScsiHardware;
  3570. }
  3571. for( ; pHw; pHw=pHw->Next) {
  3572. if(!pHw->ThirdPartyOptionSelected) {
  3573. SpAddSingleFileToCopyList(
  3574. SifHandle,
  3575. DiskFileLists,
  3576. DiskCount,
  3577. L"SCSI.Load",
  3578. pHw->IdString,
  3579. 0,
  3580. TargetDevicePath,
  3581. NULL,
  3582. COPY_ALWAYS,
  3583. FALSE
  3584. );
  3585. }
  3586. }
  3587. SpAddBusExtendersToCopyList( SifHandle,
  3588. DiskFileLists,
  3589. DiskCount,
  3590. TargetDevicePath );
  3591. #if 0
  3592. //
  3593. // If not being replaced by third-party ones, add keyboard and mouse
  3594. // class drivers.
  3595. // Note that in the pre-install case, keyboard and class drivers will
  3596. // be added if at least one retail mouse or keyborad driver are
  3597. // to be pre-installed.
  3598. //
  3599. if( !PreInstall ||
  3600. ( PreinstallHardwareComponents[HwComponentMouse] == NULL ) ) {
  3601. pHw=HardwareComponents[HwComponentMouse];
  3602. } else {
  3603. pHw=PreinstallHardwareComponents[HwComponentMouse];
  3604. }
  3605. for( ;pHw;pHw=pHw->Next ) {
  3606. if(!pHw->ThirdPartyOptionSelected
  3607. || !IS_FILETYPE_PRESENT(pHw->FileTypeBits,HwFileClass))
  3608. {
  3609. SpAddSingleFileToCopyList(
  3610. SifHandle,
  3611. DiskFileLists,
  3612. DiskCount,
  3613. SIF_SPECIALFILES,
  3614. SIF_MOUSECLASS,
  3615. 0,
  3616. TargetDevicePath,
  3617. NULL,
  3618. COPY_ALWAYS,
  3619. FALSE
  3620. );
  3621. //
  3622. // We don't need to continue to look at the other mouse drivers
  3623. // since we have already added the class driver
  3624. //
  3625. break;
  3626. }
  3627. }
  3628. if( !PreInstall ||
  3629. ( PreinstallHardwareComponents[HwComponentKeyboard] == NULL ) ) {
  3630. pHw=HardwareComponents[HwComponentKeyboard];
  3631. } else {
  3632. pHw=PreinstallHardwareComponents[HwComponentKeyboard];
  3633. }
  3634. for( ;pHw;pHw=pHw->Next ) {
  3635. if(!pHw->ThirdPartyOptionSelected
  3636. || !IS_FILETYPE_PRESENT(pHw->FileTypeBits,HwFileClass))
  3637. {
  3638. SpAddSingleFileToCopyList(
  3639. SifHandle,
  3640. DiskFileLists,
  3641. DiskCount,
  3642. SIF_SPECIALFILES,
  3643. SIF_KEYBOARDCLASS,
  3644. 0,
  3645. TargetDevicePath,
  3646. NULL,
  3647. COPY_ALWAYS,
  3648. FALSE
  3649. );
  3650. //
  3651. // We don't need to continue to look at the other keyboard drivers
  3652. // since we have already added the class driver
  3653. //
  3654. break;
  3655. }
  3656. }
  3657. #endif // if 0
  3658. if( ( HardwareComponents[HwComponentMouse] != NULL ) &&
  3659. ( _wcsicmp( (HardwareComponents[HwComponentMouse])->IdString, L"none" ) != 0)
  3660. ) {
  3661. SpAddSingleFileToCopyList(
  3662. SifHandle,
  3663. DiskFileLists,
  3664. DiskCount,
  3665. SIF_SPECIALFILES,
  3666. SIF_MOUSECLASS,
  3667. 0,
  3668. TargetDevicePath,
  3669. NULL,
  3670. COPY_ALWAYS,
  3671. FALSE
  3672. );
  3673. }
  3674. if( HardwareComponents[HwComponentKeyboard] != NULL ) {
  3675. SpAddSingleFileToCopyList(
  3676. SifHandle,
  3677. DiskFileLists,
  3678. DiskCount,
  3679. SIF_SPECIALFILES,
  3680. SIF_KEYBOARDCLASS,
  3681. 0,
  3682. TargetDevicePath,
  3683. NULL,
  3684. COPY_ALWAYS,
  3685. FALSE
  3686. );
  3687. }
  3688. }
  3689. VOID
  3690. SpDontOverwriteMigratedDrivers (
  3691. IN PWSTR SysrootDevice,
  3692. IN PWSTR Sysroot,
  3693. IN PWSTR SyspartDevice,
  3694. IN PWSTR SyspartDirectory,
  3695. IN PDISK_FILE_LIST DiskFileLists,
  3696. IN ULONG DiskCount
  3697. )
  3698. {
  3699. PLIST_ENTRY ListEntry;
  3700. PSP_MIG_DRIVER_ENTRY MigEntry;
  3701. while (!IsListEmpty(&MigratedDriversList)) {
  3702. ListEntry = RemoveHeadList(&MigratedDriversList);
  3703. MigEntry = CONTAINING_RECORD(ListEntry, SP_MIG_DRIVER_ENTRY, ListEntry);
  3704. SpRemoveEntryFromCopyList (
  3705. DiskFileLists,
  3706. DiskCount,
  3707. L"system32\\drivers",
  3708. MigEntry->BaseDllName,
  3709. SysrootDevice,
  3710. FALSE
  3711. );
  3712. SpMemFree(MigEntry->BaseDllName);
  3713. SpMemFree(MigEntry);
  3714. }
  3715. }
  3716. VOID
  3717. SpCopyThirdPartyDrivers(
  3718. IN PWSTR SourceDevicePath,
  3719. IN PWSTR SysrootDevice,
  3720. IN PWSTR Sysroot,
  3721. IN PWSTR SyspartDevice,
  3722. IN PWSTR SyspartDirectory,
  3723. IN PDISK_FILE_LIST DiskFileLists,
  3724. IN ULONG DiskCount
  3725. )
  3726. {
  3727. ULONG component;
  3728. PHARDWARE_COMPONENT pHw;
  3729. PHARDWARE_COMPONENT_FILE pHwFile;
  3730. FILE_TO_COPY FileDescriptor;
  3731. PWSTR TargetRoot;
  3732. PWSTR InfNameBases[HwComponentMax+1] = { L"cpt", L"vio", L"kbd", L"lay", L"ptr", L"scs" };
  3733. ULONG InfCounts[HwComponentMax+1] = { 0,0,0,0,0,0 };
  3734. WCHAR InfFilename[20];
  3735. ULONG CheckSum;
  3736. BOOLEAN FileSkipped;
  3737. ULONG TargetFileAttribs;
  3738. ULONG CopyFlags;
  3739. PWSTR OemDirPath;
  3740. BOOLEAN OemDirExists;
  3741. PWSTR NtOemSourceDevicePath;
  3742. //
  3743. // Find out if the %SystemRoot%\OemDir exists. This directory will be needed if the third party drivers
  3744. // istalled contain a catalog.
  3745. //
  3746. OemDirPath = SpMemAlloc(ACTUAL_MAX_PATH * sizeof(WCHAR));
  3747. wcscpy( OemDirPath, SysrootDevice );
  3748. SpConcatenatePaths( OemDirPath, Sysroot );
  3749. SpConcatenatePaths( OemDirPath, OemDirName );
  3750. OemDirExists = SpFileExists( OemDirPath, TRUE );
  3751. SpMemFree( OemDirPath );
  3752. OemDirPath = NULL;
  3753. for(component=0; component<=HwComponentMax; component++) {
  3754. //
  3755. // If we're upgrading, then we only want to copy third-party HALs or SCSI
  3756. // drivers (if supplied)
  3757. //
  3758. if((NTUpgrade == UpgradeFull) &&
  3759. !((component == HwComponentComputer) || (component == HwComponentMax))) {
  3760. continue;
  3761. }
  3762. //
  3763. // Handle scsi specially.
  3764. //
  3765. pHw = (component==HwComponentMax) ? ( ( !PreInstall ||
  3766. ( PreinstallScsiHardware == NULL )
  3767. )?
  3768. ScsiHardware :
  3769. PreinstallScsiHardware
  3770. )
  3771. :
  3772. ( ( !PreInstall ||
  3773. ( PreinstallHardwareComponents[component] == NULL )
  3774. )?
  3775. HardwareComponents[component] :
  3776. PreinstallHardwareComponents[component]
  3777. );
  3778. //
  3779. // Look at each instance of this component.
  3780. //
  3781. for( ; pHw; pHw=pHw->Next) {
  3782. BOOLEAN CatalogIsPresent;
  3783. BOOLEAN DynamicUpdateComponent = (IS_FILETYPE_PRESENT(pHw->FileTypeBits, HwFileDynUpdt) != 0);
  3784. //
  3785. // Skip this device if not a third-party selection.
  3786. //
  3787. if(!pHw->ThirdPartyOptionSelected) {
  3788. continue;
  3789. }
  3790. //
  3791. // Create the OemDir if necessary
  3792. //
  3793. if( !OemDirExists ) {
  3794. SpCreateDirectory( SysrootDevice,
  3795. Sysroot,
  3796. OemDirName,
  3797. 0,
  3798. 0 );
  3799. OemDirExists = TRUE;
  3800. }
  3801. //
  3802. // Find out if a catalog was provided with this third party driver
  3803. //
  3804. for(CatalogIsPresent=FALSE, pHwFile=pHw->Files; pHwFile; pHwFile=pHwFile->Next) {
  3805. if(pHwFile->FileType == HwFileCatalog) {
  3806. CatalogIsPresent = TRUE;
  3807. break;
  3808. }
  3809. }
  3810. //
  3811. // Loop through the list of files associated with this selection.
  3812. //
  3813. for(pHwFile=pHw->Files; pHwFile; pHwFile=pHwFile->Next) {
  3814. //
  3815. // Assume the file goes on the nt drive (as opposed to
  3816. // the system partition drive) and that the target name
  3817. // is the same as the source name. Also, assume no special
  3818. // attributes (ie, FILE_ATTRIBUTE_NORMAL)
  3819. //
  3820. FileDescriptor.Next = NULL;
  3821. FileDescriptor.SourceFilename = pHwFile->Filename;
  3822. FileDescriptor.TargetDevicePath = SysrootDevice;
  3823. FileDescriptor.TargetFilename = FileDescriptor.SourceFilename;
  3824. FileDescriptor.Flags = COPY_ALWAYS;
  3825. FileDescriptor.AbsoluteTargetDirectory = FALSE;
  3826. TargetFileAttribs = 0;
  3827. NtOemSourceDevicePath = NULL;
  3828. if (pHwFile->ArcDeviceName) {
  3829. NtOemSourceDevicePath = SpArcToNt(pHwFile->ArcDeviceName);
  3830. }
  3831. if (!NtOemSourceDevicePath) {
  3832. NtOemSourceDevicePath = SourceDevicePath;
  3833. }
  3834. switch(pHwFile->FileType) {
  3835. //
  3836. // Driver, port, and class type files are all device drivers
  3837. // and are treated the same -- they get copied to the
  3838. // system32\drivers directory.
  3839. //
  3840. case HwFileDriver:
  3841. case HwFilePort:
  3842. case HwFileClass:
  3843. TargetRoot = Sysroot;
  3844. FileDescriptor.TargetDirectory = L"system32\\drivers";
  3845. break;
  3846. //
  3847. // Dlls get copied to the system32 directory.
  3848. //
  3849. case HwFileDll:
  3850. TargetRoot = Sysroot;
  3851. FileDescriptor.TargetDirectory = L"system32";
  3852. break;
  3853. //
  3854. // Catalogs get copied to the OemDir directory.
  3855. //
  3856. case HwFileCatalog:
  3857. TargetRoot = Sysroot;
  3858. FileDescriptor.TargetDirectory = OemDirName;
  3859. break;
  3860. //
  3861. // Inf files get copied to the system32 directory and are
  3862. // renamed based on the component.
  3863. //
  3864. case HwFileInf:
  3865. if(InfCounts[component] < 99) {
  3866. InfCounts[component]++; // names start at 1
  3867. swprintf(
  3868. InfFilename,
  3869. L"oem%s%02d.inf",
  3870. InfNameBases[component],
  3871. InfCounts[component]
  3872. );
  3873. FileDescriptor.TargetFilename = InfFilename;
  3874. }
  3875. TargetRoot = Sysroot;
  3876. FileDescriptor.TargetDirectory = OemDirName;
  3877. break;
  3878. //
  3879. // Hal files are renamed to hal.dll and copied to the system32
  3880. // directory
  3881. //
  3882. case HwFileHal:
  3883. TargetRoot = Sysroot;
  3884. FileDescriptor.TargetDirectory = L"system32";
  3885. FileDescriptor.TargetFilename = L"hal.dll";
  3886. break;
  3887. //
  3888. // Detect modules are renamed to ntdetect.com and copied to
  3889. // the root of the system partition (C:).
  3890. //
  3891. case HwFileDetect:
  3892. TargetRoot = NULL;
  3893. FileDescriptor.TargetDevicePath = SyspartDevice;
  3894. FileDescriptor.TargetDirectory = SyspartDirectory;
  3895. FileDescriptor.TargetFilename = L"ntdetect.com";
  3896. TargetFileAttribs = ATTR_RHS;
  3897. break;
  3898. }
  3899. if( !PreInstall && !DynamicUpdateComponent) {
  3900. //
  3901. // Prompt for the disk.
  3902. //
  3903. SpPromptForDisk(
  3904. pHwFile->DiskDescription,
  3905. NtOemSourceDevicePath,
  3906. pHwFile->DiskTagFile,
  3907. FALSE, // don't ignore disk in drive
  3908. FALSE, // don't allow escape
  3909. FALSE, // don't warn about multiple prompts
  3910. NULL // don't care about redraw flag
  3911. );
  3912. }
  3913. //
  3914. // Passing the empty string as the first arg forces
  3915. // the action area of the status line to be set up.
  3916. // Not doing so results in the "Copying: xxxxx" to be
  3917. // flush left on the status line instead of where
  3918. // it belongs (flush right).
  3919. //
  3920. SpCopyFilesScreenRepaint(L"",NULL,TRUE);
  3921. //
  3922. // Copy the file.
  3923. //
  3924. SpCopyFileWithRetry(
  3925. &FileDescriptor,
  3926. NtOemSourceDevicePath,
  3927. (PreInstall) ? PreinstallOemSourcePath : pHwFile->Directory,
  3928. NULL,
  3929. TargetRoot,
  3930. TargetFileAttribs,
  3931. SpCopyFilesScreenRepaint,
  3932. &CheckSum,
  3933. &FileSkipped,
  3934. COPY_SOURCEISOEM
  3935. );
  3936. //
  3937. // Log the file
  3938. //
  3939. if( !FileSkipped ) {
  3940. //
  3941. // Catalog files don't need to be logged, since they don't need to be repaired.
  3942. //
  3943. if ( pHwFile->FileType != HwFileCatalog ) {
  3944. SpLogOneFile( &FileDescriptor,
  3945. TargetRoot,
  3946. pHwFile->Directory,
  3947. pHwFile->DiskDescription,
  3948. pHwFile->DiskTagFile,
  3949. CheckSum );
  3950. }
  3951. //
  3952. // If a catalog is part of the third party driver being installed, then we need to copy
  3953. // the file to OemDir also. Note that we don't copy the catalog to the OemDir directory,
  3954. // since it was already copied.
  3955. //
  3956. if(pHwFile->FileType != HwFileCatalog){
  3957. //
  3958. // Save off original target directory.
  3959. //
  3960. PWSTR SpOriginalTargetDir = FileDescriptor.TargetDirectory;
  3961. FileDescriptor.TargetDirectory = OemDirName;
  3962. SpCopyFileWithRetry(
  3963. &FileDescriptor,
  3964. NtOemSourceDevicePath,
  3965. (PreInstall)? PreinstallOemSourcePath : pHwFile->Directory,
  3966. NULL,
  3967. TargetRoot,
  3968. TargetFileAttribs,
  3969. SpCopyFilesScreenRepaint,
  3970. &CheckSum,
  3971. &FileSkipped,
  3972. COPY_SOURCEISOEM
  3973. );
  3974. //
  3975. // If this was an inf file then we need to remember its name
  3976. //
  3977. if( pHwFile->FileType == HwFileInf ) {
  3978. POEM_INF_FILE p;
  3979. p = SpMemAlloc( sizeof(OEM_INF_FILE) );
  3980. p->InfName = SpDupStringW( FileDescriptor.TargetFilename );
  3981. p->Next = OemInfFileList;
  3982. OemInfFileList = p;
  3983. }
  3984. //
  3985. // Restore original target directory so as to remove the correct
  3986. // entry from the file list to copy.
  3987. //
  3988. if (SpOriginalTargetDir){
  3989. FileDescriptor.TargetDirectory = SpOriginalTargetDir;
  3990. SpOriginalTargetDir = NULL;
  3991. }
  3992. }
  3993. }
  3994. //
  3995. // Remove the file from the copy list so that it won't be overwritten
  3996. //
  3997. SpRemoveEntryFromCopyList( DiskFileLists,
  3998. DiskCount,
  3999. FileDescriptor.TargetDirectory,
  4000. FileDescriptor.TargetFilename,
  4001. FileDescriptor.TargetDevicePath,
  4002. FileDescriptor.AbsoluteTargetDirectory );
  4003. }
  4004. }
  4005. }
  4006. }
  4007. #ifdef _X86_
  4008. VOID
  4009. SpCopyNtbootddScreenRepaint(
  4010. IN PWSTR FullSourcename, OPTIONAL
  4011. IN PWSTR FullTargetname, OPTIONAL
  4012. IN BOOLEAN RepaintEntireScreen
  4013. )
  4014. {
  4015. UNREFERENCED_PARAMETER(FullSourcename);
  4016. UNREFERENCED_PARAMETER(FullTargetname);
  4017. UNREFERENCED_PARAMETER(RepaintEntireScreen);
  4018. //
  4019. // Just put up a message indicating that we are setting up
  4020. // boot params.
  4021. //
  4022. CLEAR_CLIENT_SCREEN();
  4023. SpDisplayStatusText(SP_STAT_DOING_NTBOOTDD,DEFAULT_STATUS_ATTRIBUTE);
  4024. }
  4025. BOOLEAN
  4026. FindFalsexInt13Support(
  4027. IN PVOID SifHandle
  4028. )
  4029. /*++
  4030. Routine Description:
  4031. Go look through the devices installed and see if any match our
  4032. list of known devices that may lie to us about their support for
  4033. xInt13.
  4034. Arguments:
  4035. SifHandle - supplies handle to loaded setup information file.
  4036. Return Value:
  4037. TRUE - We found a match.
  4038. FALSE otherwise
  4039. --*/
  4040. {
  4041. HARDWAREIDLIST *MyHardwareIDList = HardwareIDList;
  4042. while( MyHardwareIDList ) {
  4043. if( MyHardwareIDList->HardwareID ) {
  4044. if( SpGetSectionKeyExists(SifHandle, L"BadXInt13Devices", MyHardwareIDList->HardwareID) ) {
  4045. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: FindFalsexInt13Support: Found it.\n" ));
  4046. return TRUE;
  4047. }
  4048. }
  4049. MyHardwareIDList = MyHardwareIDList->Next;
  4050. }
  4051. return FALSE;
  4052. }
  4053. BOOL
  4054. SpUseBIOSToBoot(
  4055. IN PDISK_REGION NtPartitionRegion,
  4056. IN PWSTR NtPartitionDevicePath,
  4057. IN PVOID SifHandle
  4058. )
  4059. /*++
  4060. Routine Description:
  4061. Determine if we need a mini port driver to boot or if we can rely
  4062. on the BIOS.
  4063. Arguments:
  4064. NtPartitionRegion - supplies the region descriptor for the disk region
  4065. onto which the user chose to install Windows NT.
  4066. NtPartitionDevicePath - supplies the nt namespace pathname for the
  4067. partition onto which the user chose to install Windows NT.
  4068. SifHandle - supplies handle to loaded setup information file.
  4069. Return Value:
  4070. TRUE - we can safely rely on the BIOS to boot.
  4071. FALSE - we will need a mini port driver to boot.
  4072. --*/
  4073. {
  4074. PDISK_SIGNATURE_INFORMATION DiskSignature;
  4075. PWSTR p;
  4076. if( ForceBIOSBoot ) {
  4077. //
  4078. // Either the user has asked us to force the use of the BIOS
  4079. // to boot, or we've already manually checked and determined
  4080. // that it's okay to use the BIOS.
  4081. //
  4082. return TRUE;
  4083. }
  4084. //
  4085. // This may be the first time we've been called. see if the user
  4086. // wants us to force a BIOS boot.
  4087. //
  4088. p = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,L"UseBIOSToBoot",0);
  4089. if( p != NULL ) {
  4090. //
  4091. // The user wants us to use the BIOS. Set our global and
  4092. // get out of here.
  4093. //
  4094. ForceBIOSBoot = TRUE;
  4095. return TRUE;
  4096. }
  4097. //
  4098. // The NtPartitionDevicePath may or may not be available to the
  4099. // caller. If it isn't, then attempt to derive it from the
  4100. // NtPartitionRegion.
  4101. //
  4102. if( NtPartitionDevicePath ) {
  4103. p = SpNtToArc( NtPartitionDevicePath, PrimaryArcPath );
  4104. } else {
  4105. p = SpMemAlloc( (MAX_PATH*2) );
  4106. if( p ) {
  4107. SpArcNameFromRegion( NtPartitionRegion,
  4108. p,
  4109. (MAX_PATH*2),
  4110. PartitionOrdinalOnDisk,
  4111. PrimaryArcPath );
  4112. }
  4113. }
  4114. if(p) {
  4115. if( _wcsnicmp(p,L"multi(",6) == 0 ) {
  4116. if( !SpIsRegionBeyondCylinder1024(NtPartitionRegion) ) {
  4117. //
  4118. // This region is very small, so we won't be needing
  4119. // a miniport to boot.
  4120. //
  4121. ForceBIOSBoot = TRUE;
  4122. } else {
  4123. //
  4124. // Hang on. This disk is big, but it may support xint13. In
  4125. // that case we won't need a miniport. Luckily, we have that
  4126. // information stored away.
  4127. //
  4128. DiskSignature = DiskSignatureInformation;
  4129. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: About to search through the DiskSignatureInformation database for a device called %ws\n", p ));
  4130. while( DiskSignature != NULL ) {
  4131. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: this DiskSignatureInformation entry is called %ws\n", DiskSignature->ArcPath ));
  4132. if( !_wcsnicmp( p, DiskSignature->ArcPath, wcslen(DiskSignature->ArcPath) ) ) {
  4133. //
  4134. // We found our disk. Now just check his support for xint13.
  4135. //
  4136. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: I think they matched.\n" ));
  4137. if( DiskSignature->xInt13 ) {
  4138. //
  4139. // Yep, he's going to support xint13, so there's
  4140. // nothing for us to do here.
  4141. //
  4142. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: I think he's got xInt13 support.\n" ));
  4143. //
  4144. // But it's possible that the BIOS has lied to us about his xInt13
  4145. // support. We want to go check txtsetup.sif and see if this is a
  4146. // known controller that we don't support.
  4147. //
  4148. if( HardDisks[NtPartitionRegion->DiskNumber].Description[0] ) {
  4149. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: His description is: %ws\n", HardDisks[NtPartitionRegion->DiskNumber].Description ));
  4150. } else {
  4151. //
  4152. // Odd... This guy doesn't have a description.
  4153. //
  4154. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: This device has no description!\n" ));
  4155. }
  4156. //
  4157. // Now go look in txtsetup.sif and see if this is listed as a device
  4158. // that I don't believe.
  4159. //
  4160. if( FindFalsexInt13Support(SifHandle) ) {
  4161. //
  4162. // We think this guy might be lying to us when he tells
  4163. // us that he supports xint13. Assume that he really
  4164. // doesn't, which means we'll be using a miniport to
  4165. // boot.
  4166. //
  4167. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: This machine has a device that may erroneously indicate its xint13 support.\n" ));
  4168. break;
  4169. } else {
  4170. //
  4171. // This device isn't lised in the list that
  4172. // we don't believe, so assume that he
  4173. // really does have xint13 support.
  4174. //
  4175. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpCreateNtbootddSys: I trust this device when he tells me he has xint13 support.\n" ));
  4176. //
  4177. // Remember that we're going to use the BIOS to boot rather than
  4178. // a miniport.
  4179. //
  4180. ForceBIOSBoot = TRUE;
  4181. break;
  4182. }
  4183. } else {
  4184. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: I don't think he has xInt13 support.\n" ));
  4185. }
  4186. } else {
  4187. //
  4188. // This isn't the right region. Fall through and look at
  4189. // the next one.
  4190. //
  4191. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpUseBIOSToBoot: They didn't match.\n" ));
  4192. }
  4193. DiskSignature = DiskSignature->Next;
  4194. }
  4195. }
  4196. }
  4197. SpMemFree(p);
  4198. }
  4199. return ForceBIOSBoot;
  4200. }
  4201. VOID
  4202. SpCreateNtbootddSys(
  4203. IN PDISK_REGION NtPartitionRegion,
  4204. IN PWSTR NtPartitionDevicePath,
  4205. IN PWSTR Sysroot,
  4206. IN PWSTR SystemPartitionDevicePath,
  4207. IN PVOID SifHandle,
  4208. IN PWSTR SourceDevicePath,
  4209. IN PWSTR DirectoryOnSourceDevice
  4210. )
  4211. /*++
  4212. Routine Description:
  4213. Create c:\ntbootdd.sys if necessary.
  4214. The scsi miniport driver file will be copied from the drivers directory
  4215. (where it was copied during the earlier file copy phase) to c:\ntbootdd.sys.
  4216. In the atapi case, the file ataboot.sys will be copied from the media to
  4217. c:\ntbootdd.sys.
  4218. NOTE: We're not going to support this on atapi devices anymore. However,
  4219. I'm leaving the code here in case we want to do it again later. This code
  4220. should execute early because I've modifed SpGetDiskInfo, so that
  4221. ScsiMiniportShortname won't ever get set for atapi devices. -matth
  4222. Arguments:
  4223. NtPartitionRegion - supplies the region descriptor for the disk region
  4224. onto which the user chose to install Windows NT.
  4225. NtPartitionDevicePath - supplies the nt namespace pathname for the
  4226. partition onto which the user chose to install Windows NT.
  4227. Sysroot - supplies the directory on the target partition.
  4228. SystemPartitionDevicePath - supplies the nt device path of the partition
  4229. onto which to copy ntbootdd.sys (ie, C:\).
  4230. SifHandle - supplies handle to loaded setup information file.
  4231. SourceDevicePath- Path to the device that contains the source.
  4232. DirectoryOnSourceDevice - Supplies the directory on the source where
  4233. the file is to be found.
  4234. Return Value:
  4235. None.
  4236. --*/
  4237. {
  4238. PWSTR MiniportDriverBasename;
  4239. PWSTR MiniportDriverFilename;
  4240. FILE_TO_COPY Descriptor;
  4241. PWSTR DriversDirectory,p;
  4242. ULONG CheckSum;
  4243. BOOLEAN FileSkipped;
  4244. ULONG CopyFlags;
  4245. BOOLEAN IsAtapi = FALSE;
  4246. //
  4247. // no PC98 need NTBOOTDD.SYS.
  4248. //
  4249. if (IsNEC_98) {
  4250. return;
  4251. }
  4252. #if defined(REMOTE_BOOT)
  4253. //
  4254. // If the NT partition is on DiskNumber -1, this is a remote boot setup,
  4255. // so there's nothing to do.
  4256. //
  4257. if (NtPartitionRegion->DiskNumber == 0xffffffff) {
  4258. return;
  4259. }
  4260. #endif // defined(REMOTE_BOOT)
  4261. //
  4262. // If the Nt Partition is not on a scsi disk, there's nothing to do.
  4263. //
  4264. MiniportDriverBasename = HardDisks[NtPartitionRegion->DiskNumber].ScsiMiniportShortname;
  4265. if(*MiniportDriverBasename == 0) {
  4266. return;
  4267. }
  4268. if( SpUseBIOSToBoot(NtPartitionRegion, NtPartitionDevicePath, SifHandle) ) {
  4269. //
  4270. // We can use the BIOS, so there's no reason to continue.
  4271. //
  4272. return;
  4273. }
  4274. IsAtapi = (_wcsicmp(MiniportDriverBasename,L"atapi") == 0);
  4275. if( !IsAtapi ) {
  4276. //
  4277. // Form the name of the scsi miniport driver.
  4278. //
  4279. wcscpy(TemporaryBuffer,MiniportDriverBasename);
  4280. wcscat(TemporaryBuffer,L".sys");
  4281. } else {
  4282. wcscpy(TemporaryBuffer,L"ataboot.sys");
  4283. }
  4284. MiniportDriverFilename = SpDupStringW(TemporaryBuffer);
  4285. if( !IsAtapi ) {
  4286. //
  4287. // Form the full path to the drivers directory.
  4288. //
  4289. wcscpy(TemporaryBuffer,Sysroot);
  4290. SpConcatenatePaths(TemporaryBuffer,L"system32\\drivers");
  4291. } else {
  4292. //
  4293. // If it is atapi then make DriversDirectory point to the source media
  4294. //
  4295. PWSTR MediaShortName;
  4296. PWSTR MediaDirectory;
  4297. MediaShortName = SpLookUpValueForFile( SifHandle,
  4298. MiniportDriverFilename, // L"ataboot.sys",
  4299. INDEX_WHICHMEDIA,
  4300. TRUE );
  4301. SpGetSourceMediaInfo(SifHandle,MediaShortName,NULL,NULL,&MediaDirectory);
  4302. wcscpy(TemporaryBuffer,DirectoryOnSourceDevice);
  4303. SpConcatenatePaths(TemporaryBuffer,MediaDirectory);
  4304. }
  4305. DriversDirectory = SpDupStringW(TemporaryBuffer);
  4306. //
  4307. //
  4308. // Fill in the fields of the file descriptor.
  4309. //
  4310. Descriptor.SourceFilename = MiniportDriverFilename;
  4311. Descriptor.TargetDevicePath = SystemPartitionDevicePath;
  4312. Descriptor.TargetDirectory = L"";
  4313. Descriptor.TargetFilename = L"NTBOOTDD.SYS";
  4314. Descriptor.Flags = COPY_ALWAYS;
  4315. CopyFlags = 0;
  4316. if(!WIN9X_OR_NT_UPGRADE || IsFileFlagSet(SifHandle,Descriptor.TargetFilename,FILEFLG_NOVERSIONCHECK)) {
  4317. CopyFlags |= COPY_NOVERSIONCHECK;
  4318. }
  4319. //
  4320. // Copy the file.
  4321. //
  4322. SpCopyFileWithRetry(
  4323. &Descriptor,
  4324. (IsAtapi) ? SourceDevicePath : NtPartitionDevicePath,
  4325. DriversDirectory,
  4326. NULL,
  4327. NULL,
  4328. ATTR_RHS,
  4329. SpCopyNtbootddScreenRepaint,
  4330. &CheckSum,
  4331. &FileSkipped,
  4332. CopyFlags
  4333. );
  4334. //
  4335. // Log the file
  4336. //
  4337. if( !FileSkipped ) {
  4338. SpLogOneFile( &Descriptor,
  4339. Sysroot,
  4340. NULL,
  4341. NULL,
  4342. NULL,
  4343. CheckSum );
  4344. }
  4345. //
  4346. // Clean up.
  4347. //
  4348. SpMemFree(MiniportDriverFilename);
  4349. SpMemFree(DriversDirectory);
  4350. }
  4351. #endif
  4352. VOID
  4353. SpCopyFiles(
  4354. IN PVOID SifHandle,
  4355. IN PDISK_REGION SystemPartitionRegion,
  4356. IN PDISK_REGION NtPartitionRegion,
  4357. IN PWSTR Sysroot,
  4358. IN PWSTR SystemPartitionDirectory,
  4359. IN PWSTR SourceDevicePath,
  4360. IN PWSTR DirectoryOnSourceDevice,
  4361. IN PWSTR ThirdPartySourceDevicePath
  4362. )
  4363. {
  4364. PDISK_FILE_LIST DiskFileLists;
  4365. ULONG DiskCount;
  4366. PWSTR NtPartition,SystemPartition;
  4367. PWSTR p;
  4368. BOOLEAN Uniprocessor;
  4369. ULONG n;
  4370. NTSTATUS Status;
  4371. OBJECT_ATTRIBUTES ObjectAttributes;
  4372. UNICODE_STRING NtPartitionString;
  4373. IO_STATUS_BLOCK IoStatusBlock;
  4374. INCOMPATIBLE_FILE_LIST IncompatibleFileListHead;
  4375. CLEAR_CLIENT_SCREEN();
  4376. Uniprocessor = !SpInstallingMp();
  4377. //
  4378. // open a handle to the driver inf file
  4379. //
  4380. SpInitializeDriverInf(SifHandle,
  4381. SourceDevicePath,
  4382. DirectoryOnSourceDevice);
  4383. //
  4384. // initialize alternate sources (if any)
  4385. //
  4386. SpInitAlternateSource ();
  4387. //
  4388. // Skip copying if directed to do so in the setup information file.
  4389. //
  4390. if((p = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SIF_DONTCOPY,0))
  4391. && SpStringToLong(p,NULL,10))
  4392. {
  4393. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DontCopy flag is set in .sif; skipping file copying\n"));
  4394. return;
  4395. }
  4396. //
  4397. // Initialize the diamond decompression engine. In the remote boot
  4398. // case this will already have been initialized.
  4399. //
  4400. if (!RemoteInstallSetup) {
  4401. SpdInitialize();
  4402. }
  4403. //
  4404. // Get the device path of the nt partition.
  4405. //
  4406. SpNtNameFromRegion(
  4407. NtPartitionRegion,
  4408. TemporaryBuffer,
  4409. sizeof(TemporaryBuffer),
  4410. PartitionOrdinalCurrent
  4411. );
  4412. NtPartition = SpDupStringW(TemporaryBuffer);
  4413. //
  4414. // Get the device path of the system partition.
  4415. //
  4416. if (SystemPartitionRegion != NULL) {
  4417. SpNtNameFromRegion(
  4418. SystemPartitionRegion,
  4419. TemporaryBuffer,
  4420. sizeof(TemporaryBuffer),
  4421. PartitionOrdinalCurrent
  4422. );
  4423. SystemPartition = SpDupStringW(TemporaryBuffer);
  4424. } else {
  4425. SystemPartition = NULL;
  4426. }
  4427. //
  4428. // Create the system partition directory.
  4429. //
  4430. if (SystemPartition != NULL) {
  4431. SpCreateDirectory(SystemPartition,NULL,SystemPartitionDirectory,0,0);
  4432. #ifdef _IA64_
  4433. {
  4434. PWSTR SubDirPath = SpGetSectionKeyIndex(
  4435. SifHandle,
  4436. L"SetupData",
  4437. L"EfiUtilPath",
  4438. 0
  4439. );
  4440. SpCreateDirectory(SystemPartition,NULL,SubDirPath,0,0);
  4441. }
  4442. #endif // defined _IA64_
  4443. }
  4444. //
  4445. // Create the nt tree.
  4446. //
  4447. SpCreateDirectoryStructureFromSif(SifHandle,SIF_NTDIRECTORIES,NtPartition,Sysroot);
  4448. //
  4449. // We may be installing into an old tree, so delete all files
  4450. // in the system32\config subdirectory (unless we're upgrading).
  4451. //
  4452. if(NTUpgrade != UpgradeFull) {
  4453. wcscpy(TemporaryBuffer, NtPartition);
  4454. SpConcatenatePaths(TemporaryBuffer, Sysroot);
  4455. SpConcatenatePaths(TemporaryBuffer, L"system32\\config");
  4456. p = SpDupStringW(TemporaryBuffer);
  4457. //
  4458. // Enumerate and delete all files in system32\config subdirectory.
  4459. //
  4460. SpEnumFiles(p, SpDelEnumFile, &n, NULL);
  4461. SpMemFree(p);
  4462. } else {
  4463. //
  4464. // We go off and try to load the setup.log file for the
  4465. // installation we're about to upgrade. We do this because we
  4466. // need to transfer any loggged OEM files to our new setup.log.
  4467. // Otherwise, these entries would be lost in our new log file,
  4468. // and we would have an unrepairable installation if the OEM files
  4469. // lost were vital for booting.
  4470. //
  4471. ULONG RootDirLength;
  4472. NTSTATUS Status;
  4473. PVOID Inf;
  4474. //
  4475. // We first find out if the repair directory exists. If it does exist
  4476. // load setup.log from the repair directory. Otherwise, load setup.log
  4477. // from the WinNt directory
  4478. //
  4479. wcscpy(TemporaryBuffer, NtPartition);
  4480. SpConcatenatePaths(TemporaryBuffer, Sysroot);
  4481. RootDirLength = wcslen(TemporaryBuffer);
  4482. SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
  4483. SpConcatenatePaths(TemporaryBuffer, SETUP_LOG_FILENAME);
  4484. if(!SpFileExists(TemporaryBuffer, FALSE)) {
  4485. (TemporaryBuffer)[RootDirLength] = UNICODE_NULL;
  4486. SpConcatenatePaths(TemporaryBuffer, SETUP_LOG_FILENAME);
  4487. }
  4488. p = SpDupStringW(TemporaryBuffer);
  4489. //
  4490. // Attempt to load old setup.log. If we can't, it's no big deal, We just
  4491. // won't have any old logged OEM files to merge in.
  4492. //
  4493. Status = SpLoadSetupTextFile(p, NULL, 0, &Inf, &n, TRUE, FALSE);
  4494. if(!NT_SUCCESS(Status)) {
  4495. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCopyFiles: can't load old setup.log (%lx)\n", Status));
  4496. } else {
  4497. //
  4498. // We found setup.log, so go and pull out anything pertinent.
  4499. //
  4500. _LoggedOemFiles = SppRetrieveLoggedOemFiles(Inf);
  4501. SpFreeTextFile(Inf);
  4502. }
  4503. SpMemFree(p);
  4504. //
  4505. // Prepare fonts for upgrade.
  4506. //
  4507. wcscpy(TemporaryBuffer,NtPartition);
  4508. SpConcatenatePaths(TemporaryBuffer,Sysroot);
  4509. SpConcatenatePaths(TemporaryBuffer,L"SYSTEM");
  4510. p = SpDupStringW(TemporaryBuffer);
  4511. SpPrepareFontsForUpgrade(p);
  4512. SpMemFree(p);
  4513. }
  4514. SpDisplayStatusText(SP_STAT_BUILDING_COPYLIST,DEFAULT_STATUS_ATTRIBUTE);
  4515. //
  4516. // Create the buffer for the log file.
  4517. //
  4518. _SetupLogFile = SpNewSetupTextFile();
  4519. if( _SetupLogFile == NULL ) {
  4520. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to create buffer for setup.log \n"));
  4521. }
  4522. #if defined(REMOTE_BOOT)
  4523. //
  4524. // If this is a remote boot setup, open the root of the NT partition
  4525. // so that single-instance store links may be created instead of
  4526. // copying files.
  4527. //
  4528. SisRootHandle = NULL;
  4529. if (RemoteBootSetup) {
  4530. RtlInitUnicodeString( &NtPartitionString, NtPartition );
  4531. InitializeObjectAttributes(
  4532. &ObjectAttributes,
  4533. &NtPartitionString,
  4534. OBJ_CASE_INSENSITIVE,
  4535. NULL,
  4536. NULL);
  4537. Status = ZwCreateFile(
  4538. &SisRootHandle,
  4539. GENERIC_READ,
  4540. &ObjectAttributes,
  4541. &IoStatusBlock,
  4542. NULL,
  4543. 0,
  4544. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4545. OPEN_EXISTING,
  4546. 0,
  4547. NULL,
  4548. 0);
  4549. if (!NT_SUCCESS(Status)) {
  4550. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpCopyFiles: Unable to open SIS volume %ws: %x\n", NtPartition, Status ));
  4551. SisRootHandle = NULL;
  4552. }
  4553. }
  4554. #endif // defined(REMOTE_BOOT)
  4555. //
  4556. // Generate media descriptors for the source media.
  4557. //
  4558. SpInitializeFileLists(
  4559. SifHandle,
  4560. &DiskFileLists,
  4561. &DiskCount
  4562. );
  4563. //
  4564. // And gather the list of files deemed 'incompatible' during
  4565. // winnt32, if any
  4566. //
  4567. if ( WinntSifHandle != NULL ) {
  4568. //
  4569. // We'll do this for fun because we have to.
  4570. //
  4571. SpInitializeCompatibilityOverwriteLists(
  4572. WinntSifHandle,
  4573. &IncompatibleFileListHead
  4574. );
  4575. }
  4576. if(NTUpgrade != UpgradeFull) {
  4577. SpAddMasterFileSectionToCopyList(
  4578. SifHandle,
  4579. DiskFileLists,
  4580. DiskCount,
  4581. NtPartition,
  4582. NULL,
  4583. INDEX_WINNTFILE
  4584. );
  4585. //
  4586. // Add the section of system partition files that are always copied.
  4587. //
  4588. SpAddSectionFilesToCopyList(
  4589. SifHandle,
  4590. DiskFileLists,
  4591. DiskCount,
  4592. SIF_SYSPARTCOPYALWAYS,
  4593. SystemPartition,
  4594. SystemPartitionDirectory,
  4595. COPY_ALWAYS,
  4596. (BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
  4597. );
  4598. #ifdef _IA64_
  4599. {
  4600. PWSTR SubDirPath;
  4601. //
  4602. // Add the section of system partition root files that are always copied.
  4603. //
  4604. SpAddSectionFilesToCopyList(
  4605. SifHandle,
  4606. DiskFileLists,
  4607. DiskCount,
  4608. SIF_SYSPARTROOT,
  4609. SystemPartition,
  4610. L"\\",
  4611. COPY_ALWAYS,
  4612. (BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
  4613. );
  4614. //
  4615. // Add the section of system partition utility files that are always copied.
  4616. //
  4617. SubDirPath = SpGetSectionKeyIndex(
  4618. SifHandle,
  4619. L"SetupData",
  4620. L"EfiUtilPath",
  4621. 0
  4622. );
  4623. SpAddSectionFilesToCopyList(
  4624. SifHandle,
  4625. DiskFileLists,
  4626. DiskCount,
  4627. SIF_SYSPARTUTIL,
  4628. SystemPartition,
  4629. SubDirPath,
  4630. COPY_ALWAYS,
  4631. (BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
  4632. );
  4633. }
  4634. #endif // defined _IA64_
  4635. //
  4636. // Add conditional files to the copy list.
  4637. //
  4638. SpAddConditionalFilesToCopyList(
  4639. SifHandle,
  4640. DiskFileLists,
  4641. DiskCount,
  4642. NtPartition,
  4643. SystemPartition,
  4644. SystemPartitionDirectory,
  4645. Uniprocessor
  4646. );
  4647. }
  4648. else {
  4649. PHARDWARE_COMPONENT pHw;
  4650. //
  4651. // Add the section of system partition files that are always copied.
  4652. //
  4653. SpAddSectionFilesToCopyList(
  4654. SifHandle,
  4655. DiskFileLists,
  4656. DiskCount,
  4657. SIF_SYSPARTCOPYALWAYS,
  4658. SystemPartition,
  4659. SystemPartitionDirectory,
  4660. COPY_ALWAYS,
  4661. (BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
  4662. );
  4663. #ifdef _IA64_
  4664. {
  4665. PWSTR SubDirPath;
  4666. //
  4667. // Add the section of system partition root files that are always copied.
  4668. //
  4669. SpAddSectionFilesToCopyList(
  4670. SifHandle,
  4671. DiskFileLists,
  4672. DiskCount,
  4673. SIF_SYSPARTROOT,
  4674. SystemPartition,
  4675. L"\\",
  4676. COPY_ALWAYS,
  4677. (BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
  4678. );
  4679. //
  4680. // Add the section of system partition utility files that are always copied.
  4681. //
  4682. SubDirPath = SpGetSectionKeyIndex(
  4683. SifHandle,
  4684. L"SetupData",
  4685. L"EfiUtilPath",
  4686. 0
  4687. );
  4688. SpAddSectionFilesToCopyList(
  4689. SifHandle,
  4690. DiskFileLists,
  4691. DiskCount,
  4692. SIF_SYSPARTUTIL,
  4693. SystemPartition,
  4694. SubDirPath,
  4695. COPY_ALWAYS,
  4696. (BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
  4697. );
  4698. }
  4699. #endif // defined _IA64_
  4700. //
  4701. // Add the detected scsi miniport drivers to the copy list.
  4702. // Note that they are always copied to the target.
  4703. // These files have to be added to the copy list, before the ones marked
  4704. // as COPY_ONLY_IF_PRESENT. This is because in most cases, these files
  4705. // will be listed in [Files] with COPY_ONLY_IF_PRESENT set, and the
  4706. // function that creates entries in the copy list, will not create more
  4707. // than one entry for the same file. So if we add the file to the copy
  4708. // list, with COPY_ONLY_IF_PRESENT, there will be no way to replace
  4709. // or overwrite this entry in the list, and the file will end up not
  4710. // being copied.
  4711. //
  4712. // we just use the filename specified in [SCSI.Load] --
  4713. // no need for separate [files.xxxx] sections.
  4714. //
  4715. if( !PreInstall ||
  4716. ( PreinstallScsiHardware == NULL ) ) {
  4717. pHw = ScsiHardware;
  4718. } else {
  4719. pHw = PreinstallScsiHardware;
  4720. }
  4721. for( ; pHw; pHw=pHw->Next) {
  4722. if(!pHw->ThirdPartyOptionSelected) {
  4723. SpAddSingleFileToCopyList(
  4724. SifHandle,
  4725. DiskFileLists,
  4726. DiskCount,
  4727. L"SCSI.Load",
  4728. pHw->IdString,
  4729. 0,
  4730. NtPartition,
  4731. NULL,
  4732. COPY_ALWAYS,
  4733. FALSE
  4734. );
  4735. }
  4736. }
  4737. //
  4738. // Add the bus extender drivers to the copy list
  4739. //
  4740. SpAddBusExtendersToCopyList( SifHandle,
  4741. DiskFileLists,
  4742. DiskCount,
  4743. NtPartition );
  4744. //
  4745. // Add the files in the master file list with the copy options
  4746. // specified in each line on the INDEX_UPGRADE index. The options
  4747. // specify whether the file is to be copied at all or copied always
  4748. // or copied only if there on the target or not copied if there on
  4749. // the target.
  4750. //
  4751. SpAddMasterFileSectionToCopyList(
  4752. SifHandle,
  4753. DiskFileLists,
  4754. DiskCount,
  4755. NtPartition,
  4756. NULL,
  4757. INDEX_UPGRADE
  4758. );
  4759. //
  4760. // Add the section of files that are upgraded only if it is not
  4761. // a Win31 upgrade
  4762. //
  4763. if(WinUpgradeType != UpgradeWin31) {
  4764. SpAddSectionFilesToCopyList(
  4765. SifHandle,
  4766. DiskFileLists,
  4767. DiskCount,
  4768. SIF_FILESUPGRADEWIN31,
  4769. NtPartition,
  4770. NULL,
  4771. COPY_ALWAYS,
  4772. FALSE
  4773. );
  4774. }
  4775. //
  4776. // Add the files for kernel, hal and detect module, these are
  4777. // handled specially because they involve renamed files (it is
  4778. // not possible to find out just by looking at the target file
  4779. // how to upgrade it).
  4780. // NOTE: This does not handle third-party HAL's (they get copied
  4781. // by SpCopyThirdPartyDrivers() below).
  4782. //
  4783. SpAddHalKrnlDetToCopyList(
  4784. SifHandle,
  4785. DiskFileLists,
  4786. DiskCount,
  4787. NtPartition,
  4788. SystemPartition,
  4789. SystemPartitionDirectory,
  4790. Uniprocessor
  4791. );
  4792. //
  4793. // Add the new hive files so that our config stuff can get at them
  4794. // to extract new configuration information. These new hive files
  4795. // are renamed on the target so that they don't overwrite the
  4796. // existing hives.
  4797. SpAddSectionFilesToCopyList(
  4798. SifHandle,
  4799. DiskFileLists,
  4800. DiskCount,
  4801. SIF_FILESNEWHIVES,
  4802. NtPartition,
  4803. NULL,
  4804. COPY_ALWAYS,
  4805. FALSE
  4806. );
  4807. //
  4808. // Copy third-party migrated drivers.
  4809. // The driver files are actually already in place (since it's an upgrade)
  4810. // but the function makes sure they are not overwriten with inbox drivers
  4811. // if there's a filename collision
  4812. //
  4813. SpDontOverwriteMigratedDrivers (
  4814. NtPartition,
  4815. Sysroot,
  4816. SystemPartition,
  4817. SystemPartitionDirectory,
  4818. DiskFileLists,
  4819. DiskCount
  4820. );
  4821. }
  4822. #if defined(REMOTE_BOOT)
  4823. //
  4824. // If remote booting, add the [Files.RemoteBoot] section.
  4825. //
  4826. if (RemoteBootSetup) {
  4827. SpAddSectionFilesToCopyList(
  4828. SifHandle,
  4829. DiskFileLists,
  4830. DiskCount,
  4831. SIF_REMOTEBOOTFILES,
  4832. NtPartition,
  4833. NULL,
  4834. COPY_ALWAYS,
  4835. FALSE
  4836. );
  4837. }
  4838. #endif // defined(REMOTE_BOOT)
  4839. //
  4840. // Copy third-party files.
  4841. // We do this here just in case there is some error in the setup information
  4842. // file -- we'd have caught it by now, before we start copying files to the
  4843. // user's hard drive.
  4844. // NOTE: SpCopyThirdPartyDrivers has a check to make sure it only copies the
  4845. // HAL and PAL if we're in an upgrade (in which case, we want to leave the other
  4846. // drivers alone).
  4847. //
  4848. SpCopyThirdPartyDrivers(
  4849. ThirdPartySourceDevicePath,
  4850. NtPartition,
  4851. Sysroot,
  4852. SystemPartition,
  4853. SystemPartitionDirectory,
  4854. DiskFileLists,
  4855. DiskCount
  4856. );
  4857. #if 0
  4858. KdPrintEx( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, ("SETUP: Sysroot = %ls \n", Sysroot ) );
  4859. KdPrintEx( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, ("SETUP: SystemPartitionDirectory = %ls \n", SystemPartitionDirectory ));
  4860. KdPrintEx( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, ("SETUP: SourceDevicePath = %ls \n", SourceDevicePath ));
  4861. KdPrintEx( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, ("SETUP: DirectoryOnSourceDevice = %ls \n", DirectoryOnSourceDevice ));
  4862. KdPrintEx( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, ("SETUP: ThirdPartySourceDevicePath = %ls \n", ThirdPartySourceDevicePath ));
  4863. // SpCreateSetupLogFile( DiskFileLists, DiskCount, NtPartitionRegion, Sysroot, DirectoryOnSourceDevice );
  4864. #endif // if 0
  4865. //
  4866. // Copy files in the copy list.
  4867. //
  4868. SpCopyFilesInCopyList(
  4869. SifHandle,
  4870. DiskFileLists,
  4871. DiskCount,
  4872. SourceDevicePath,
  4873. DirectoryOnSourceDevice,
  4874. Sysroot,
  4875. &IncompatibleFileListHead
  4876. );
  4877. #ifdef _X86_
  4878. if(!SpIsArc()){
  4879. //
  4880. // Take care of ntbootdd.sys.
  4881. //
  4882. SpCreateNtbootddSys(
  4883. NtPartitionRegion,
  4884. NtPartition,
  4885. Sysroot,
  4886. SystemPartition,
  4887. SifHandle,
  4888. SourceDevicePath,
  4889. DirectoryOnSourceDevice
  4890. );
  4891. //
  4892. // Now get rid of x86-ARC turd files that
  4893. // we won't need (because we're not on an
  4894. // arc machine.
  4895. //
  4896. wcscpy( TemporaryBuffer, NtBootDevicePath );
  4897. SpDeleteFile( TemporaryBuffer, L"arcsetup.exe", NULL );
  4898. wcscpy( TemporaryBuffer, NtBootDevicePath );
  4899. SpDeleteFile( TemporaryBuffer, L"arcldr.exe", NULL );
  4900. }
  4901. #endif // defined _X86_
  4902. if( PreInstall ) {
  4903. SppCopyOemDirectories( SourceDevicePath,
  4904. NtPartition,
  4905. Sysroot );
  4906. }
  4907. //
  4908. // Create the log file in disk
  4909. //
  4910. if( _SetupLogFile != NULL ) {
  4911. PWSTR p;
  4912. PWSTR TempName;
  4913. PWSTR Values[] = {
  4914. SIF_NEW_REPAIR_NT_VERSION
  4915. };
  4916. //
  4917. // Merge in the OEM files retrived from the previous setup.log
  4918. //
  4919. if(_LoggedOemFiles) {
  4920. SppMergeLoggedOemFiles(_SetupLogFile,
  4921. _LoggedOemFiles,
  4922. SystemPartition,
  4923. ( *SystemPartitionDirectory != (WCHAR)'\0' )? SystemPartitionDirectory :
  4924. ( PWSTR )L"\\",
  4925. NtPartition );
  4926. SpFreeTextFile(_LoggedOemFiles);
  4927. }
  4928. //
  4929. // Add signature
  4930. //
  4931. SpAddLineToSection( _SetupLogFile,
  4932. SIF_NEW_REPAIR_SIGNATURE,
  4933. SIF_NEW_REPAIR_VERSION_KEY,
  4934. Values,
  4935. 1 );
  4936. //
  4937. // Add section that contains the paths
  4938. //
  4939. Values[0] = SystemPartition;
  4940. SpAddLineToSection( _SetupLogFile,
  4941. SIF_NEW_REPAIR_PATHS,
  4942. SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE,
  4943. Values,
  4944. 1 );
  4945. Values[0] = ( *SystemPartitionDirectory != (WCHAR)'\0' )? SystemPartitionDirectory :
  4946. ( PWSTR )L"\\";
  4947. SpAddLineToSection( _SetupLogFile,
  4948. SIF_NEW_REPAIR_PATHS,
  4949. SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DIRECTORY,
  4950. Values,
  4951. 1 );
  4952. Values[0] = NtPartition;
  4953. SpAddLineToSection( _SetupLogFile,
  4954. SIF_NEW_REPAIR_PATHS,
  4955. SIF_NEW_REPAIR_PATHS_TARGET_DEVICE,
  4956. Values,
  4957. 1 );
  4958. Values[0] = Sysroot;
  4959. SpAddLineToSection( _SetupLogFile,
  4960. SIF_NEW_REPAIR_PATHS,
  4961. SIF_NEW_REPAIR_PATHS_TARGET_DIRECTORY,
  4962. Values,
  4963. 1 );
  4964. //
  4965. // Flush to disk
  4966. //
  4967. TempName = SpMemAlloc( ( wcslen( SETUP_REPAIR_DIRECTORY ) + 1 +
  4968. wcslen( SETUP_LOG_FILENAME ) + 1 ) * sizeof( WCHAR ) );
  4969. wcscpy( TempName, SETUP_REPAIR_DIRECTORY );
  4970. SpConcatenatePaths(TempName, SETUP_LOG_FILENAME );
  4971. SpWriteSetupTextFile(_SetupLogFile,NtPartition,Sysroot,TempName);
  4972. SpMemFree( TempName );
  4973. SpFreeTextFile( _SetupLogFile );
  4974. _SetupLogFile = NULL;
  4975. }
  4976. //
  4977. // Free the media descriptors.
  4978. //
  4979. SpFreeCopyLists(&DiskFileLists,DiskCount);
  4980. //
  4981. // Free incompatible file lists
  4982. //
  4983. if ( IncompatibleFileListHead.EntryCount ) {
  4984. SpFreeIncompatibleFileList(&IncompatibleFileListHead);
  4985. }
  4986. SpMemFree(NtPartition);
  4987. if (SystemPartition != NULL) {
  4988. SpMemFree(SystemPartition);
  4989. }
  4990. #if defined(REMOTE_BOOT)
  4991. //
  4992. // If this is a remote boot setup, close the root of the NT partition.
  4993. //
  4994. if (SisRootHandle != NULL) {
  4995. ZwClose(SisRootHandle);
  4996. SisRootHandle = NULL;
  4997. }
  4998. #endif // defined(REMOTE_BOOT)
  4999. //
  5000. // Terminate diamond.
  5001. //
  5002. SpdTerminate();
  5003. SpUninitAlternateSource ();
  5004. }
  5005. VOID
  5006. SppDeleteDirectoriesInSection(
  5007. IN PVOID SifHandle,
  5008. IN PWSTR SifSection,
  5009. IN PDISK_REGION NtPartitionRegion,
  5010. IN PWSTR Sysroot
  5011. )
  5012. /*++
  5013. Routine Description:
  5014. This routine enumerates files listed in the given section and deletes
  5015. them from the system tree.
  5016. Arguments:
  5017. SifHandle - supplies handle to loaded setup information file.
  5018. SifSection - section containing files to delete
  5019. NtPartitionRegion - region descriptor for volume on which nt resides.
  5020. Sysroot - root directory for nt.
  5021. Return Value:
  5022. None.
  5023. --*/
  5024. {
  5025. ULONG Count,u;
  5026. PWSTR RelativePath, DirOrdinal, TargetDir, NtDir, DirPath;
  5027. NTSTATUS Status;
  5028. CLEAR_CLIENT_SCREEN();
  5029. //
  5030. // Determine the number of files listed in the section.
  5031. // This value may be zero.
  5032. //
  5033. Count = SpCountLinesInSection(SifHandle,SifSection);
  5034. for(u=0; u<Count; u++) {
  5035. DirOrdinal = SpGetSectionLineIndex(SifHandle, SifSection, u, 0);
  5036. RelativePath = SpGetSectionLineIndex(SifHandle, SifSection, u, 1);
  5037. //
  5038. // Validate the filename and dirordinal
  5039. //
  5040. if(!DirOrdinal) {
  5041. SpFatalSifError(SifHandle,SifSection,NULL,u,0);
  5042. }
  5043. if(!RelativePath) {
  5044. SpFatalSifError(SifHandle,SifSection,NULL,u,1);
  5045. }
  5046. //
  5047. // use the dirordinal key to get the path relative to sysroot of the
  5048. // directory the file is in
  5049. //
  5050. DirPath = SpLookUpTargetDirectory(SifHandle,DirOrdinal);
  5051. wcscpy( TemporaryBuffer, Sysroot );
  5052. SpConcatenatePaths( TemporaryBuffer, DirPath );
  5053. SpConcatenatePaths( TemporaryBuffer, RelativePath );
  5054. TargetDir = SpDupStringW( TemporaryBuffer );
  5055. //
  5056. // display status bar
  5057. //
  5058. if( !HeadlessTerminalConnected ) {
  5059. SpDisplayStatusText(SP_STAT_DELETING_FILE,DEFAULT_STATUS_ATTRIBUTE, TargetDir);
  5060. } else {
  5061. PWCHAR TempPtr = NULL;
  5062. //
  5063. // If we're headless, we need to be careful about displaying very long
  5064. // file/directory names. For that reason, just display a little spinner.
  5065. //
  5066. switch( u % 4) {
  5067. case 0:
  5068. TempPtr = L"-";
  5069. break;
  5070. case 1:
  5071. TempPtr = L"\\";
  5072. break;
  5073. case 2:
  5074. TempPtr = L"|";
  5075. break;
  5076. default:
  5077. TempPtr = L"/";
  5078. break;
  5079. }
  5080. SpDisplayStatusText(SP_STAT_DELETING_FILE,DEFAULT_STATUS_ATTRIBUTE, TempPtr);
  5081. }
  5082. //
  5083. // delete the directory
  5084. //
  5085. SpDeleteExistingTargetDir(NtPartitionRegion, TargetDir, FALSE, 0);
  5086. SpMemFree(TargetDir);
  5087. }
  5088. }
  5089. VOID
  5090. SppDeleteFilesInSection(
  5091. IN PVOID SifHandle,
  5092. IN PWSTR SifSection,
  5093. IN PDISK_REGION NtPartitionRegion,
  5094. IN PWSTR Sysroot
  5095. )
  5096. /*++
  5097. Routine Description:
  5098. This routine enumerates files listed in the given section and deletes
  5099. them from the system tree.
  5100. Arguments:
  5101. SifHandle - supplies handle to loaded setup information file.
  5102. SifSection - section containing files to delete
  5103. NtPartitionRegion - region descriptor for volume on which nt resides.
  5104. Sysroot - root directory for nt.
  5105. Return Value:
  5106. None.
  5107. --*/
  5108. {
  5109. ULONG Count,u;
  5110. PWSTR filename, dirordinal, targetdir, ntdir;
  5111. NTSTATUS Status;
  5112. CLEAR_CLIENT_SCREEN();
  5113. //
  5114. // Get the device path of the nt partition.
  5115. //
  5116. SpNtNameFromRegion(
  5117. NtPartitionRegion,
  5118. TemporaryBuffer,
  5119. sizeof(TemporaryBuffer),
  5120. PartitionOrdinalCurrent
  5121. );
  5122. SpConcatenatePaths(TemporaryBuffer,Sysroot);
  5123. ntdir = SpDupStringW(TemporaryBuffer);
  5124. //
  5125. // Determine the number of files listed in the section.
  5126. // This value may be zero.
  5127. //
  5128. Count = SpCountLinesInSection(SifHandle,SifSection);
  5129. for(u=0; u<Count; u++) {
  5130. filename = SpGetSectionLineIndex(SifHandle, SifSection, u, 0);
  5131. dirordinal = SpGetSectionLineIndex(SifHandle, SifSection, u, 1);
  5132. //
  5133. // Validate the filename and dirordinal
  5134. //
  5135. if(!filename) {
  5136. SpFatalSifError(SifHandle,SifSection,NULL,u,0);
  5137. }
  5138. if(!dirordinal) {
  5139. SpFatalSifError(SifHandle,SifSection,NULL,u,1);
  5140. }
  5141. //
  5142. // use the dirordinal key to get the path relative to sysroot of the
  5143. // directory the file is in
  5144. //
  5145. targetdir = SpLookUpTargetDirectory(SifHandle,dirordinal);
  5146. //
  5147. // display status bar
  5148. //
  5149. if( !HeadlessTerminalConnected ) {
  5150. SpDisplayStatusText(SP_STAT_DELETING_FILE,DEFAULT_STATUS_ATTRIBUTE, filename);
  5151. } else {
  5152. PWCHAR TempPtr = NULL;
  5153. //
  5154. // If we're headless, we need to be careful about displaying very long
  5155. // file/directory names. For that reason, just display a little spinner.
  5156. //
  5157. switch( u % 4) {
  5158. case 0:
  5159. TempPtr = L"-";
  5160. break;
  5161. case 1:
  5162. TempPtr = L"\\";
  5163. break;
  5164. case 2:
  5165. TempPtr = L"|";
  5166. break;
  5167. default:
  5168. TempPtr = L"/";
  5169. break;
  5170. }
  5171. SpDisplayStatusText(SP_STAT_DELETING_FILE,DEFAULT_STATUS_ATTRIBUTE, TempPtr);
  5172. }
  5173. //
  5174. // delete the file
  5175. //
  5176. while(TRUE) {
  5177. Status = SpDeleteFile(ntdir, targetdir, filename);
  5178. if(!NT_SUCCESS(Status)
  5179. && Status != STATUS_OBJECT_NAME_NOT_FOUND
  5180. && Status != STATUS_OBJECT_PATH_NOT_FOUND
  5181. ) {
  5182. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete file %ws (%lx)\n",filename, Status));
  5183. //
  5184. // We can ignore this error since this just means that we have
  5185. // less free space on the hard disk. It is not critical for
  5186. // install.
  5187. //
  5188. if(!SpNonCriticalError(SifHandle, SP_SCRN_DELETE_FAILED, filename, NULL)) {
  5189. break;
  5190. }
  5191. }
  5192. else {
  5193. break;
  5194. }
  5195. }
  5196. }
  5197. SpMemFree(ntdir);
  5198. }
  5199. VOID
  5200. SppBackupFilesInSection(
  5201. IN PVOID SifHandle,
  5202. IN PWSTR SifSection,
  5203. IN PDISK_REGION NtPartitionRegion,
  5204. IN PWSTR Sysroot
  5205. )
  5206. /*++
  5207. Routine Description:
  5208. This routine enumerates files listed in the given section and deletes
  5209. backs them up in the given NT tree if found by renaming.
  5210. Arguments:
  5211. SifHandle - supplies handle to loaded setup information file.
  5212. SifSection - section containing files to backup
  5213. NtPartitionRegion - region descriptor for volume on which nt resides.
  5214. Sysroot - root directory for nt.
  5215. Return Value:
  5216. None.
  5217. --*/
  5218. {
  5219. ULONG Count,u;
  5220. PWSTR filename, dirordinal, backupfile, targetdir, ntdir;
  5221. WCHAR OldFile[ACTUAL_MAX_PATH];
  5222. WCHAR NewFile[ACTUAL_MAX_PATH];
  5223. NTSTATUS Status;
  5224. CLEAR_CLIENT_SCREEN();
  5225. //
  5226. // Get the device path of the nt partition.
  5227. //
  5228. SpNtNameFromRegion(
  5229. NtPartitionRegion,
  5230. TemporaryBuffer,
  5231. sizeof(TemporaryBuffer),
  5232. PartitionOrdinalCurrent
  5233. );
  5234. SpConcatenatePaths(TemporaryBuffer,Sysroot);
  5235. ntdir = SpDupStringW(TemporaryBuffer);
  5236. //
  5237. // Determine the number of files listed in the section.
  5238. // This value may be zero.
  5239. //
  5240. Count = SpCountLinesInSection(SifHandle,SifSection);
  5241. for(u=0; u<Count; u++) {
  5242. filename = SpGetSectionLineIndex(SifHandle, SifSection, u, 0);
  5243. dirordinal = SpGetSectionLineIndex(SifHandle, SifSection, u, 1);
  5244. backupfile = SpGetSectionLineIndex(SifHandle, SifSection, u, 2);
  5245. //
  5246. // Validate the filename and dirordinal
  5247. //
  5248. if(!filename) {
  5249. SpFatalSifError(SifHandle,SifSection,NULL,u,0);
  5250. }
  5251. if(!dirordinal) {
  5252. SpFatalSifError(SifHandle,SifSection,NULL,u,1);
  5253. }
  5254. if(!backupfile) {
  5255. SpFatalSifError(SifHandle,SifSection,NULL,u,2);
  5256. }
  5257. //
  5258. // use the dirordinal key to get the path relative to sysroot of the
  5259. // directory the file is in
  5260. //
  5261. targetdir = SpLookUpTargetDirectory(SifHandle,dirordinal);
  5262. //
  5263. // display status bar
  5264. //
  5265. SpDisplayStatusText(SP_STAT_BACKING_UP_FILE,DEFAULT_STATUS_ATTRIBUTE, filename, backupfile);
  5266. //
  5267. // Form the complete pathnames of the old file name and the new file
  5268. // name
  5269. //
  5270. wcscpy(OldFile, ntdir);
  5271. SpConcatenatePaths(OldFile, targetdir);
  5272. wcscpy(NewFile, OldFile);
  5273. SpConcatenatePaths(OldFile, filename);
  5274. SpConcatenatePaths(NewFile, backupfile);
  5275. while(TRUE) {
  5276. if(!SpFileExists(OldFile, FALSE)) {
  5277. break;
  5278. }
  5279. if(SpFileExists(NewFile, FALSE)) {
  5280. SpDeleteFile(NewFile, NULL, NULL);
  5281. }
  5282. Status = SpRenameFile(OldFile, NewFile, FALSE);
  5283. if(!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND && Status != STATUS_OBJECT_PATH_NOT_FOUND) {
  5284. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to rename file %ws to %ws(%lx)\n",OldFile, NewFile, Status));
  5285. //
  5286. // We can ignore this error, since it is not critical
  5287. //
  5288. if(!SpNonCriticalError(SifHandle, SP_SCRN_BACKUP_FAILED, filename, backupfile)) {
  5289. break;
  5290. }
  5291. }
  5292. else {
  5293. break;
  5294. }
  5295. }
  5296. }
  5297. SpMemFree(ntdir);
  5298. }
  5299. VOID
  5300. SpDeleteAndBackupFiles(
  5301. IN PVOID SifHandle,
  5302. IN PDISK_REGION TargetRegion,
  5303. IN PWSTR TargetPath
  5304. )
  5305. {
  5306. //
  5307. // If we are not upgrading or installing into the same tree, then
  5308. // we have nothing to do
  5309. //
  5310. if(NTUpgrade == DontUpgrade) {
  5311. return;
  5312. }
  5313. //
  5314. // Below is code for NT-to-NT upgrade only
  5315. //
  5316. //
  5317. // The order in which the tasks below are performed is important.
  5318. // So do not change it!!!
  5319. // This is necessary in order to upgrade 3rd party video drivers
  5320. // (eg. rename sni543x.sys to cirrus.sys, so that we only upgrade
  5321. // the driver if it was present).
  5322. //
  5323. //
  5324. // Backup files
  5325. //
  5326. SppBackupFilesInSection(
  5327. SifHandle,
  5328. (NTUpgrade == UpgradeFull) ? SIF_FILESBACKUPONUPGRADE : SIF_FILESBACKUPONOVERWRITE,
  5329. TargetRegion,
  5330. TargetPath
  5331. );
  5332. //
  5333. // Delete files
  5334. //
  5335. SppDeleteFilesInSection(
  5336. SifHandle,
  5337. SIF_FILESDELETEONUPGRADE,
  5338. TargetRegion,
  5339. TargetPath
  5340. );
  5341. //
  5342. // Delete directories
  5343. //
  5344. SppDeleteDirectoriesInSection(
  5345. SifHandle,
  5346. SIF_DIRSDELETEONUPGRADE,
  5347. TargetRegion,
  5348. TargetPath
  5349. );
  5350. }
  5351. BOOLEAN
  5352. SpDelEnumFile(
  5353. IN PCWSTR DirName,
  5354. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  5355. OUT PULONG ret,
  5356. IN PVOID Pointer
  5357. )
  5358. {
  5359. PWSTR FileName;
  5360. static ULONG u = 0;
  5361. //
  5362. // Ignore subdirectories
  5363. //
  5364. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  5365. return TRUE; // continue processing
  5366. }
  5367. //
  5368. // We have to make a copy of the filename, because the info struct
  5369. // we get isn't NULL-terminated.
  5370. //
  5371. wcsncpy(
  5372. TemporaryBuffer,
  5373. FileInfo->FileName,
  5374. FileInfo->FileNameLength
  5375. );
  5376. (TemporaryBuffer)[FileInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  5377. FileName = SpDupStringW(TemporaryBuffer);
  5378. //
  5379. // display status bar
  5380. //
  5381. if( !HeadlessTerminalConnected ) {
  5382. SpDisplayStatusText( SP_STAT_DELETING_FILE, DEFAULT_STATUS_ATTRIBUTE, FileName );
  5383. } else {
  5384. PWCHAR TempPtr = NULL;
  5385. //
  5386. // If we're headless, we need to be careful about displaying very long
  5387. // file/directory names. For that reason, just display a little spinner.
  5388. //
  5389. switch( u % 4) {
  5390. case 0:
  5391. TempPtr = L"-";
  5392. break;
  5393. case 1:
  5394. TempPtr = L"\\";
  5395. break;
  5396. case 2:
  5397. TempPtr = L"|";
  5398. break;
  5399. default:
  5400. TempPtr = L"/";
  5401. break;
  5402. }
  5403. SpDisplayStatusText( SP_STAT_DELETING_FILE, DEFAULT_STATUS_ATTRIBUTE, TempPtr );
  5404. u++;
  5405. }
  5406. //
  5407. // Ignore return status of delete
  5408. //
  5409. SpDeleteFile(DirName, FileName, NULL);
  5410. SpMemFree(FileName);
  5411. return TRUE; // continue processing
  5412. }
  5413. BOOLEAN
  5414. SpDelEnumFileAndDirectory(
  5415. IN PCWSTR DirName,
  5416. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  5417. OUT PULONG ret,
  5418. IN PVOID Pointer
  5419. )
  5420. {
  5421. PWSTR FileName = NULL;
  5422. NTSTATUS Del_Status;
  5423. DWORD FileOrDir;
  5424. static ULONG u = 0;
  5425. if(*(PULONG)Pointer == SP_DELETE_FILESTODELETE ){
  5426. //
  5427. // We have to make a copy of the filename, because the info struct
  5428. // we get isn't NULL-terminated.
  5429. //
  5430. wcsncpy(
  5431. TemporaryBuffer,
  5432. FileInfo->FileName,
  5433. FileInfo->FileNameLength
  5434. );
  5435. (TemporaryBuffer)[FileInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  5436. FileName = SpDupStringW(TemporaryBuffer);
  5437. //
  5438. // display status bar
  5439. //
  5440. if( !HeadlessTerminalConnected ) {
  5441. SpDisplayStatusText( SP_STAT_DELETING_FILE, DEFAULT_STATUS_ATTRIBUTE, FileName );
  5442. } else {
  5443. PWCHAR TempPtr = NULL;
  5444. //
  5445. // If we're headless, we need to be careful about displaying very long
  5446. // file/directory names. For that reason, just display a little spinner.
  5447. //
  5448. switch( u % 4) {
  5449. case 0:
  5450. TempPtr = L"-";
  5451. break;
  5452. case 1:
  5453. TempPtr = L"\\";
  5454. break;
  5455. case 2:
  5456. TempPtr = L"|";
  5457. break;
  5458. default:
  5459. TempPtr = L"/";
  5460. break;
  5461. }
  5462. SpDisplayStatusText( SP_STAT_DELETING_FILE, DEFAULT_STATUS_ATTRIBUTE, TempPtr );
  5463. u++;
  5464. }
  5465. //
  5466. // Ignore return status of delete
  5467. //
  5468. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  5469. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DELETING DirName-%ws : FileName-%ws\n", DirName, FileName ));
  5470. }
  5471. Del_Status = SpDeleteFileEx( DirName,
  5472. FileName,
  5473. NULL,
  5474. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  5475. FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT );
  5476. if(!NT_SUCCESS(Del_Status))
  5477. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: File Not Deleted - Status - %ws (%lx)\n", TemporaryBuffer, Del_Status));
  5478. if( FileDeleteGauge )
  5479. SpTickGauge(FileDeleteGauge);
  5480. SpMemFree(FileName);
  5481. }
  5482. else
  5483. *(PULONG)Pointer = *(PULONG)Pointer + 1;
  5484. return TRUE; // continue processing
  5485. }
  5486. VOID
  5487. SpLogOneFile(
  5488. IN PFILE_TO_COPY FileToCopy,
  5489. IN PWSTR Sysroot,
  5490. IN PWSTR DirectoryOnSourceDevice,
  5491. IN PWSTR DiskDescription,
  5492. IN PWSTR DiskTag,
  5493. IN ULONG CheckSum
  5494. )
  5495. {
  5496. PWSTR Values[ 5 ];
  5497. LPWSTR NtPath;
  5498. ULONG ValueCount;
  5499. PFILE_TO_COPY p;
  5500. WCHAR CheckSumString[ 9 ];
  5501. if( _SetupLogFile == NULL ) {
  5502. return;
  5503. }
  5504. Values[ 1 ] = CheckSumString;
  5505. Values[ 2 ] = DirectoryOnSourceDevice;
  5506. Values[ 3 ] = DiskDescription;
  5507. Values[ 4 ] = DiskTag;
  5508. swprintf( CheckSumString, ( LPWSTR )L"%lx", CheckSum );
  5509. p = FileToCopy;
  5510. #if 0
  5511. KdPrintEx( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, ("SETUP: Source Name = %ls, \t\tTargetDirectory = %ls \t\tTargetName = %ls\t\tTargetDevice = %ls, \tAbsoluteDirectory = %d \n",
  5512. p->SourceFilename,
  5513. p->TargetDirectory,
  5514. p->TargetFilename,
  5515. p->TargetDevicePath,
  5516. p->AbsoluteTargetDirectory ));
  5517. #endif // if 0
  5518. Values[0] = p->SourceFilename;
  5519. ValueCount = ( DirectoryOnSourceDevice == NULL )? 2 : 5;
  5520. if( ( Sysroot == NULL ) ||
  5521. ( wcslen( p->TargetDirectory ) == 0 )
  5522. ) {
  5523. SpAddLineToSection( _SetupLogFile,
  5524. SIF_NEW_REPAIR_SYSPARTFILES,
  5525. p->TargetFilename,
  5526. Values,
  5527. ValueCount );
  5528. } else {
  5529. NtPath = SpDupStringW( Sysroot );
  5530. if (NtPath) {
  5531. NtPath = SpMemRealloc( NtPath,
  5532. sizeof( WCHAR ) * ( wcslen( Sysroot ) +
  5533. wcslen( p->TargetDirectory ) +
  5534. wcslen( p->TargetFilename ) +
  5535. 2 + // for possible two extra back slashes
  5536. 1 // for the terminating NULL
  5537. ) );
  5538. if (NtPath) {
  5539. SpConcatenatePaths( NtPath, p->TargetDirectory );
  5540. SpConcatenatePaths( NtPath, p->TargetFilename );
  5541. SpAddLineToSection( _SetupLogFile,
  5542. SIF_NEW_REPAIR_WINNTFILES,
  5543. NtPath,
  5544. Values,
  5545. ValueCount );
  5546. SpMemFree( NtPath );
  5547. }
  5548. }
  5549. }
  5550. }
  5551. PVOID
  5552. SppRetrieveLoggedOemFiles(
  5553. PVOID OldLogFile
  5554. )
  5555. {
  5556. PVOID NewLogFile;
  5557. BOOLEAN OldFormatSetupLogFile, FilesRetrieved = FALSE;
  5558. PWSTR SectionName[2];
  5559. ULONG FileCount, SectionIndex, i;
  5560. PWSTR TargetFileName;
  5561. PWSTR OemDiskDescription, OemDiskTag, OemSourceDirectory;
  5562. PWSTR Values[5];
  5563. //
  5564. // Create a new setup.log file to merge the OEM files into
  5565. //
  5566. NewLogFile = SpNewSetupTextFile();
  5567. if(!NewLogFile) {
  5568. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to create new setup.log buffer for OEM merging.\n"));
  5569. return NULL;
  5570. }
  5571. //
  5572. // Determine whether setup.log has the new or old style
  5573. //
  5574. if(OldFormatSetupLogFile = !IsSetupLogFormatNew(OldLogFile)) {
  5575. SectionName[0] = SIF_REPAIRSYSPARTFILES;
  5576. SectionName[1] = SIF_REPAIRWINNTFILES;
  5577. } else {
  5578. SectionName[0] = SIF_NEW_REPAIR_SYSPARTFILES;
  5579. SectionName[1] = SIF_NEW_REPAIR_WINNTFILES;
  5580. }
  5581. if(OldFormatSetupLogFile) {
  5582. //
  5583. // I don't know if we even want to mess with this.
  5584. // The format of setup.log in NT 3.1 makes it impossible
  5585. // to identify any OEM files except for SCSI files, and
  5586. // even then the tagfile name is lost. I would have to use
  5587. // the driver filename itself as a substitute for the tagfile
  5588. // name (which is what NT 3.1 repair did--UGGHH!!)
  5589. //
  5590. } else {
  5591. //
  5592. // Retrieve logged OEM files first from system partition, then
  5593. // from winnt directory.
  5594. //
  5595. for(SectionIndex = 0; SectionIndex < 2; SectionIndex++) {
  5596. FileCount = SpCountLinesInSection(OldLogFile, SectionName[SectionIndex]);
  5597. for(i=0; i<FileCount; i++) {
  5598. OemSourceDirectory = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 2);
  5599. OemDiskTag = NULL;
  5600. if(OemSourceDirectory) {
  5601. OemDiskDescription = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 3);
  5602. if(OemDiskDescription) {
  5603. OemDiskTag = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 4);
  5604. }
  5605. }
  5606. if(OemDiskTag) { // then we have an OEM file
  5607. TargetFileName = SpGetKeyName(OldLogFile, SectionName[SectionIndex], i);
  5608. Values[0] = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 0);
  5609. Values[1] = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 1);
  5610. Values[2] = OemSourceDirectory;
  5611. Values[3] = OemDiskDescription;
  5612. Values[4] = OemDiskTag;
  5613. SpAddLineToSection(NewLogFile,
  5614. SectionName[SectionIndex],
  5615. TargetFileName,
  5616. Values,
  5617. 5
  5618. );
  5619. FilesRetrieved = TRUE;
  5620. }
  5621. }
  5622. }
  5623. }
  5624. if(FilesRetrieved) {
  5625. return NewLogFile;
  5626. } else {
  5627. SpFreeTextFile(NewLogFile);
  5628. return NULL;
  5629. }
  5630. }
  5631. VOID
  5632. SppMergeLoggedOemFiles(
  5633. IN PVOID DestLogHandle,
  5634. IN PVOID OemLogHandle,
  5635. IN PWSTR SystemPartition,
  5636. IN PWSTR SystemPartitionDirectory,
  5637. IN PWSTR NtPartition
  5638. )
  5639. {
  5640. PWSTR SectionName[2] = {SIF_NEW_REPAIR_SYSPARTFILES, SIF_NEW_REPAIR_WINNTFILES};
  5641. PWSTR FullPathNames[2] = {NULL, NULL};
  5642. ULONG FileCount, SectionIndex, i, j;
  5643. PWSTR TargetFileName;
  5644. PWSTR Values[5];
  5645. //
  5646. // First build the target path. It will be used to check if
  5647. // an existing OEM file still exists on the new installation
  5648. // (An OEM file could listed in the FilesToDelete section of txtsetup.sif)
  5649. //
  5650. wcscpy( TemporaryBuffer, SystemPartition );
  5651. SpConcatenatePaths(TemporaryBuffer, SystemPartitionDirectory );
  5652. FullPathNames[0] = SpDupStringW(TemporaryBuffer);
  5653. FullPathNames[1] = SpDupStringW(NtPartition);
  5654. //
  5655. // Merge logged OEM files first from system partition, then
  5656. // from winnt directory.
  5657. //
  5658. for(SectionIndex = 0; SectionIndex < 2; SectionIndex++) {
  5659. FileCount = SpCountLinesInSection(OemLogHandle, SectionName[SectionIndex]);
  5660. for(i=0; i<FileCount; i++) {
  5661. TargetFileName = SpGetKeyName(OemLogHandle, SectionName[SectionIndex], i);
  5662. //
  5663. // Find out if there's already an entry for this file. If so, then don't
  5664. // merge in the OEM file.
  5665. //
  5666. if(!SpGetSectionKeyExists(DestLogHandle, SectionName[SectionIndex], TargetFileName)) {
  5667. PWSTR p;
  5668. //
  5669. // Find out if the OEM file still exists on the target system.
  5670. // If it doesn't exist, don't merge in the OEM file.
  5671. //
  5672. wcscpy( TemporaryBuffer, FullPathNames[SectionIndex] );
  5673. SpConcatenatePaths(TemporaryBuffer, TargetFileName );
  5674. p = SpDupStringW(TemporaryBuffer);
  5675. if(SpFileExists(p, FALSE)) {
  5676. for(j = 0; j < 5; j++) {
  5677. Values[j] = SpGetSectionLineIndex(OemLogHandle, SectionName[SectionIndex], i, j);
  5678. }
  5679. SpAddLineToSection(DestLogHandle,
  5680. SectionName[SectionIndex],
  5681. TargetFileName,
  5682. Values,
  5683. 5
  5684. );
  5685. }
  5686. SpMemFree(p);
  5687. }
  5688. }
  5689. }
  5690. SpMemFree( FullPathNames[0] );
  5691. SpMemFree( FullPathNames[1] );
  5692. }
  5693. BOOLEAN
  5694. SppIsFileLoggedAsOemFile(
  5695. IN PWSTR TargetFileName
  5696. )
  5697. {
  5698. PWSTR SectionName[2] = {SIF_NEW_REPAIR_SYSPARTFILES, SIF_NEW_REPAIR_WINNTFILES};
  5699. ULONG FileCount, SectionIndex;
  5700. BOOLEAN FileIsOem;
  5701. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SppIsFileLoggedAsOemFile() is checking %ls \n", TargetFileName ));
  5702. FileIsOem = FALSE;
  5703. if( _LoggedOemFiles ) {
  5704. //
  5705. // Look first in the from system partition section, then
  5706. // in the winnt section.
  5707. //
  5708. for(SectionIndex = 0; SectionIndex < 2; SectionIndex++) {
  5709. if( SpGetSectionKeyExists( _LoggedOemFiles, SectionName[SectionIndex], TargetFileName)) {
  5710. FileIsOem = TRUE;
  5711. break;
  5712. }
  5713. }
  5714. }
  5715. return( FileIsOem );
  5716. }
  5717. BOOLEAN
  5718. SpRemoveEntryFromCopyList(
  5719. IN PDISK_FILE_LIST DiskFileLists,
  5720. IN ULONG DiskCount,
  5721. IN PWSTR TargetDirectory,
  5722. IN PWSTR TargetFilename,
  5723. IN PWSTR TargetDevicePath,
  5724. IN BOOLEAN AbsoluteTargetDirectory
  5725. )
  5726. /*++
  5727. Routine Description:
  5728. Removes an entry from a disk's file copy list.
  5729. Arguments:
  5730. DiskFileLists - supplies an array of file lists, one for each distribution
  5731. disk in the product.
  5732. DiskCount - supplies number of elements in the DiskFileLists array.
  5733. TargetDirectory - supplies the directory on the target media
  5734. into which the file will be copied.
  5735. TargetFilename - supplies the name of the file as it will exist
  5736. in the target tree.
  5737. TargetDevicePath - supplies the NT name of the device onto which the file
  5738. is to be copied (ie, \device\harddisk1\partition2, etc).
  5739. AbsoluteTargetDirectory - indicates whether TargetDirectory is a path from the
  5740. root, or relative to a root to specified later.
  5741. Return Value:
  5742. TRUE if a new copy list entry was created; FALSE if not (ie, the file was
  5743. already on the copy list).
  5744. --*/
  5745. {
  5746. PDISK_FILE_LIST pDiskList;
  5747. PFILE_TO_COPY pListEntry;
  5748. ULONG DiskNumber;
  5749. for(DiskNumber=0; DiskNumber<DiskCount; DiskNumber++) {
  5750. pDiskList = &DiskFileLists[DiskNumber];
  5751. for(pListEntry=pDiskList->FileList; pListEntry; pListEntry=pListEntry->Next) {
  5752. if(!_wcsicmp(pListEntry->TargetFilename,TargetFilename)
  5753. && !_wcsicmp(pListEntry->TargetDirectory,TargetDirectory)
  5754. && !_wcsicmp(pListEntry->TargetDevicePath,TargetDevicePath)
  5755. && (pListEntry->AbsoluteTargetDirectory == AbsoluteTargetDirectory)) {
  5756. pListEntry->Flags &= ~COPY_DISPOSITION_MASK;
  5757. pListEntry->Flags |= COPY_NEVER;
  5758. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpRemoveEntryFromCopyList() removed %ls from copy list \n", TargetFilename ));
  5759. return( TRUE );
  5760. }
  5761. }
  5762. }
  5763. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRemoveEntryFromCopyList() failed to remove %ls from copy list \n", TargetFilename ));
  5764. return( FALSE );
  5765. }
  5766. NTSTATUS
  5767. SpMoveFileOrDirectory(
  5768. IN PWSTR SrcPath,
  5769. IN PWSTR DestPath
  5770. )
  5771. /*++
  5772. Routine Description:
  5773. This routine attempts to move a source file or directory, to a target
  5774. file or directory.
  5775. Note: This function will fail if the source and destination paths do not
  5776. point to the same volume.
  5777. Arguments:
  5778. SrcPath: Absolute path to the source file or directory.
  5779. This path should include the path to the source device.
  5780. DestPath: Absolute path to the destination file or directory.
  5781. This path should include the path to the source device.
  5782. Return Value:
  5783. NTSTATUS
  5784. --*/
  5785. {
  5786. OBJECT_ATTRIBUTES Obja;
  5787. IO_STATUS_BLOCK IoStatusBlock;
  5788. UNICODE_STRING SrcName;
  5789. HANDLE hSrc;
  5790. NTSTATUS Status;
  5791. BYTE RenameFileInfoBuffer[ACTUAL_MAX_PATH * sizeof(WCHAR) + sizeof(FILE_RENAME_INFORMATION)];
  5792. PFILE_RENAME_INFORMATION RenameFileInfo;
  5793. if(wcslen(DestPath) >= ACTUAL_MAX_PATH){
  5794. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  5795. "SETUP:SpMoveFileOrDirectory, Actual length of Dest path is %d more that %d - skipping %ws move",
  5796. wcslen(DestPath), ACTUAL_MAX_PATH, DestPath));
  5797. return STATUS_NAME_TOO_LONG;
  5798. }
  5799. //
  5800. // Initialize names and attributes.
  5801. //
  5802. INIT_OBJA(&Obja,&SrcName,SrcPath);
  5803. Status = ZwCreateFile( &hSrc,
  5804. FILE_GENERIC_READ,
  5805. &Obja,
  5806. &IoStatusBlock,
  5807. NULL,
  5808. FILE_ATTRIBUTE_NORMAL,
  5809. FILE_SHARE_READ,
  5810. FILE_OPEN,
  5811. 0,
  5812. NULL,
  5813. 0 );
  5814. if( !NT_SUCCESS( Status ) ) {
  5815. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open source file %ws. Status = %lx\n",SrcPath, Status));
  5816. return( Status );
  5817. }
  5818. memset(RenameFileInfoBuffer, 0, sizeof(RenameFileInfoBuffer));
  5819. RenameFileInfo = (PFILE_RENAME_INFORMATION)RenameFileInfoBuffer;
  5820. RenameFileInfo->ReplaceIfExists = TRUE;
  5821. RenameFileInfo->RootDirectory = NULL;
  5822. RenameFileInfo->FileNameLength = wcslen( DestPath )*sizeof( WCHAR );
  5823. RtlMoveMemory(RenameFileInfo->FileName,DestPath,(wcslen( DestPath )+1)*sizeof(WCHAR));
  5824. Status = ZwSetInformationFile( hSrc,
  5825. &IoStatusBlock,
  5826. RenameFileInfo,
  5827. sizeof(RenameFileInfoBuffer),
  5828. FileRenameInformation );
  5829. if(!NT_SUCCESS(Status)) {
  5830. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to set attribute on %ws. Status = %lx\n",SrcPath, Status));
  5831. }
  5832. ZwClose(hSrc);
  5833. return( Status );
  5834. }
  5835. BOOLEAN
  5836. SppCopyDirRecursiveCallback(
  5837. IN PCWSTR SrcPath,
  5838. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  5839. OUT PULONG ReturnData,
  5840. IN PVOID Params
  5841. )
  5842. /*++
  5843. Routine Description:
  5844. This routine is called by the file enumerator as a callback for each
  5845. file or subdirectory found in the parent directory. It creates a node
  5846. for the file or subdirectory and appends it to the appropriate list.
  5847. Arguments:
  5848. SrcPath - Absolute path to the parent directory. Unused.
  5849. the path to the source device.
  5850. FileInfo - supplies find data for a file or directory in the parent directory.
  5851. ReturnData - receives an error code if an error occurs.
  5852. We ignore errors in this routine and thus we always
  5853. just fill this in with NO_ERROR.
  5854. Params - Contains a pointer to the COPYDIR_DIRECTORY_NODE for the parent directory.
  5855. Return Value:
  5856. TRUE if successful otherwise FALSE (if ran out of memory).
  5857. --*/
  5858. {
  5859. PCOPYDIR_FILE_NODE fileEntry;
  5860. PCOPYDIR_DIRECTORY_NODE directoryEntry;
  5861. PCOPYDIR_DIRECTORY_NODE parentDirectory = Params;
  5862. ULONG nameLength;
  5863. BOOLEAN Result = TRUE;
  5864. *ReturnData = NO_ERROR;
  5865. nameLength = FileInfo->FileNameLength / sizeof(WCHAR);
  5866. if( (FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ) {
  5867. //
  5868. // This is a file. Create a node for it, linked to the parent directory.
  5869. //
  5870. fileEntry = SpMemAlloc(sizeof(COPYDIR_FILE_NODE) + FileInfo->FileNameLength);
  5871. if (fileEntry) {
  5872. wcsncpy(fileEntry->Name, FileInfo->FileName, nameLength);
  5873. fileEntry->Name[nameLength] = 0;
  5874. InsertTailList(&parentDirectory->FileList, &fileEntry->SiblingListEntry);
  5875. } else {
  5876. Result = FALSE; // ran out of memory
  5877. }
  5878. } else {
  5879. //
  5880. // This is a directory. Skip it if it's "." or "..". Otherwise,
  5881. // create a node for it, linked to the parent directory.
  5882. //
  5883. ASSERT(nameLength != 0);
  5884. if ( (FileInfo->FileName[0] == L'.') &&
  5885. ( (nameLength == 1) ||
  5886. ( (nameLength == 2) && (FileInfo->FileName[1] == L'.') ) ) ) {
  5887. //
  5888. // Skip . and ..
  5889. //
  5890. } else {
  5891. directoryEntry = SpMemAlloc(sizeof(COPYDIR_DIRECTORY_NODE) + FileInfo->FileNameLength);
  5892. if (directoryEntry) {
  5893. InitializeListHead(&directoryEntry->FileList);
  5894. InitializeListHead(&directoryEntry->SubdirectoryList);
  5895. directoryEntry->Parent = parentDirectory;
  5896. wcsncpy( directoryEntry->Name,
  5897. FileInfo->FileName,
  5898. FileInfo->FileNameLength/sizeof(WCHAR) );
  5899. directoryEntry->Name[FileInfo->FileNameLength/sizeof(WCHAR)] = 0;
  5900. InsertTailList( &parentDirectory->SubdirectoryList,
  5901. &directoryEntry->SiblingListEntry );
  5902. } else {
  5903. Result = FALSE; // ran out of memory
  5904. }
  5905. }
  5906. }
  5907. return Result;
  5908. }
  5909. VOID
  5910. SpCopyDirRecursive(
  5911. IN PWSTR SrcPath,
  5912. IN PWSTR DestDevPath,
  5913. IN PWSTR DestDirPath,
  5914. IN ULONG CopyFlags
  5915. )
  5916. /*++
  5917. Routine Description:
  5918. This routine recursively copies a src directory to a destination directory.
  5919. Arguments:
  5920. SrcPath: Absolute path to the source directory. This path should include
  5921. the path to the source device.
  5922. DestDevPath: Path to the destination device.
  5923. DestDirPath: Path to the destination directory.
  5924. CopyFlags: Flags to pass to SpCopyFilesUsingNames()
  5925. Return Value:
  5926. None.
  5927. --*/
  5928. {
  5929. ULONG n;
  5930. NTSTATUS Status;
  5931. PWSTR currentSrcPath;
  5932. PWSTR currentDestPath;
  5933. LIST_ENTRY directoryList;
  5934. LIST_ENTRY fileList;
  5935. COPYDIR_DIRECTORY_NODE rootDirectory;
  5936. PCOPYDIR_DIRECTORY_NODE currentDirectory;
  5937. PCOPYDIR_DIRECTORY_NODE oldDirectory;
  5938. PCOPYDIR_FILE_NODE fileEntry;
  5939. PLIST_ENTRY listEntry;
  5940. //
  5941. // Allocate a buffer to hold the working source and destination paths.
  5942. //
  5943. #define COPYDIR_MAX_PATH 16384 // characters
  5944. currentSrcPath = SpMemAlloc(2 * COPYDIR_MAX_PATH * sizeof(WCHAR));
  5945. currentDestPath = currentSrcPath + COPYDIR_MAX_PATH;
  5946. wcscpy(currentSrcPath, SrcPath);
  5947. wcscpy(currentDestPath, DestDevPath);
  5948. SpConcatenatePaths(currentDestPath, DestDirPath);
  5949. //
  5950. // Create the target directory
  5951. //
  5952. if( !SpFileExists( currentDestPath, TRUE ) ) {
  5953. //
  5954. // If the directory doesn't exist, then try to move (rename) the
  5955. // source directory.
  5956. //
  5957. if (!RemoteSysPrepSetup) {
  5958. Status = SpMoveFileOrDirectory( SrcPath, currentDestPath );
  5959. if( NT_SUCCESS( Status ) ) {
  5960. SpMemFree(currentSrcPath);
  5961. return;
  5962. }
  5963. }
  5964. //
  5965. // If unable to rename the source directory, then create the
  5966. // target directory
  5967. //
  5968. SpCreateDirectory( DestDevPath,
  5969. NULL,
  5970. DestDirPath,
  5971. 0,
  5972. 0 );
  5973. if (RemoteSysPrepSetup) {
  5974. Status = SpCopyEAsAndStreams( currentSrcPath,
  5975. NULL,
  5976. currentDestPath,
  5977. NULL,
  5978. TRUE );
  5979. if ( NT_SUCCESS( Status )) {
  5980. Status = SpSysPrepSetExtendedInfo( currentSrcPath,
  5981. currentDestPath,
  5982. TRUE,
  5983. FALSE );
  5984. }
  5985. if (! NT_SUCCESS( Status )) {
  5986. SpMemFree(currentSrcPath);
  5987. return;
  5988. }
  5989. }
  5990. }
  5991. //
  5992. // Initialize the screen.
  5993. //
  5994. SpCopyFilesScreenRepaint(L"", NULL, TRUE);
  5995. //
  5996. // Create directory node for the starting directory.
  5997. //
  5998. InitializeListHead( &rootDirectory.SubdirectoryList );
  5999. InitializeListHead( &rootDirectory.FileList );
  6000. rootDirectory.Parent = NULL;
  6001. currentDirectory = &rootDirectory;
  6002. do {
  6003. //
  6004. // Enumerate the files and directories in the current source directory.
  6005. //
  6006. SpEnumFiles(currentSrcPath, SppCopyDirRecursiveCallback, &n, currentDirectory);
  6007. //
  6008. // Copy all files in the current source directory to the destination directory.
  6009. //
  6010. while ( !IsListEmpty(&currentDirectory->FileList) ) {
  6011. listEntry = RemoveHeadList(&currentDirectory->FileList);
  6012. fileEntry = CONTAINING_RECORD( listEntry,
  6013. COPYDIR_FILE_NODE,
  6014. SiblingListEntry );
  6015. SpConcatenatePaths(currentSrcPath, fileEntry->Name);
  6016. SpConcatenatePaths(currentDestPath, fileEntry->Name);
  6017. SpMemFree(fileEntry);
  6018. SpCopyFilesScreenRepaint(currentSrcPath, NULL, FALSE);
  6019. Status = SpCopyFileUsingNames( currentSrcPath,
  6020. currentDestPath,
  6021. 0,
  6022. CopyFlags );
  6023. if( !NT_SUCCESS( Status ) ) {
  6024. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to copy %ws. Status = %lx\n", currentSrcPath, Status));
  6025. SpCopyFilesScreenRepaint(L"", NULL, TRUE);
  6026. }
  6027. *wcsrchr(currentSrcPath, L'\\') = 0;
  6028. *wcsrchr(currentDestPath, L'\\') = 0;
  6029. }
  6030. //
  6031. // If the current directory has no subdirectories, walk back up the
  6032. // tree looking for an unprocessed directory.
  6033. //
  6034. while ( IsListEmpty(&currentDirectory->SubdirectoryList) ) {
  6035. //
  6036. // If the current directory is the root directory, we're done. Otherwise,
  6037. // move up to the parent directory entry and delete the current one.
  6038. //
  6039. oldDirectory = currentDirectory;
  6040. currentDirectory = currentDirectory->Parent;
  6041. if ( currentDirectory == NULL ) {
  6042. break;
  6043. }
  6044. ASSERT(IsListEmpty(&oldDirectory->FileList));
  6045. ASSERT(IsListEmpty(&oldDirectory->SiblingListEntry));
  6046. SpMemFree(oldDirectory);
  6047. //
  6048. // Strip the name of the current directory off of the path.
  6049. //
  6050. *wcsrchr(currentSrcPath, L'\\') = 0;
  6051. *wcsrchr(currentDestPath, L'\\') = 0;
  6052. }
  6053. if ( currentDirectory != NULL ) {
  6054. //
  6055. // We found another directory to work on.
  6056. //
  6057. listEntry = RemoveHeadList(&currentDirectory->SubdirectoryList);
  6058. currentDirectory = CONTAINING_RECORD( listEntry,
  6059. COPYDIR_DIRECTORY_NODE,
  6060. SiblingListEntry );
  6061. #if DBG
  6062. InitializeListHead(&currentDirectory->SiblingListEntry);
  6063. #endif
  6064. //
  6065. // Create the target directory.
  6066. //
  6067. SpCreateDirectory( currentDestPath,
  6068. NULL,
  6069. currentDirectory->Name,
  6070. 0,
  6071. 0 );
  6072. SpCopyFilesScreenRepaint(L"",NULL,TRUE);
  6073. SpConcatenatePaths(currentSrcPath, currentDirectory->Name);
  6074. SpConcatenatePaths(currentDestPath, currentDirectory->Name);
  6075. if (RemoteSysPrepSetup) {
  6076. Status = SpCopyEAsAndStreams( currentSrcPath,
  6077. NULL,
  6078. currentDestPath,
  6079. NULL,
  6080. TRUE );
  6081. if ( NT_SUCCESS( Status )) {
  6082. Status = SpSysPrepSetExtendedInfo( currentSrcPath,
  6083. currentDestPath,
  6084. TRUE,
  6085. FALSE );
  6086. }
  6087. if (! NT_SUCCESS( Status )) {
  6088. goto cleanup;
  6089. }
  6090. }
  6091. }
  6092. } while ( currentDirectory != NULL );
  6093. ASSERT(IsListEmpty(&rootDirectory.FileList));
  6094. ASSERT(IsListEmpty(&rootDirectory.SubdirectoryList));
  6095. cleanup:
  6096. //
  6097. // Normally everything will already be cleaned up by the time we get here.
  6098. // But if the above loop is aborted, there may be some cleanup to do.
  6099. // Walk the lists in the same manner as the above loop, freeing memory
  6100. // along the way.
  6101. //
  6102. currentDirectory = &rootDirectory;
  6103. do {
  6104. while ( !IsListEmpty(&currentDirectory->FileList) ) {
  6105. listEntry = RemoveHeadList(&currentDirectory->FileList);
  6106. fileEntry = CONTAINING_RECORD( listEntry,
  6107. COPYDIR_FILE_NODE,
  6108. SiblingListEntry );
  6109. SpMemFree(fileEntry);
  6110. }
  6111. while ( IsListEmpty(&currentDirectory->SubdirectoryList) ) {
  6112. oldDirectory = currentDirectory;
  6113. currentDirectory = currentDirectory->Parent;
  6114. if ( currentDirectory == NULL ) {
  6115. break;
  6116. }
  6117. ASSERT(IsListEmpty(&oldDirectory->FileList));
  6118. ASSERT(IsListEmpty(&oldDirectory->SiblingListEntry));
  6119. SpMemFree(oldDirectory);
  6120. }
  6121. if ( currentDirectory != NULL ) {
  6122. listEntry = RemoveHeadList(&currentDirectory->SubdirectoryList);
  6123. currentDirectory = CONTAINING_RECORD( listEntry,
  6124. COPYDIR_DIRECTORY_NODE,
  6125. SiblingListEntry );
  6126. #if DBG
  6127. InitializeListHead(&currentDirectory->SiblingListEntry);
  6128. #endif
  6129. }
  6130. } while ( currentDirectory != NULL );
  6131. //
  6132. // Free the buffer allocated at the beginning.
  6133. //
  6134. SpMemFree(currentSrcPath);
  6135. return;
  6136. } // SpCopyDirRecursive
  6137. VOID
  6138. SppCopyOemDirectories(
  6139. IN PWSTR SourceDevicePath,
  6140. IN PWSTR NtPartition,
  6141. IN PWSTR Sysroot
  6142. )
  6143. /*++
  6144. Routine Description:
  6145. This routine recursively copies a src directory to a destination directory.
  6146. Arguments:
  6147. SourceDevicePath: Path to the device that contains the source.
  6148. NtPartition: Path to the drive that contains the system.
  6149. Systroot: Directory where the system is installed.
  6150. Return Value:
  6151. None.
  6152. --*/
  6153. {
  6154. PWSTR r, s, t;
  6155. WCHAR Drive[3];
  6156. PDISK_REGION TargetRegion;
  6157. //
  6158. // Check if the subdirectory $OEM$\\$$ exists on the source directory.
  6159. // If it exists, then tree copy the directory on top of %SystemRoot%
  6160. //
  6161. wcscpy(TemporaryBuffer, SourceDevicePath);
  6162. SpConcatenatePaths( TemporaryBuffer, PreinstallOemSourcePath );
  6163. r = wcsrchr( TemporaryBuffer, (WCHAR)'\\' );
  6164. if( r != NULL ) {
  6165. *r = (WCHAR)'\0';
  6166. }
  6167. //
  6168. // Make a copy of the path that we have so far. It will be used to build the
  6169. // path to $OEM$\$1
  6170. //
  6171. s = SpDupStringW(TemporaryBuffer);
  6172. SpConcatenatePaths( TemporaryBuffer, WINNT_OEM_FILES_SYSROOT_W );
  6173. r = SpDupStringW(TemporaryBuffer);
  6174. if (r) {
  6175. if( SpFileExists( r, TRUE ) ) {
  6176. SpCopyFilesScreenRepaint(L"", NULL, TRUE);
  6177. SpCopyDirRecursive( r,
  6178. NtPartition,
  6179. Sysroot,
  6180. COPY_DELETESOURCE
  6181. );
  6182. }
  6183. SpMemFree( r );
  6184. }
  6185. //
  6186. // Check if the subdirectory $OEM$\\$1 exists on the source directory.
  6187. // If it exists, then tree copy the directory to the root of %SystemDrive%
  6188. //
  6189. wcscpy(TemporaryBuffer, s);
  6190. SpMemFree( s );
  6191. SpConcatenatePaths( TemporaryBuffer, WINNT_OEM_FILES_SYSDRVROOT_W );
  6192. r = SpDupStringW(TemporaryBuffer);
  6193. if (r) {
  6194. if( SpFileExists( r, TRUE ) ) {
  6195. SpCopyFilesScreenRepaint(L"", NULL, TRUE);
  6196. SpCopyDirRecursive( r,
  6197. NtPartition,
  6198. L"\\",
  6199. COPY_DELETESOURCE
  6200. );
  6201. }
  6202. SpMemFree( r );
  6203. }
  6204. //
  6205. // Copy the subdirectories $OEM$\<drive letter> to the root of each
  6206. // corresponding drive.
  6207. // These directories are:
  6208. //
  6209. // $OEM$\C
  6210. // $OEM$\D
  6211. // $OEM$\E
  6212. // .
  6213. // .
  6214. // .
  6215. // $OEM$\Z
  6216. //
  6217. //
  6218. wcscpy(TemporaryBuffer, SourceDevicePath);
  6219. SpConcatenatePaths( TemporaryBuffer, PreinstallOemSourcePath );
  6220. r = wcsrchr( TemporaryBuffer, (WCHAR)'\\' );
  6221. if( r != NULL ) {
  6222. *r = (WCHAR)'\0';
  6223. }
  6224. SpConcatenatePaths( TemporaryBuffer, L"\\C" );
  6225. r = SpDupStringW(TemporaryBuffer);
  6226. if (r) {
  6227. s = wcsrchr( r, (WCHAR)'\\' );
  6228. s++;
  6229. Drive[1] = (WCHAR)':';
  6230. Drive[2] = (WCHAR)'\0';
  6231. for( Drive[0] = (WCHAR)'C'; Drive[0] <= (WCHAR)'Z'; Drive[0] = Drive[0] + 1) {
  6232. //
  6233. // If the subdirectory $OEM$\<drive letter> exists on the source,
  6234. // and if there is a FAT or NTFS partition in the target machine that
  6235. // has the same drive letter specification, then tree copy
  6236. // $OEM$\<drive letter> to the corresponding partition in the target
  6237. // machine.
  6238. //
  6239. *s = Drive[0];
  6240. if( SpFileExists( r, TRUE ) ) {
  6241. if( ( ( TargetRegion = SpRegionFromDosName( Drive ) ) != NULL ) &&
  6242. TargetRegion->PartitionedSpace &&
  6243. ( ( TargetRegion->Filesystem == FilesystemFat ) ||
  6244. ( TargetRegion->Filesystem == FilesystemFat32 ) ||
  6245. ( TargetRegion->Filesystem == FilesystemNtfs ) )
  6246. ) {
  6247. SpNtNameFromRegion( TargetRegion,
  6248. TemporaryBuffer,
  6249. sizeof(TemporaryBuffer),
  6250. PartitionOrdinalCurrent );
  6251. t = SpDupStringW(TemporaryBuffer);
  6252. SpCopyDirRecursive( r,
  6253. t,
  6254. L"",
  6255. COPY_DELETESOURCE
  6256. );
  6257. SpMemFree( t );
  6258. }
  6259. }
  6260. }
  6261. SpMemFree( r );
  6262. }
  6263. //
  6264. // Merge %SystemRoot%\$$rename.txt with $$rename.txt in the root of the
  6265. // NT partition.
  6266. //
  6267. SppMergeRenameFiles( SourceDevicePath, NtPartition, Sysroot );
  6268. }
  6269. VOID
  6270. SppMergeRenameFiles(
  6271. IN PWSTR SourceDevicePath,
  6272. IN PWSTR NtPartition,
  6273. IN PWSTR Sysroot
  6274. )
  6275. /*++
  6276. Routine Description:
  6277. This routine recursively copies a src directory to a destination directory.
  6278. Arguments:
  6279. SourceDevicePath: Path to the device that contains the source.
  6280. NtPartition: Path to the drive that contains the system.
  6281. Systroot: Directory where the system is installed.
  6282. Return Value:
  6283. None.
  6284. --*/
  6285. {
  6286. PWSTR r, s;
  6287. PDISK_REGION TargetRegion;
  6288. NTSTATUS Status;
  6289. PVOID RootRenameFile;
  6290. PVOID SysrootRenameFile;
  6291. ULONG ErrorLine;
  6292. ULONG SectionCount;
  6293. ULONG LineCount;
  6294. ULONG i,j;
  6295. PWSTR SectionName;
  6296. PWSTR NewSectionName;
  6297. PWSTR KeyName;
  6298. PWSTR Values[1];
  6299. PFILE_TO_RENAME File;
  6300. //
  6301. // Build the ful path to %sysroot%\$$rename.txt
  6302. //
  6303. wcscpy(TemporaryBuffer, NtPartition);
  6304. SpConcatenatePaths( TemporaryBuffer, Sysroot );
  6305. SpConcatenatePaths( TemporaryBuffer, WINNT_OEM_LFNLIST_W );
  6306. s = SpDupStringW(TemporaryBuffer);
  6307. //
  6308. // Load %sysroot%\$$rename.txt, if one exists
  6309. //
  6310. if( SpFileExists( s, FALSE ) ) {
  6311. //
  6312. // Load Sysroot\$$rename.txt
  6313. //
  6314. Status = SpLoadSetupTextFile( s,
  6315. NULL,
  6316. 0,
  6317. &SysrootRenameFile,
  6318. &ErrorLine,
  6319. TRUE,
  6320. FALSE
  6321. );
  6322. if( !NT_SUCCESS( Status ) ) {
  6323. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to load file %ws. Status = %lx \n", s, Status ));
  6324. goto merge_rename_exit;
  6325. }
  6326. } else {
  6327. SysrootRenameFile = NULL;
  6328. }
  6329. //
  6330. // If there is a $$rename.txt on sysroot, then it needs to be merged
  6331. // (or appended) to the one in the NtPartition.
  6332. // If RenameList is not empty, then the files in this list need to be
  6333. // added to $$rename.txt on the NtPartition.
  6334. // Otherwise, don't do any merge.
  6335. //
  6336. if( ( SysrootRenameFile != NULL )
  6337. || ( RenameList != NULL )
  6338. ) {
  6339. //
  6340. // Find out if the NtPartition contains a $$rename.txt
  6341. //
  6342. wcscpy(TemporaryBuffer, NtPartition);
  6343. SpConcatenatePaths( TemporaryBuffer, WINNT_OEM_LFNLIST_W );
  6344. r = SpDupStringW(TemporaryBuffer);
  6345. if( !SpFileExists( r, FALSE ) ) {
  6346. //
  6347. // If the NT partition doesn't contain $$rename.txt, then
  6348. // create a new $$rename.txt in memory
  6349. //
  6350. RootRenameFile = SpNewSetupTextFile();
  6351. if( RootRenameFile == NULL ) {
  6352. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpNewSetupTextFile() failed \n"));
  6353. if( SysrootRenameFile != NULL ) {
  6354. SpFreeTextFile( SysrootRenameFile );
  6355. }
  6356. SpMemFree( r );
  6357. goto merge_rename_exit;
  6358. }
  6359. } else {
  6360. //
  6361. // Load $$rename on the NTPartition
  6362. //
  6363. Status = SpLoadSetupTextFile( r,
  6364. NULL,
  6365. 0,
  6366. &RootRenameFile,
  6367. &ErrorLine,
  6368. TRUE,
  6369. FALSE
  6370. );
  6371. if( !NT_SUCCESS( Status ) ) {
  6372. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to load file %ws. Status = %lx \n", r, Status ));
  6373. if( SysrootRenameFile != NULL ) {
  6374. SpFreeTextFile( SysrootRenameFile );
  6375. }
  6376. SpMemFree( r );
  6377. goto merge_rename_exit;
  6378. }
  6379. }
  6380. if( SysrootRenameFile != NULL ) {
  6381. //
  6382. // Add the section of Sysroot\$$rename.txt to $$rename.txt in memory
  6383. // Note that we need to prepend Sysroot to the section name
  6384. //
  6385. SectionCount = SpCountSectionsInFile( SysrootRenameFile );
  6386. for( i = 0; i < SectionCount; i++ ) {
  6387. SectionName = SpGetSectionName( SysrootRenameFile, i );
  6388. if( SectionName != NULL ) {
  6389. wcscpy(TemporaryBuffer, L"\\");
  6390. SpConcatenatePaths( TemporaryBuffer, Sysroot);
  6391. SpConcatenatePaths( TemporaryBuffer, SectionName );
  6392. NewSectionName = SpDupStringW(TemporaryBuffer);
  6393. LineCount = SpCountLinesInSection( SysrootRenameFile, SectionName );
  6394. for( j = 0; j < LineCount; j++ ) {
  6395. KeyName = SpGetKeyName( SysrootRenameFile, SectionName, j );
  6396. Values[0] = SpGetSectionKeyIndex( SysrootRenameFile, SectionName, KeyName, 0 );
  6397. SpAddLineToSection( RootRenameFile,
  6398. NewSectionName,
  6399. KeyName,
  6400. Values,
  6401. 1 );
  6402. }
  6403. SpMemFree( NewSectionName );
  6404. }
  6405. }
  6406. //
  6407. // $$rename.txt on Sysroot is no longer needed
  6408. //
  6409. SpFreeTextFile( SysrootRenameFile );
  6410. SpDeleteFile( s, NULL, NULL );
  6411. }
  6412. //
  6413. // Add the files in RenameList to \$$rename.txt
  6414. //
  6415. if( RenameList != NULL ) {
  6416. do {
  6417. File = RenameList;
  6418. RenameList = File->Next;
  6419. Values[0] = File->TargetFilename;
  6420. SpAddLineToSection( RootRenameFile,
  6421. File->TargetDirectory,
  6422. File->SourceFilename,
  6423. Values,
  6424. 1 );
  6425. SpMemFree( File->SourceFilename );
  6426. SpMemFree( File->TargetFilename );
  6427. SpMemFree( File->TargetDirectory );
  6428. SpMemFree( File );
  6429. } while( RenameList != NULL );
  6430. }
  6431. //
  6432. // Create a new \$$rename.txt
  6433. //
  6434. SpWriteSetupTextFile( RootRenameFile, r, NULL, NULL );
  6435. //
  6436. // $$rename.txt on memory is no longer needed
  6437. //
  6438. SpFreeTextFile( RootRenameFile );
  6439. }
  6440. merge_rename_exit:
  6441. SpMemFree( s );
  6442. }
  6443. BOOLEAN
  6444. SpTimeFromDosTime(
  6445. IN USHORT Date,
  6446. IN USHORT Time,
  6447. OUT PLARGE_INTEGER UtcTime
  6448. )
  6449. {
  6450. //
  6451. // steal time from windows\base\client\datetime.c, DosDateTimeToFileTime()
  6452. // and LocalFileTimeToFileTime()
  6453. //
  6454. TIME_FIELDS TimeFields;
  6455. LARGE_INTEGER FileTime;
  6456. LARGE_INTEGER Bias;
  6457. TimeFields.Year = (CSHORT)((Date & 0xFE00) >> 9)+(CSHORT)1980;
  6458. TimeFields.Month = (CSHORT)((Date & 0x01E0) >> 5);
  6459. TimeFields.Day = (CSHORT)((Date & 0x001F) >> 0);
  6460. TimeFields.Hour = (CSHORT)((Time & 0xF800) >> 11);
  6461. TimeFields.Minute = (CSHORT)((Time & 0x07E0) >> 5);
  6462. TimeFields.Second = (CSHORT)((Time & 0x001F) << 1);
  6463. TimeFields.Milliseconds = 0;
  6464. if (RtlTimeFieldsToTime(&TimeFields,&FileTime)) {
  6465. //
  6466. // now convert to utc time
  6467. //
  6468. do {
  6469. Bias.HighPart = USER_SHARED_DATA->TimeZoneBias.High1Time;
  6470. Bias.LowPart = USER_SHARED_DATA->TimeZoneBias.LowPart;
  6471. } while (Bias.HighPart != USER_SHARED_DATA->TimeZoneBias.High2Time);
  6472. UtcTime->QuadPart = Bias.QuadPart + FileTime.QuadPart;
  6473. return(TRUE);
  6474. }
  6475. RtlSecondsSince1980ToTime( 0, UtcTime ); // default = 1-1-1980
  6476. return(FALSE);
  6477. }
  6478. BOOLEAN
  6479. pSpIsFileInDriverInf(
  6480. IN PCWSTR FileName,
  6481. IN PVOID SifHandle,
  6482. HANDLE *CabHandle
  6483. )
  6484. {
  6485. PWSTR InfFileName, CabFileName;
  6486. UINT FileCount,i,j;
  6487. PWSTR szSetupSourceDevicePath = 0;
  6488. PWSTR szDirectoryOnSetupSource = 0;
  6489. HANDLE hSif = (HANDLE)0;
  6490. CABDATA *MyCabData;
  6491. if (!DriverInfHandle) {
  6492. if (gpCmdConsBlock) {
  6493. szSetupSourceDevicePath = gpCmdConsBlock->SetupSourceDevicePath;
  6494. szDirectoryOnSetupSource = gpCmdConsBlock->DirectoryOnSetupSource;
  6495. hSif = (HANDLE)(gpCmdConsBlock->SifHandle);
  6496. } else {
  6497. if (ghSif && gszDrvInfDeviceName && gszDrvInfDirName) {
  6498. hSif = ghSif;
  6499. szSetupSourceDevicePath = gszDrvInfDeviceName;
  6500. szDirectoryOnSetupSource = gszDrvInfDirName;
  6501. }
  6502. }
  6503. if (szSetupSourceDevicePath && szDirectoryOnSetupSource &&
  6504. hSif) {
  6505. //
  6506. // try to open handle to drvindex.inf and to driver.cab,
  6507. // prompting for media if required
  6508. //
  6509. SpInitializeDriverInf( hSif,
  6510. szSetupSourceDevicePath,
  6511. szDirectoryOnSetupSource );
  6512. if (!DriverInfHandle)
  6513. return(FALSE);
  6514. } else {
  6515. return FALSE;
  6516. }
  6517. }
  6518. //
  6519. // look for the file in all loaded cabs, in order
  6520. //
  6521. MyCabData = CabData;
  6522. while (MyCabData) {
  6523. if (MyCabData->CabHandle && MyCabData->CabSectionName && MyCabData->CabInfHandle) {
  6524. if (!SifHandle || SifHandle == MyCabData->CabInfHandle) {
  6525. //
  6526. // look for entries in this inf
  6527. //
  6528. FileCount = SpCountLinesInSection(MyCabData->CabInfHandle, MyCabData->CabSectionName);
  6529. for (i=0; i< FileCount; i++) {
  6530. InfFileName = SpGetSectionLineIndex( MyCabData->CabInfHandle, MyCabData->CabSectionName, i, 0);
  6531. if (InfFileName && _wcsicmp (InfFileName, FileName) == 0) {
  6532. //
  6533. // Got him. Return the handle.
  6534. //
  6535. *CabHandle = MyCabData->CabHandle;
  6536. return TRUE;
  6537. }
  6538. }
  6539. }
  6540. }
  6541. MyCabData = MyCabData->Next;
  6542. }
  6543. return(FALSE);
  6544. }
  6545. NTSTATUS
  6546. SpOpenFileInDriverCab(
  6547. PCWSTR SourceFileName,
  6548. IN PVOID SifHandle,
  6549. HANDLE *SourceHandle
  6550. )
  6551. {
  6552. if (!pSpIsFileInDriverInf( SourceFileName, SifHandle, SourceHandle )) {
  6553. return STATUS_OBJECT_NAME_NOT_FOUND;
  6554. }
  6555. return STATUS_SUCCESS;
  6556. }
  6557. #ifdef _X86_
  6558. //
  6559. // Structure used by next few routines below. The SpMigMoveFileOrDir
  6560. // moves the file/dir with ntos rtl, but the rtl resets the attributes!!
  6561. // We have no choice but to traverse the file/dir and save the attributes
  6562. // in a list, then do the move, then restore the attributes from the list.
  6563. //
  6564. typedef struct {
  6565. ULONG BaseDirChars;
  6566. PWSTR BaseDir;
  6567. ULONG FileCount;
  6568. ULONG BytesNeeded;
  6569. PBYTE OriginalPos;
  6570. PBYTE CurrentPos; // NULL if callback should determine size and count
  6571. } ATTRIBS_LIST, *PATTRIBS_LIST;
  6572. VOID
  6573. SppAddAttributeToList (
  6574. IN ULONG Attributes,
  6575. IN PWSTR FileOrDir,
  6576. OUT PATTRIBS_LIST List
  6577. )
  6578. /*++
  6579. Routine Description:
  6580. This private function updates the attribute list. It has two modes:
  6581. (A) the size is being calculated or (B) the list is being created.
  6582. Arguments:
  6583. Attributes: The attributes of the file (needed for (B) only)
  6584. FileOrDir: Partial path to file or dir (it is relative to the
  6585. base path)
  6586. List: List structure that is updated
  6587. Return Value:
  6588. None.
  6589. --*/
  6590. {
  6591. ULONG BytesNeeded;
  6592. BytesNeeded = sizeof (ULONG) + (wcslen (FileOrDir) + 1) * sizeof (WCHAR);
  6593. if (List->CurrentPos) {
  6594. *((PULONG) List->CurrentPos) = Attributes;
  6595. wcscpy ((PWSTR) (List->CurrentPos + sizeof (ULONG)), FileOrDir);
  6596. List->CurrentPos += BytesNeeded;
  6597. } else {
  6598. List->BytesNeeded += BytesNeeded;
  6599. List->FileCount += 1;
  6600. }
  6601. }
  6602. BOOLEAN
  6603. SpAttribsEnumFile(
  6604. IN PCWSTR DirName,
  6605. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  6606. OUT PULONG ret,
  6607. IN PVOID Pointer
  6608. )
  6609. /*++
  6610. Routine Description:
  6611. SpAttribsEnumFile is an EnumFilesRecursive callback. It
  6612. recieves every file, dir, subfile and subdir for a file/dir
  6613. being moved. (It does not recieve the . and .. dirs.)
  6614. For each file, the attributes and file name are added to
  6615. the attribute list.
  6616. Arguments:
  6617. DirName: Path to the current directory
  6618. FileInfo: Structure containing information about the file or
  6619. subdir being enumerated.
  6620. ret: Return code used for failuers
  6621. Pointer: A pointer to an ATTRIBS_LIST structure.
  6622. Return Value:
  6623. TRUE unless an error occurs (errors stop enumeration).
  6624. --*/
  6625. {
  6626. PATTRIBS_LIST BufferInfo;
  6627. PWSTR p;
  6628. ULONG Attributes;
  6629. NTSTATUS Status;
  6630. PWSTR temp;
  6631. ULONG Len;
  6632. PWSTR FullPath;
  6633. BufferInfo = (PATTRIBS_LIST) Pointer;
  6634. //
  6635. // Check state of BufferInfo
  6636. //
  6637. ASSERT (wcslen(DirName) >= BufferInfo->BaseDirChars);
  6638. //
  6639. // Build the full file or dir path
  6640. //
  6641. temp = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  6642. Len = FileInfo->FileNameLength/sizeof(WCHAR);
  6643. wcsncpy(temp,FileInfo->FileName,Len);
  6644. temp[Len] = 0;
  6645. wcscpy(TemporaryBuffer,DirName);
  6646. SpConcatenatePaths(TemporaryBuffer,temp);
  6647. FullPath = SpDupStringW(TemporaryBuffer);
  6648. //
  6649. // Get attributes and add file to the list
  6650. //
  6651. Status = SpGetAttributes (FullPath, &Attributes);
  6652. if (NT_SUCCESS (Status)) {
  6653. SppAddAttributeToList (
  6654. Attributes,
  6655. FullPath + BufferInfo->BaseDirChars,
  6656. BufferInfo
  6657. );
  6658. } else {
  6659. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not get attributes for %ws, Status=%lx\n", FullPath, Status));
  6660. }
  6661. SpMemFree (FullPath);
  6662. return TRUE;
  6663. }
  6664. NTSTATUS
  6665. SpSaveFileOrDirAttribs (
  6666. IN PWSTR SourceFileOrDir,
  6667. OUT PATTRIBS_LIST BufferInfo
  6668. )
  6669. /*++
  6670. Routine Description:
  6671. This routine determines if SourceFileOrDir is a file or dir.
  6672. For a file, it obtains the attributes and puts it in the
  6673. supplied attribs list. For a dir, it obtains the attributes
  6674. of the dir, plus all attributes of subdirs and subfiles and
  6675. puts them in the supplied attribs list. This function uses
  6676. EnumFilesRecursive to enumerate everything in a directory.
  6677. Arguments:
  6678. SourceFileOrDir: Full path to a file or directory to build
  6679. an attribute list from.
  6680. BufferInfo: A caller-allocated ATTRIBS_LIST struct that
  6681. recieves a list of attributes and relative
  6682. paths.
  6683. Return Value:
  6684. Standard NT Status code.
  6685. --*/
  6686. {
  6687. LONG BaseAttribute;
  6688. NTSTATUS Status;
  6689. //
  6690. // Get attributes of base file or directory provided
  6691. //
  6692. Status = SpGetAttributes (SourceFileOrDir, &BaseAttribute);
  6693. if (!NT_SUCCESS (Status)) {
  6694. KdPrintEx((
  6695. DPFLTR_SETUP_ID,
  6696. DPFLTR_ERROR_LEVEL,
  6697. "SETUP:SpSaveFileOrDirAttribs, Failed to get attributes %ws - status 0x%08X.\n",
  6698. SourceFileOrDir,
  6699. Status));
  6700. return Status;
  6701. }
  6702. //
  6703. // Set the size required and file count for base file or dir
  6704. //
  6705. RtlZeroMemory (BufferInfo, sizeof (ATTRIBS_LIST));
  6706. BufferInfo->BaseDirChars = wcslen (SourceFileOrDir);
  6707. SppAddAttributeToList (BaseAttribute, L"", BufferInfo);
  6708. //
  6709. // If the supplied path is to a directory, find the number of bytes
  6710. // needed to hold a list of all subfiles and subdirectories.
  6711. //
  6712. if (BaseAttribute & FILE_ATTRIBUTE_DIRECTORY) {
  6713. // Determine space needed to hold all file names
  6714. SpEnumFilesRecursive (
  6715. SourceFileOrDir,
  6716. SpAttribsEnumFile,
  6717. &Status,
  6718. BufferInfo
  6719. );
  6720. }
  6721. //
  6722. // Allocate the file list
  6723. //
  6724. BufferInfo->OriginalPos = SpMemAlloc (BufferInfo->BytesNeeded);
  6725. BufferInfo->CurrentPos = BufferInfo->OriginalPos;
  6726. //
  6727. // Add the base attributes for real this time
  6728. //
  6729. SppAddAttributeToList (BaseAttribute, L"", BufferInfo);
  6730. //
  6731. // For directories, add all subfiles and subdirectories
  6732. //
  6733. if (BaseAttribute & FILE_ATTRIBUTE_DIRECTORY) {
  6734. // Add all files, dirs, subfiles and subdirs to the list
  6735. SpEnumFilesRecursive (
  6736. SourceFileOrDir,
  6737. SpAttribsEnumFile,
  6738. &Status,
  6739. BufferInfo
  6740. );
  6741. }
  6742. return Status;
  6743. }
  6744. VOID
  6745. SppRestoreAttributesFromList (
  6746. IN OUT PATTRIBS_LIST BufferInfo
  6747. )
  6748. /*++
  6749. Routine Description:
  6750. This routine restores the attributes associated with a file
  6751. in the supplied attribs list. After the attributes are set,
  6752. the list size is decremented. A few sanity checks are also
  6753. done.
  6754. Arguments:
  6755. BufferInfo: The attribs structure that has at least one
  6756. file/dir and attribute pair in it. The
  6757. list pointer is advanced and the file count
  6758. is decremented.
  6759. Return Value:
  6760. None.
  6761. --*/
  6762. {
  6763. ULONG Attributes;
  6764. PWSTR Path;
  6765. ULONG BytesNeeded;
  6766. PWSTR FullPath;
  6767. NTSTATUS Status;
  6768. Attributes = *((PULONG) BufferInfo->CurrentPos);
  6769. Path = (PWSTR) (BufferInfo->CurrentPos + sizeof (ULONG));
  6770. BytesNeeded = sizeof (ULONG) + (wcslen (Path) + 1) * sizeof (WCHAR);
  6771. // guard against abnormal failure
  6772. if (BytesNeeded > BufferInfo->BytesNeeded ||
  6773. !BufferInfo->BaseDir) {
  6774. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SppRestoreAttributesFromList failed abnormally\n"));
  6775. BufferInfo->FileCount = 0;
  6776. return;
  6777. }
  6778. //
  6779. // Prepare full path
  6780. //
  6781. wcscpy (TemporaryBuffer, BufferInfo->BaseDir);
  6782. if (*Path) {
  6783. SpConcatenatePaths(TemporaryBuffer, Path);
  6784. }
  6785. FullPath = SpDupStringW(TemporaryBuffer);
  6786. //
  6787. // Set attributes
  6788. //
  6789. Status = SpSetAttributes (FullPath, Attributes);
  6790. if (!NT_SUCCESS (Status)) {
  6791. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not set attributes for %ws, Status=%lx\n", FullPath, Status));
  6792. }
  6793. //
  6794. // Adjust position state
  6795. //
  6796. BufferInfo->CurrentPos += BytesNeeded;
  6797. BufferInfo->BytesNeeded -= BytesNeeded;
  6798. BufferInfo->FileCount -= 1;
  6799. //
  6800. // Cleanup
  6801. //
  6802. SpMemFree (FullPath);
  6803. }
  6804. VOID
  6805. SpCleanUpAttribsList (
  6806. IN PATTRIBS_LIST BufferInfo
  6807. )
  6808. /*++
  6809. Routine Description:
  6810. This is the cleanup routine needed by SpRestoreFileOrDirAttribs,
  6811. or by the ATTRIBS_LIST allocating function if the attributes
  6812. don't get restored.
  6813. This routine cannot be called twice on the same structure.
  6814. Arguments:
  6815. BufferInfo: The attribs structure to clean up.
  6816. Return Value:
  6817. None.
  6818. --*/
  6819. {
  6820. if (BufferInfo->OriginalPos) {
  6821. SpMemFree (BufferInfo->OriginalPos);
  6822. }
  6823. }
  6824. VOID
  6825. SpRestoreFileOrDirAttribs (
  6826. IN PWSTR DestFileOrDir,
  6827. IN PATTRIBS_LIST BufferInfo
  6828. )
  6829. /*++
  6830. Routine Description:
  6831. This routine calls SppRestoreAttributesFromList for every
  6832. file/dir and attribute pair in the supplied attribute list.
  6833. The attributes are applied to a new base dir. This function
  6834. is used to restore attributes after a file or directory has
  6835. been moved.
  6836. Arguments:
  6837. DestFileOrDir: The new full path of the file or dir
  6838. BufferInfo: The caller-allocated ATTRIBS_LIST that was
  6839. prepared by SpSaveFileOrDirAttribs.
  6840. Return Value:
  6841. None. (Errors are ignored.)
  6842. --*/
  6843. {
  6844. ULONG BaseAttributes;
  6845. NTSTATUS Status;
  6846. BufferInfo->CurrentPos = BufferInfo->OriginalPos;
  6847. BufferInfo->BaseDir = DestFileOrDir;
  6848. while (BufferInfo->FileCount > 0) {
  6849. SppRestoreAttributesFromList (BufferInfo);
  6850. }
  6851. SpCleanUpAttribsList (BufferInfo);
  6852. }
  6853. VOID
  6854. SpMigMoveFileOrDir (
  6855. IN PWSTR SourceFileOrDir,
  6856. IN PWSTR DestFileOrDir
  6857. )
  6858. /*++
  6859. Routine Description:
  6860. SpMigMoveFileOrDir sets the attribute of the source file to be
  6861. normal, moves the file into the destination, and resets the
  6862. attribute. If an error occurs, it is ignored. There's nothing
  6863. the user can do about the error, and it will be detected in GUI
  6864. mode. In an error condition, the user's settings will not be
  6865. completely migrated, but NT will install OK. (Any error would
  6866. be really bad news for the user anyhow, like a hardware failure.)
  6867. Arguments:
  6868. SourceFileOrDir: The source path (with DOS drive)
  6869. DestFileOrDir: The destination path (with DOS drive)
  6870. Return Value:
  6871. None. Errors ignored.
  6872. --*/
  6873. {
  6874. NTSTATUS Status;
  6875. PDISK_REGION SourceRegion; // source region (converted from DOS path)
  6876. PDISK_REGION DestRegion; // destination region (also converted)
  6877. PWSTR SrcNTPath; // buffer for full source path
  6878. PWSTR DestPartition; // buffer for destination partition in NT namespace
  6879. PWSTR DestNTPath; // buffer for full source dest
  6880. PWSTR DestDir; // DestFileOrDir with last subdir or file chopped off
  6881. PWSTR DestDirWack; // Used to find last subdir or file in DestDir path
  6882. ATTRIBS_LIST AttribsList; // used to save attribute list
  6883. // We are guaranteed to have drive letters because of WINNT32's behavior.
  6884. // However, let's verify and ignore messed up data.
  6885. if (!(SourceFileOrDir && SourceFileOrDir[0] && SourceFileOrDir[1] == L':')) {
  6886. return;
  6887. }
  6888. if (!(DestFileOrDir && DestFileOrDir[0] && DestFileOrDir[1] == L':')) {
  6889. return;
  6890. }
  6891. // Get regions for DOS paths
  6892. SourceRegion = SpRegionFromDosName (SourceFileOrDir);
  6893. if (!SourceRegion) {
  6894. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  6895. "SETUP: SpRegionFromDosName failed for %ws\n", SourceFileOrDir));
  6896. return;
  6897. }
  6898. DestRegion = SpRegionFromDosName (DestFileOrDir);
  6899. if (!DestRegion) {
  6900. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  6901. "SETUP: SpRegionFromDosName failed for %ws\n", DestFileOrDir));
  6902. return;
  6903. }
  6904. // Make full paths
  6905. SpNtNameFromRegion(
  6906. SourceRegion,
  6907. TemporaryBuffer,
  6908. sizeof(TemporaryBuffer),
  6909. // no repartioning is possible, so this is the same ordinal
  6910. // as the original
  6911. PartitionOrdinalCurrent
  6912. );
  6913. SpConcatenatePaths( TemporaryBuffer, &SourceFileOrDir[2]);
  6914. SrcNTPath = SpDupStringW(TemporaryBuffer);
  6915. SpNtNameFromRegion(
  6916. DestRegion,
  6917. TemporaryBuffer,
  6918. sizeof(TemporaryBuffer),
  6919. PartitionOrdinalCurrent
  6920. );
  6921. DestPartition = SpDupStringW(TemporaryBuffer);
  6922. SpConcatenatePaths( TemporaryBuffer, &DestFileOrDir[2]);
  6923. DestNTPath = SpDupStringW(TemporaryBuffer);
  6924. // Save file attribs
  6925. Status = SpSaveFileOrDirAttribs (SrcNTPath, &AttribsList);
  6926. if (NT_SUCCESS (Status)) {
  6927. // Reset file attribs
  6928. Status = SpSetAttributes (SrcNTPath, FILE_ATTRIBUTE_NORMAL);
  6929. if (NT_SUCCESS (Status)) {
  6930. // Ensure destination exists
  6931. DestDir = SpDupStringW (&DestFileOrDir[2]);
  6932. if (DestDir) {
  6933. DestDirWack = wcsrchr (DestDir, L'\\');
  6934. if (DestDirWack) {
  6935. *DestDirWack = 0;
  6936. }
  6937. SpCreateDirectory (DestPartition,
  6938. NULL,
  6939. DestDir,
  6940. 0,
  6941. 0);
  6942. SpMemFree (DestDir);
  6943. }
  6944. // Move the file or directory tree
  6945. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  6946. "SETUP: Moving %ws to %ws\n", SrcNTPath, DestNTPath));
  6947. Status = SpMoveFileOrDirectory (SrcNTPath, DestNTPath);
  6948. // Restore attributes
  6949. if (NT_SUCCESS (Status)) {
  6950. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  6951. "SETUP: Restoring attributes on %ws\n", DestNTPath));
  6952. SpRestoreFileOrDirAttribs (DestNTPath, &AttribsList);
  6953. } else {
  6954. SpCleanUpAttribsList (&AttribsList);
  6955. }
  6956. }
  6957. else {
  6958. KdPrintEx((
  6959. DPFLTR_SETUP_ID,
  6960. DPFLTR_ERROR_LEVEL,
  6961. "SETUP:SpMigMoveFileOrDir, Could not set attributes for %ws, Status=%lx\n",
  6962. SrcNTPath,
  6963. Status));
  6964. }
  6965. }
  6966. else{
  6967. KdPrintEx((
  6968. DPFLTR_SETUP_ID,
  6969. DPFLTR_ERROR_LEVEL,
  6970. "SETUP:SpMigMoveFileOrDir, Function \"SpSaveFileOrDirAttribs\" failed with %ws, Status=%lx\n",
  6971. SrcNTPath,
  6972. Status));
  6973. }
  6974. if( !NT_SUCCESS( Status ) ) {
  6975. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  6976. "SETUP: Unable to move file %ws to %ws. Status = %lx \n",
  6977. SrcNTPath, DestNTPath, Status ));
  6978. }
  6979. // Clean up
  6980. SpMemFree( SrcNTPath );
  6981. SpMemFree( DestNTPath );
  6982. SpMemFree( DestPartition );
  6983. }
  6984. VOID
  6985. SpMigDeleteFile (
  6986. PWSTR DosFileToDelete
  6987. )
  6988. /*++
  6989. Routine Description:
  6990. SpMigDeleteFile sets the attribute of the source file to be
  6991. normal, and then deletes the file. If an error occurs, it
  6992. is ignored. There's nothing the user can do about the error,
  6993. and it will be detected in file copy. In an error condition,
  6994. there is a potential for two copies of the same file--an NT
  6995. version and a Win9x version. Any error would be really
  6996. bad news for the user anyhow, like a hardware failure, and
  6997. textmode's file copy won't succeed.
  6998. Arguments:
  6999. DosFileToDelete: The source path (with DOS drive)
  7000. Return Value:
  7001. None. Errors ignored.
  7002. --*/
  7003. {
  7004. NTSTATUS Status;
  7005. PDISK_REGION SourceRegion; // source region (converted from DOS path)
  7006. PWSTR SrcNTPath; // buffer for full source path
  7007. // We are guaranteed to have drive letters because of WINNT32's behavior.
  7008. // However, let's verify and ignore messed up data.
  7009. if (!(DosFileToDelete && DosFileToDelete[0] && DosFileToDelete[1] == L':'))
  7010. return;
  7011. // Get region for DOS path
  7012. SourceRegion = SpRegionFromDosName (DosFileToDelete);
  7013. if (!SourceRegion) {
  7014. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRegionFromDosName failed for %ws\n", DosFileToDelete));
  7015. return;
  7016. }
  7017. SpNtNameFromRegion(
  7018. SourceRegion,
  7019. TemporaryBuffer,
  7020. sizeof(TemporaryBuffer),
  7021. // no repartioning is possible, so this is the same ordinal
  7022. // as the original
  7023. PartitionOrdinalCurrent
  7024. );
  7025. SpConcatenatePaths (TemporaryBuffer, &DosFileToDelete[2]);
  7026. SrcNTPath = SpDupStringW (TemporaryBuffer);
  7027. SpSetAttributes (SrcNTPath, FILE_ATTRIBUTE_NORMAL);
  7028. if (SpFileExists (SrcNTPath, FALSE)) {
  7029. //
  7030. // Delete the file
  7031. //
  7032. Status = SpDeleteFile (SrcNTPath, NULL, NULL);
  7033. } else if (SpFileExists (SrcNTPath, TRUE)) {
  7034. //
  7035. // Delete the empty directory
  7036. //
  7037. Status = SpDeleteFileEx (
  7038. SrcNTPath,
  7039. NULL,
  7040. NULL,
  7041. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  7042. FILE_OPEN_FOR_BACKUP_INTENT
  7043. );
  7044. } else {
  7045. //
  7046. // Doesn't exist -- ignore delete request
  7047. //
  7048. Status = STATUS_SUCCESS;
  7049. }
  7050. if(!NT_SUCCESS(Status)) {
  7051. KdPrintEx((
  7052. DPFLTR_SETUP_ID,
  7053. DPFLTR_ERROR_LEVEL,
  7054. "SETUP: Unable to delete %ws. Status = %lx \n",
  7055. SrcNTPath,
  7056. Status
  7057. ));
  7058. }
  7059. // Clean up
  7060. SpMemFree( SrcNTPath );
  7061. }
  7062. #endif // defined _X86_
  7063. NTSTATUS
  7064. SpExpandFile(
  7065. IN PWSTR SourceFilename,
  7066. IN PWSTR TargetPathname,
  7067. IN PEXPAND_CALLBACK Callback,
  7068. IN PVOID CallbackContext
  7069. )
  7070. /*++
  7071. Routine Description:
  7072. Attempt to decompress contents of a file, reporting progress via callback.
  7073. Arguments:
  7074. SourceFilename - supplies fully qualified name of compressed file
  7075. in the NT namespace.
  7076. TargetPathname - supplies fully qualified path for target file(s)
  7077. in the NT namespace.
  7078. Return Value:
  7079. NT Status value indicating outcome.
  7080. --*/
  7081. {
  7082. NTSTATUS Status;
  7083. HANDLE SourceHandle = INVALID_HANDLE_VALUE;
  7084. IO_STATUS_BLOCK IoStatusBlock;
  7085. ULONG FileSize;
  7086. PVOID ImageBase;
  7087. HANDLE SectionHandle = INVALID_HANDLE_VALUE;
  7088. BOOLEAN IsCabinet = FALSE;
  7089. BOOLEAN IsMultiFileCabinet;
  7090. OBJECT_ATTRIBUTES Obja;
  7091. UNICODE_STRING UnicodeString;
  7092. //
  7093. // Open the source file.
  7094. //
  7095. INIT_OBJA(&Obja,&UnicodeString,SourceFilename);
  7096. Status = ZwCreateFile( &SourceHandle,
  7097. FILE_GENERIC_READ,
  7098. &Obja,
  7099. &IoStatusBlock,
  7100. NULL,
  7101. FILE_ATTRIBUTE_NORMAL,
  7102. FILE_SHARE_READ,
  7103. FILE_OPEN,
  7104. 0,
  7105. NULL,
  7106. 0 );
  7107. if( !NT_SUCCESS(Status) ) {
  7108. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpExpandFile: Unable to open source file %ws (%x)\n",SourceFilename,Status));
  7109. goto exit;
  7110. }
  7111. Status = SpGetFileSize( SourceHandle, &FileSize );
  7112. if( !NT_SUCCESS(Status) ) {
  7113. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpExpandFile: unable to get size of %ws (%x)\n",SourceFilename,Status));
  7114. goto exit;
  7115. }
  7116. Status = SpMapEntireFile( SourceHandle, &SectionHandle, &ImageBase, FALSE );
  7117. if( !NT_SUCCESS(Status) ) {
  7118. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpExpandFile: Unable to map source file %ws (%x)\n",SourceFilename,Status));
  7119. goto exit;
  7120. }
  7121. IsCabinet = SpdIsCabinet( ImageBase, FileSize, &IsMultiFileCabinet );
  7122. if ( !IsCabinet ) {
  7123. LARGE_INTEGER Zero;
  7124. Zero.QuadPart = 0;
  7125. Callback( EXPAND_NOTIFY_CANNOT_EXPAND,
  7126. SourceFilename,
  7127. &Zero,
  7128. &Zero,
  7129. 0,
  7130. CallbackContext );
  7131. Status = STATUS_UNSUCCESSFUL;
  7132. goto exit;
  7133. }
  7134. //
  7135. // Advise client if the source contains multiple files
  7136. //
  7137. if ( IsMultiFileCabinet ) {
  7138. EXPAND_CALLBACK_RESULT rc;
  7139. LARGE_INTEGER Zero;
  7140. Zero.QuadPart = 0;
  7141. rc = Callback( EXPAND_NOTIFY_MULTIPLE,
  7142. SourceFilename,
  7143. &Zero,
  7144. &Zero,
  7145. 0,
  7146. CallbackContext );
  7147. if ( rc == EXPAND_ABORT ) {
  7148. Status = STATUS_UNSUCCESSFUL;
  7149. goto exit;
  7150. }
  7151. }
  7152. Status = SpdDecompressCabinet( ImageBase,
  7153. FileSize,
  7154. TargetPathname,
  7155. Callback,
  7156. CallbackContext );
  7157. exit:
  7158. if (SectionHandle != INVALID_HANDLE_VALUE) {
  7159. SpUnmapFile( SectionHandle, ImageBase );
  7160. }
  7161. if ( SourceHandle != INVALID_HANDLE_VALUE ) {
  7162. ZwClose( SourceHandle );
  7163. }
  7164. return(Status);
  7165. }