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

9154 lines
274 KiB

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