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.

5412 lines
170 KiB

  1. #include "precomp.h"
  2. #include "SetupSxs.h"
  3. #include "sputils.h"
  4. #pragma hdrstop
  5. //
  6. // Structure used to contain data about each directory
  7. // containing files we will copy from the source(s).
  8. //
  9. typedef struct _DIR {
  10. struct _DIR *Next;
  11. #ifndef SLOWER_WAY
  12. struct _DIR *Prev;
  13. #endif
  14. //
  15. // Symbol in main inf [Directories] section.
  16. // May be NULL.
  17. //
  18. LPCTSTR InfSymbol;
  19. //
  20. // Flags.
  21. //
  22. UINT Flags;
  23. //
  24. // In some cases files come from one directory on the source
  25. // but go to a different directory on the target.
  26. //
  27. LPCTSTR SourceName;
  28. LPCTSTR TargetName;
  29. } DIR, *PDIR;
  30. #define WINDOWS_DEFAULT_PFDOC_SIZE 81112
  31. #define DIR_NEED_TO_FREE_SOURCENAME 0x00000001
  32. #define DIR_ABSOLUTE_PATH 0x00000002
  33. #define DIR_USE_SUBDIR 0x00000004
  34. // If DIR_IS_PLATFORM_INDEPEND is passed to AddDirectory, then
  35. // all the files it enumerates will have their FILE_IN_PLATFORM_INDEPEND_DIR
  36. // flag set and then they will get copied to c:\$win_nt$.~ls instead of
  37. // c:\$win_nt$.~ls\<processor>
  38. #define DIR_IS_PLATFORM_INDEPEND 0x00000008
  39. #define DIR_SUPPORT_DYNAMIC_UPDATE 0x00000010
  40. #define DIR_DOESNT_SUPPORT_PRIVATES 0x00000020
  41. //
  42. // Dummy directory id we use for sections in the in (like [RootBootFiles])
  43. // that don't have a directory specifier in the inf
  44. //
  45. #define DUMMY_DIRID TEXT("**")
  46. typedef struct _FIL {
  47. //
  48. // Size of file.
  49. //
  50. ULONGLONG Size;
  51. struct _FIL *Next;
  52. #ifndef SLOWER_WAY
  53. struct _FIL *Prev;
  54. #endif
  55. //
  56. // Directory information for the file.
  57. //
  58. PDIR Directory;
  59. //
  60. // Name of file on source.
  61. //
  62. LPCTSTR SourceName;
  63. //
  64. // Name of file on target.
  65. //
  66. LPCTSTR TargetName;
  67. UINT Flags;
  68. //
  69. // Bitmap used to track which threads have had a crack at
  70. // copying this file.
  71. //
  72. UINT ThreadBitmap;
  73. } FIL, *PFIL;
  74. #define FILE_NEED_TO_FREE_SOURCENAME 0x00000001
  75. #define FILE_NEED_TO_FREE_TARGETNAME 0x00000002
  76. #define FILE_ON_SYSTEM_PARTITION_ROOT 0x00000004
  77. #define FILE_IN_PLATFORM_INDEPEND_DIR 0x00000008
  78. #define FILE_PRESERVE_COMPRESSED_NAME 0x00000010
  79. #define FILE_DECOMPRESS 0x00000020
  80. #define FILE_IGNORE_COPY_ERROR 0x00000040
  81. #define FILE_DO_NOT_COPY 0x00000080
  82. #if defined(REMOTE_BOOT)
  83. #define FILE_ON_MACHINE_DIRECTORY_ROOT 0x00000100 // for remote boot
  84. #endif // defined(REMOTE_BOOT)
  85. //
  86. // This flag is really only meaningful on amd64/x86. It means that the file
  87. // is in the \$win_nt$.~bt directory on the system partition and not in
  88. // \$win_nt$.~ls.
  89. //
  90. #define FILE_IN_LOCAL_BOOT 0x80000000
  91. //
  92. // This flag indicates that the file is not part of the product,
  93. // and should be migrated from the current NT system. When this flag is
  94. // set, the file should be moved to the $win_nt$.~bt directory (amd64/x86),
  95. // or to the $win_nt$.~ls\alpha directory (alpha).
  96. // This flag is not valid on Win95.
  97. //
  98. #define FILE_NT_MIGRATE 0x40000000
  99. typedef struct _COPY_LIST {
  100. PDIR Directories;
  101. PFIL Files;
  102. UINT DirectoryCount;
  103. UINT FileCount;
  104. //
  105. // These members aren't initialized until we actually start
  106. // the copying.
  107. //
  108. CRITICAL_SECTION CriticalSection;
  109. BOOL ActiveCS;
  110. HANDLE StopCopyingEvent;
  111. HANDLE ListReadyEvent[MAX_SOURCE_COUNT];
  112. HANDLE Threads[MAX_SOURCE_COUNT];
  113. ULONGLONG SpaceOccupied[MAX_SOURCE_COUNT];
  114. HWND hdlg;
  115. } COPY_LIST, *PCOPY_LIST;
  116. typedef struct _BUILD_LIST_THREAD_PARAMS {
  117. //
  118. // Copy list that gets built up by the thread.
  119. // It's a private list; the main thread merges all of these together
  120. // into the master list later.
  121. //
  122. COPY_LIST CopyList;
  123. TCHAR SourceRoot[MAX_PATH];
  124. TCHAR CurrentDirectory[MAX_PATH];
  125. TCHAR DestinationDirectory[MAX_PATH];
  126. WIN32_FIND_DATA FindData;
  127. DWORD OptionalDirFlags;
  128. } BUILD_LIST_THREAD_PARAMS, *PBUILD_LIST_THREAD_PARAMS;
  129. //
  130. // Define structure used with the file copy error dialog.
  131. //
  132. typedef struct _COPY_ERR_DLG_PARAMS {
  133. LPCTSTR SourceFilename;
  134. LPCTSTR TargetFilename;
  135. UINT Win32Error;
  136. } COPY_ERR_DLG_PARAMS,*PCOPY_ERR_DLG_PARAMS;
  137. typedef struct _NAME_AND_SIZE_CAB {
  138. LPCTSTR Name;
  139. ULONGLONG Size;
  140. } NAME_AND_SIZE_CAB, *PNAME_AND_SIZE_CAB;
  141. COPY_LIST MasterCopyList;
  142. BOOL MainCopyStarted;
  143. //
  144. // Names of relevent inf sections.
  145. //
  146. LPCTSTR szDirectories = TEXT("Directories");
  147. LPCTSTR szFiles = TEXT("Files");
  148. LPCTSTR szDiskSpaceReq = TEXT("DiskSpaceRequirements");
  149. LPCTSTR szPFDocSpaceReq = TEXT("PFDocSpace");
  150. //
  151. // Amount of space we need when scanning all the
  152. // drives for a place to put the temporary files.
  153. //
  154. ULONGLONG MinDiskSpaceRequired;
  155. ULONGLONG MaxDiskSpaceRequired;
  156. TCHAR DiskDiagMessage[5000];
  157. //
  158. // Amount of space occupied by the files in the master copy list,
  159. // on the local source drive.
  160. //
  161. DWORD LocalSourceDriveClusterSize;
  162. ULONGLONG TotalDataCopied = 0;
  163. DWORD
  164. BuildCopyListForOptionalDirThread(
  165. IN PVOID ThreadParam
  166. );
  167. DWORD
  168. AddFilesInDirToCopyList(
  169. IN OUT PBUILD_LIST_THREAD_PARAMS Params
  170. );
  171. PDIR
  172. AddDirectory(
  173. IN LPCTSTR InfSymbol, OPTIONAL
  174. IN OUT PCOPY_LIST CopyList,
  175. IN LPCTSTR SourceName,
  176. IN LPCTSTR TargetName, OPTIONAL
  177. IN UINT Flags
  178. );
  179. PFIL
  180. AddFile(
  181. IN OUT PCOPY_LIST CopyList,
  182. IN LPCTSTR SourceFilename,
  183. IN LPCTSTR TargetFilename, OPTIONAL
  184. IN PDIR Directory,
  185. IN UINT Flags,
  186. IN ULONGLONG FileSize OPTIONAL
  187. );
  188. DWORD
  189. AddSection(
  190. IN PVOID Inf,
  191. IN OUT PCOPY_LIST CopyList,
  192. IN LPCTSTR SectionName,
  193. OUT UINT *ErrorLine,
  194. IN UINT FileFlags,
  195. IN BOOL SimpleList,
  196. IN BOOL DoDriverCabPruning
  197. );
  198. PDIR
  199. LookUpDirectory(
  200. IN PCOPY_LIST CopyList,
  201. IN LPCTSTR DirSymbol
  202. );
  203. VOID
  204. TearDownCopyList(
  205. IN OUT PCOPY_LIST CopyList
  206. );
  207. DWORD
  208. CopyOneFile(
  209. IN PFIL File,
  210. IN UINT SourceOrdinal,
  211. OUT PTSTR TargetFilename,
  212. IN INT CchTargetFilename,
  213. OUT ULONGLONG *SpaceOccupied
  214. );
  215. INT_PTR
  216. CopyErrDlgProc(
  217. IN HWND hdlg,
  218. IN UINT msg,
  219. IN WPARAM wParam,
  220. IN LPARAM lParam
  221. );
  222. UINT
  223. DiamondCallback(
  224. IN PVOID Context,
  225. IN UINT Code,
  226. IN UINT_PTR Param1,
  227. IN UINT_PTR Param2
  228. );
  229. LRESULT
  230. DiskDlgProc(
  231. IN HWND hdlg,
  232. IN UINT msg,
  233. IN WPARAM wParam,
  234. IN LPARAM lParam
  235. );
  236. BOOL
  237. BuildCopyListWorker(
  238. IN HWND hdlg
  239. )
  240. /*++
  241. Routine Description:
  242. Worker routine to build the queue of file to be copied.
  243. Arguments:
  244. hdlg - window handle for any UI updates.
  245. Return Value:
  246. TRUE/FALSE. If the call succeeds, TRUE is returned and the global MasterCopyList structure
  247. is ready to be copied.
  248. --*/
  249. {
  250. BOOL b;
  251. UINT u;
  252. UINT source;
  253. UINT thread;
  254. DWORD d = NO_ERROR;
  255. DWORD TempError;
  256. BUILD_LIST_THREAD_PARAMS BuildParams[MAX_OPTIONALDIRS];
  257. BUILD_LIST_THREAD_PARAMS bltp;
  258. HANDLE BuildThreads[MAX_OPTIONALDIRS];
  259. DWORD ThreadId;
  260. LPCTSTR Id,DirectoryName;
  261. PDIR DirectoryStruct;
  262. PFIL FileStruct;
  263. UINT ErrorLine;
  264. UINT i;
  265. TCHAR c;
  266. BOOL AllSourcesLocal;
  267. TCHAR floppynum[40];
  268. LPCTSTR DummyDirectoryName;
  269. TCHAR buffer[MAX_PATH];
  270. PTSTR p;
  271. TCHAR SourceDirectory[MAX_PATH];
  272. WIN32_FIND_DATA fd;
  273. #ifdef PRERELEASE
  274. LONG lines1, lines2, l;
  275. TCHAR* dirNames;
  276. PDIR* dirStructs;
  277. PCTSTR src, dst;
  278. TCHAR tmp[MAX_PATH];
  279. #endif
  280. TearDownCopyList(&MasterCopyList);
  281. DebugLog (Winnt32LogDetailedInformation, TEXT("Building Copy list."), 0);
  282. //
  283. // If NOLs was specified on the command line, and the user
  284. // did not specify to make a local source, and we have
  285. // exactly one source that is a hdd, then turn of ls and
  286. // use that drive.
  287. //
  288. if (MakeLocalSource && NoLs && !UserSpecifiedMakeLocalSource) {
  289. if (SourceCount == 1 && MyGetDriveType (*SourcePaths[0]) == DRIVE_FIXED) {
  290. MakeLocalSource = FALSE;
  291. DebugLog (Winnt32LogDetailedInformation, TEXT("Not making local source."), 0);
  292. }
  293. }
  294. #ifdef PRERELEASE
  295. if( !BuildCmdcons) {
  296. DebugLog (Winnt32LogDetailedInformation, TEXT("Adding SymbolDirs to copylist"), 0);
  297. //
  298. // for internal debugging, also copy all the .pdb files listed
  299. // in dosnet.inf
  300. //
  301. lines1 = InfGetSectionLineCount (MainInf, TEXT("SymbolDirs"));
  302. lines2 = InfGetSectionLineCount (MainInf, TEXT("SymbolFiles"));
  303. if (lines1 > 0 && lines2 > 0) {
  304. dirNames = (TCHAR*) MALLOC (lines1 * MAX_PATH * sizeof (TCHAR));
  305. dirStructs = (PDIR*) MALLOC (lines1 * sizeof (PDIR));
  306. if (dirNames && dirStructs) {
  307. u = 0;
  308. for (l = 0; l < lines1; l++) {
  309. lstrcpy (tmp, SourcePaths[0]);
  310. src = InfGetFieldByIndex (MainInf, TEXT("SymbolDirs"), l, 0);
  311. if (!src) {
  312. continue;
  313. }
  314. ConcatenatePaths (tmp, src, MAX_PATH);
  315. if (!GetFullPathName (tmp, MAX_PATH, SourceDirectory, NULL)) {
  316. continue;
  317. }
  318. if (!FileExists (SourceDirectory, &fd) || !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  319. continue;
  320. }
  321. dst = InfGetFieldByIndex (MainInf, TEXT("SymbolDirs"), l, 1);
  322. if (!dst) {
  323. dst = TEXT("symbols");
  324. }
  325. dirStructs[u] = AddDirectory (
  326. NULL,
  327. &MasterCopyList,
  328. SourceDirectory,
  329. dst,
  330. DIR_ABSOLUTE_PATH | DIR_NEED_TO_FREE_SOURCENAME
  331. );
  332. lstrcpyn (&dirNames[u * MAX_PATH], SourceDirectory, MAX_PATH);
  333. u++;
  334. }
  335. for (l = 0; l < lines2; l++) {
  336. src = InfGetFieldByIndex (MainInf, TEXT("SymbolFiles"), l, 0);
  337. if (!src) {
  338. continue;
  339. }
  340. for (i = 0; i < u; i++) {
  341. BuildPath (tmp, &dirNames[i * MAX_PATH], src);
  342. if (!FileExists (tmp, &fd) || (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  343. continue;
  344. }
  345. if (dirStructs[i]) {
  346. AddFile (&MasterCopyList, src, NULL, dirStructs[i], FILE_IGNORE_COPY_ERROR, fd.nFileSizeLow);
  347. break;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. }
  354. #endif
  355. //
  356. // copy any downloaded drivers under the local boot directory,
  357. // together with updates.cab/.sif if they are present
  358. //
  359. if (DynamicUpdateSuccessful ()) {
  360. if (g_DynUpdtStatus->UpdatesCabSource[0]) {
  361. lstrcpy (buffer, g_DynUpdtStatus->UpdatesCabSource);
  362. p = _tcsrchr (buffer, TEXT('\\'));
  363. if (!p) {
  364. d = ERROR_INVALID_PARAMETER;
  365. goto c1;
  366. }
  367. *p++ = 0;
  368. DirectoryStruct = AddDirectory (
  369. NULL,
  370. &MasterCopyList,
  371. buffer,
  372. NULL,
  373. DIR_ABSOLUTE_PATH | DIR_NEED_TO_FREE_SOURCENAME | DIR_DOESNT_SUPPORT_PRIVATES
  374. );
  375. if (!DirectoryStruct) {
  376. d = ERROR_NOT_ENOUGH_MEMORY;
  377. goto c1;
  378. }
  379. FileStruct = AddFile (
  380. &MasterCopyList,
  381. p,
  382. NULL,
  383. DirectoryStruct,
  384. FILE_IN_LOCAL_BOOT | FILE_NEED_TO_FREE_SOURCENAME,
  385. 0
  386. );
  387. if (!FileStruct) {
  388. d = ERROR_NOT_ENOUGH_MEMORY;
  389. goto c1;
  390. }
  391. //
  392. // now copy the SIF file
  393. //
  394. if (!BuildSifName (g_DynUpdtStatus->UpdatesCabSource, buffer, ARRAYSIZE(buffer))) {
  395. d = ERROR_INVALID_PARAMETER;
  396. goto c1;
  397. }
  398. p = _tcsrchr (buffer, TEXT('\\'));
  399. if (!p) {
  400. d = ERROR_INVALID_PARAMETER;
  401. goto c1;
  402. }
  403. *p++ = 0;
  404. //
  405. // the directory is the same as before
  406. //
  407. FileStruct = AddFile (
  408. &MasterCopyList,
  409. p,
  410. NULL,
  411. DirectoryStruct,
  412. FILE_IN_LOCAL_BOOT | FILE_NEED_TO_FREE_SOURCENAME,
  413. 0
  414. );
  415. if (!FileStruct) {
  416. d = ERROR_NOT_ENOUGH_MEMORY;
  417. goto c1;
  418. }
  419. }
  420. if (g_DynUpdtStatus->DuasmsSource[0]) {
  421. ZeroMemory (&bltp, sizeof(bltp));
  422. lstrcpy (bltp.CurrentDirectory, g_DynUpdtStatus->DuasmsSource);
  423. lstrcpy (bltp.DestinationDirectory, S_SUBDIRNAME_DUASMS);
  424. bltp.OptionalDirFlags = OPTDIR_TEMPONLY | OPTDIR_ABSOLUTE | OPTDIR_IN_LOCAL_BOOT | OPTDIR_DOESNT_SUPPORT_PRIVATES;
  425. d = AddFilesInDirToCopyList (&bltp);
  426. if(d != NO_ERROR) {
  427. goto c1;
  428. }
  429. //
  430. // Merge the copy list into the master copy list.
  431. //
  432. MasterCopyList.FileCount += bltp.CopyList.FileCount;
  433. MasterCopyList.DirectoryCount += bltp.CopyList.DirectoryCount;
  434. if(MasterCopyList.Directories) {
  435. #ifndef SLOWER_WAY
  436. if (bltp.CopyList.Directories) {
  437. PVOID p;
  438. p = bltp.CopyList.Directories->Prev;
  439. bltp.CopyList.Directories->Prev = MasterCopyList.Directories->Prev;
  440. MasterCopyList.Directories->Prev->Next = bltp.CopyList.Directories;
  441. MasterCopyList.Directories->Prev = p;
  442. }
  443. #else
  444. for(DirectoryStruct=MasterCopyList.Directories;
  445. DirectoryStruct->Next;
  446. DirectoryStruct=DirectoryStruct->Next) {
  447. ;
  448. }
  449. DirectoryStruct->Next = bltp.CopyList.Directories;
  450. #endif
  451. } else {
  452. MasterCopyList.Directories = bltp.CopyList.Directories;
  453. }
  454. if(MasterCopyList.Files) {
  455. #ifndef SLOWER_WAY
  456. if (bltp.CopyList.Files) {
  457. PVOID p;
  458. p = bltp.CopyList.Files->Prev;
  459. bltp.CopyList.Files->Prev = MasterCopyList.Files->Prev;
  460. MasterCopyList.Files->Prev->Next = bltp.CopyList.Files;
  461. MasterCopyList.Files->Prev = p ;
  462. }
  463. #else
  464. for(FileStruct=MasterCopyList.Files;
  465. FileStruct->Next;
  466. FileStruct=FileStruct->Next) {
  467. ;
  468. }
  469. FileStruct->Next = bltp.CopyList.Files;
  470. #endif
  471. } else {
  472. MasterCopyList.Files = bltp.CopyList.Files;
  473. }
  474. }
  475. if (g_DynUpdtStatus->NewDriversList) {
  476. ZeroMemory(&bltp,sizeof(bltp));
  477. lstrcpy (bltp.CurrentDirectory, g_DynUpdtStatus->SelectedDrivers);
  478. lstrcpy (bltp.DestinationDirectory, S_SUBDIRNAME_DRIVERS);
  479. bltp.OptionalDirFlags = OPTDIR_TEMPONLY | OPTDIR_ABSOLUTE | OPTDIR_IN_LOCAL_BOOT | OPTDIR_DOESNT_SUPPORT_PRIVATES;
  480. d = AddFilesInDirToCopyList (&bltp);
  481. if(d != NO_ERROR) {
  482. goto c1;
  483. }
  484. //
  485. // Merge the copy list into the master copy list.
  486. //
  487. MasterCopyList.FileCount += bltp.CopyList.FileCount;
  488. MasterCopyList.DirectoryCount += bltp.CopyList.DirectoryCount;
  489. if(MasterCopyList.Directories) {
  490. #ifndef SLOWER_WAY
  491. if (bltp.CopyList.Directories) {
  492. PVOID p;
  493. p = bltp.CopyList.Directories->Prev;
  494. bltp.CopyList.Directories->Prev = MasterCopyList.Directories->Prev;
  495. MasterCopyList.Directories->Prev->Next = bltp.CopyList.Directories;
  496. MasterCopyList.Directories->Prev = p;
  497. }
  498. #else
  499. for(DirectoryStruct=MasterCopyList.Directories;
  500. DirectoryStruct->Next;
  501. DirectoryStruct=DirectoryStruct->Next) {
  502. ;
  503. }
  504. DirectoryStruct->Next = bltp.CopyList.Directories;
  505. #endif
  506. } else {
  507. MasterCopyList.Directories = bltp.CopyList.Directories;
  508. }
  509. if(MasterCopyList.Files) {
  510. #ifndef SLOWER_WAY
  511. if (bltp.CopyList.Files) {
  512. PVOID p;
  513. p = bltp.CopyList.Files->Prev;
  514. bltp.CopyList.Files->Prev = MasterCopyList.Files->Prev;
  515. MasterCopyList.Files->Prev->Next = bltp.CopyList.Files;
  516. MasterCopyList.Files->Prev = p ;
  517. }
  518. #else
  519. for(FileStruct=MasterCopyList.Files;
  520. FileStruct->Next;
  521. FileStruct=FileStruct->Next) {
  522. ;
  523. }
  524. FileStruct->Next = bltp.CopyList.Files;
  525. #endif
  526. } else {
  527. MasterCopyList.Files = bltp.CopyList.Files;
  528. }
  529. }
  530. }
  531. //
  532. // Add the mandatory optional dirs to the list of optional dirs.
  533. // These are specified in txtsetup.sif.
  534. //
  535. DebugLog (Winnt32LogDetailedInformation, TEXT("Adding OptionalSrcDirs to optional dirs."), 0);
  536. u = 0;
  537. while(DirectoryName = InfGetFieldByIndex(MainInf,TEXT("OptionalSrcDirs"),u++,0)) {
  538. TCHAR TempString[MAX_PATH];
  539. RememberOptionalDir(DirectoryName,OPTDIR_TEMPONLY |OPTDIR_ADDSRCARCH | OPTDIR_SUPPORT_DYNAMIC_UPDATE);
  540. #if defined(_WIN64)
  541. lstrcpy( TempString, TEXT("..\\I386\\"));
  542. ConcatenatePaths(TempString, DirectoryName, MAX_PATH);
  543. //Also check if an I386 equivalent WOW directory exists
  544. AddCopydirIfExists( TempString, OPTDIR_TEMPONLY | OPTDIR_PLATFORM_INDEP );
  545. #endif
  546. }
  547. //
  548. // and Fusion side by side assemblies, driven by syssetup.inf, if the directories exists
  549. DebugLog (Winnt32LogDetailedInformation, TEXT("Adding AssemblyDirectories to optional dirs."), 0);
  550. //
  551. {
  552. TCHAR SideBySideInstallShareDirectory[MAX_PATH]; // source
  553. DWORD FileAttributes = 0;
  554. PCTSTR DirectoryName = NULL;
  555. u = 0;
  556. while (DirectoryName = InfGetFieldByIndex(MainInf, SXS_INF_ASSEMBLY_DIRECTORIES_SECTION_NAME, u++, 0)) {
  557. //
  558. // convention introduced specifically for side by side, so that
  559. // x86 files on amd64/ia64 might come from \i386\asms instead of \ia64\asms\i386,
  560. // depending on what dosnet.inf and syssetup.inf say:
  561. // a path that does not start with a slash is appended to \$win_nt$.~ls\processor
  562. // and \installShare\processor
  563. // (or cdromDriveLetter:\processor)
  564. // a path that does start with a slash is appended to \$win_nt$.~ls
  565. // and \installShare
  566. // (or cdromDriveLetter:\)
  567. DWORD FileAttributes;
  568. BOOL StartsWithSlash = (DirectoryName[0] == '\\' || DirectoryName[0] == '/');
  569. lstrcpyn(SideBySideInstallShareDirectory, SourcePaths[0], MAX_PATH);
  570. if (StartsWithSlash) {
  571. DirectoryName += 1; // skip slash
  572. } else {
  573. ConcatenatePaths(SideBySideInstallShareDirectory, InfGetFieldByKey(MainInf, TEXT("Miscellaneous"), TEXT("DestinationPlatform"),0), MAX_PATH);
  574. }
  575. ConcatenatePaths(SideBySideInstallShareDirectory, DirectoryName, MAX_PATH );
  576. //
  577. // The asms directory is optional because there might just be asms*.cab.
  578. //
  579. FileAttributes = GetFileAttributes(SideBySideInstallShareDirectory);
  580. if (FileAttributes != INVALID_FILE_ATTRIBUTES
  581. && (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  582. {
  583. RememberOptionalDir(DirectoryName, OPTDIR_SIDE_BY_SIDE | OPTDIR_TEMPONLY | (StartsWithSlash ? OPTDIR_PLATFORM_INDEP : OPTDIR_ADDSRCARCH));
  584. }
  585. }
  586. }
  587. thread = 0;
  588. if(MakeLocalSource && OptionalDirectoryCount) {
  589. //
  590. // Start optional directory threads going.
  591. // There will thus be as many threads as there are
  592. // optional source dirs.
  593. //
  594. DebugLog (Winnt32LogDetailedInformation, TEXT("Starting optional directory thread going..."), 0);
  595. ZeroMemory(BuildParams,sizeof(BuildParams));
  596. source = 0;
  597. for(u=0; u<OptionalDirectoryCount; u++) {
  598. PTSTR s,t;
  599. BOOL DoSource = FALSE;
  600. lstrcpy(BuildParams[u].SourceRoot,SourcePaths[source]);
  601. //
  602. // support ".." syntax
  603. //
  604. t = s = OptionalDirectories[u];
  605. while (s = _tcsstr(s,TEXT("..\\"))) {
  606. DoSource = TRUE;
  607. p = _tcsrchr(BuildParams[u].SourceRoot,TEXT('\\'));
  608. if (p) {
  609. //
  610. // note that if we could end up with a source root with no
  611. // '\' char in it, but this is not a problem since the
  612. // subroutines which use the source root handle the lack
  613. // of '\' correctly
  614. //
  615. *p = 0;
  616. }
  617. t = s += 3;
  618. }
  619. if (OptionalDirectoryFlags[u] & OPTDIR_ADDSRCARCH) {
  620. PCTSTR DirectoryRoot;
  621. DirectoryRoot = InfGetFieldByKey(MainInf, TEXT("Miscellaneous"), TEXT("DestinationPlatform"),0);
  622. lstrcpyn(SourceDirectory,DirectoryRoot,MAX_PATH);
  623. ConcatenatePaths( SourceDirectory, t, MAX_PATH );
  624. } else {
  625. lstrcpyn(SourceDirectory,t,MAX_PATH);
  626. }
  627. if (DoSource) {
  628. BuildParams[u].OptionalDirFlags = OPTDIR_ABSOLUTE;
  629. lstrcpyn(BuildParams[u].CurrentDirectory,BuildParams[u].SourceRoot,MAX_PATH);
  630. ConcatenatePaths(BuildParams[u].CurrentDirectory, SourceDirectory ,MAX_PATH);
  631. } else {
  632. lstrcpyn(BuildParams[u].CurrentDirectory,SourceDirectory,MAX_PATH);
  633. }
  634. if (OptionalDirectoryFlags[u] & OPTDIR_DEBUGGER) {
  635. lstrcpyn(BuildParams[u].DestinationDirectory,TEXT("Debuggers"),MAX_PATH);
  636. }
  637. else if (!(OptionalDirectoryFlags[u] & OPTDIR_OVERLAY)) {
  638. if (OptionalDirectoryFlags[u] & OPTDIR_PLATFORM_SPECIFIC_FIRST) {
  639. PCTSTR arch = InfGetFieldByKey(MainInf, TEXT("Miscellaneous"), TEXT("DestinationPlatform"), 0);
  640. if (arch) {
  641. lstrcpyn (buffer, BuildParams[u].SourceRoot, MAX_PATH);
  642. ConcatenatePaths (buffer, arch, MAX_PATH);
  643. ConcatenatePaths (buffer, SourceDirectory, MAX_PATH);
  644. if (FileExists (buffer, &fd) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  645. //
  646. // use this platform-specific source instead
  647. //
  648. lstrcpyn (BuildParams[u].CurrentDirectory, arch, MAX_PATH);
  649. ConcatenatePaths (BuildParams[u].CurrentDirectory, SourceDirectory, MAX_PATH);
  650. }
  651. }
  652. }
  653. if (OptionalDirectoryFlags[u] & OPTDIR_USE_TAIL_FOLDER_NAME) {
  654. //
  655. // move this directory in a subdirectory directly under target %windir%
  656. //
  657. p = _tcsrchr (t, TEXT('\\'));
  658. if (p) {
  659. p++;
  660. } else {
  661. p = t;
  662. }
  663. } else {
  664. p = t;
  665. }
  666. lstrcpyn(BuildParams[u].DestinationDirectory,p,MAX_PATH);
  667. }
  668. BuildParams[u].OptionalDirFlags |= OptionalDirectoryFlags[u];
  669. source = (source+1) % SourceCount;
  670. BuildThreads[thread] = CreateThread(
  671. NULL,
  672. 0,
  673. BuildCopyListForOptionalDirThread,
  674. &BuildParams[u],
  675. 0,
  676. &ThreadId
  677. );
  678. if(BuildThreads[thread]) {
  679. thread++;
  680. } else {
  681. d = GetLastError();
  682. DebugLog (Winnt32LogError, TEXT("ERROR: Problem with creating thread for optional directory."), 0);
  683. goto c0;
  684. }
  685. }
  686. }
  687. //
  688. // Add the directories listed in the inf to the main copy list.
  689. // Also add a dummy directory that we use for simple file list sections
  690. // that have no directory specifier in the inf.
  691. //
  692. DebugLog (Winnt32LogDetailedInformation, TEXT("Adding miscellaneous..."), 0);
  693. DummyDirectoryName = InfGetFieldByKey(MainInf, TEXT("Miscellaneous"), TEXT("DestinationPlatform"), 0);
  694. if (!DummyDirectoryName) {
  695. DummyDirectoryName = TEXT("\\");
  696. }
  697. DirectoryStruct = AddDirectory(
  698. DUMMY_DIRID,
  699. &MasterCopyList,
  700. DummyDirectoryName,
  701. NULL,
  702. DIR_SUPPORT_DYNAMIC_UPDATE
  703. );
  704. if(!DirectoryStruct) {
  705. d = ERROR_NOT_ENOUGH_MEMORY;
  706. DebugLog (Winnt32LogError, TEXT("ERROR: Could not add miscellaneous"), 0);
  707. goto c1;
  708. }
  709. u = 0;
  710. while((Id = InfGetLineKeyName(MainInf,szDirectories,u))
  711. && (DirectoryName = InfGetFieldByKey(MainInf,szDirectories,Id,0))) {
  712. DirectoryStruct = AddDirectory(
  713. Id,
  714. &MasterCopyList,
  715. DirectoryName,
  716. NULL,
  717. DIR_SUPPORT_DYNAMIC_UPDATE
  718. );
  719. if(!DirectoryStruct) {
  720. d = ERROR_NOT_ENOUGH_MEMORY;
  721. DebugLog (Winnt32LogError, TEXT("ERROR: Could not add directory %1"), 0, DirectoryName);
  722. goto c1;
  723. }
  724. u++;
  725. }
  726. //
  727. // Add files in the [Files] section.
  728. //
  729. DebugLog (Winnt32LogDetailedInformation, TEXT("Adding files from [Files] section..."), 0);
  730. if(MakeLocalSource) {
  731. d = AddSection(
  732. MainInf,
  733. &MasterCopyList,
  734. szFiles,
  735. &ErrorLine,
  736. FILE_PRESERVE_COMPRESSED_NAME | FILE_IN_PLATFORM_INDEPEND_DIR,
  737. FALSE,
  738. TRUE
  739. );
  740. if(d != NO_ERROR) {
  741. DebugLog (Winnt32LogError, TEXT("ERROR: Could not add files!"), 0);
  742. goto c1;
  743. }
  744. }
  745. #if defined(REMOTE_BOOT)
  746. if(RemoteBoot) {
  747. //
  748. // Remote boot client upgrade. Add the two special sections
  749. // RootRemoteBootFiles (ntldr and ntdetect.com in c:\) and
  750. // MachineRootRemoteBootFiles (setupldr.exe and startrom.com in
  751. // \\server\imirror\clients\client).
  752. //
  753. d = AddSection(
  754. MainInf,
  755. &MasterCopyList,
  756. TEXT("RootRemoteBootFiles"),
  757. &ErrorLine,
  758. FILE_ON_SYSTEM_PARTITION_ROOT | FILE_PRESERVE_COMPRESSED_NAME,
  759. TRUE,
  760. FALSE
  761. );
  762. d = AddSection(
  763. MainInf,
  764. &MasterCopyList,
  765. TEXT("MachineRootRemoteBootFiles"),
  766. &ErrorLine,
  767. FILE_ON_MACHINE_DIRECTORY_ROOT | FILE_PRESERVE_COMPRESSED_NAME,
  768. TRUE,
  769. FALSE
  770. );
  771. } else
  772. #endif // defined(REMOTE_BOOT)
  773. {
  774. if (!IsArc()) {
  775. #if defined(_AMD64_) || defined(_X86_)
  776. //
  777. // In the floppyless case add each of [FloppyFiles.0], [FloppyFiles.1],
  778. // [FloppyFiles.2], and [RootBootFiles].
  779. //
  780. if(MakeBootMedia && Floppyless) {
  781. for ( u=0;u<FLOPPY_COUNT;u++ ){
  782. if (FAILED (StringCchPrintf (floppynum, ARRAYSIZE(floppynum), TEXT("FloppyFiles.%u"), u))) {
  783. MYASSERT (FALSE);
  784. d = ERROR_INSUFFICIENT_BUFFER;
  785. break;
  786. }
  787. d = AddSection(
  788. MainInf,
  789. &MasterCopyList,
  790. floppynum,
  791. &ErrorLine,
  792. FILE_IN_LOCAL_BOOT | FILE_PRESERVE_COMPRESSED_NAME,
  793. FALSE,
  794. FALSE
  795. );
  796. if( d != NO_ERROR )
  797. {
  798. DebugLog (Winnt32LogError, TEXT("ERROR: Adding section %1, entry = %2!u!"), 0, floppynum, d);
  799. break;
  800. }
  801. }// for
  802. if(d == NO_ERROR) {
  803. d = AddSection(
  804. MainInf,
  805. &MasterCopyList,
  806. TEXT("RootBootFiles"),
  807. &ErrorLine,
  808. FILE_ON_SYSTEM_PARTITION_ROOT | FILE_PRESERVE_COMPRESSED_NAME,
  809. FALSE,
  810. FALSE
  811. );
  812. DebugLog (Winnt32LogDetailedInformation, TEXT("Added RootBootFiles, return = %2!u!"), 0, d);
  813. if (d == NO_ERROR && BuildCmdcons) {
  814. d = AddSection(
  815. MainInf,
  816. &MasterCopyList,
  817. TEXT("CmdConsFiles"),
  818. &ErrorLine,
  819. FILE_IN_LOCAL_BOOT | FILE_PRESERVE_COMPRESSED_NAME,
  820. TRUE,
  821. FALSE
  822. );
  823. DebugLog (Winnt32LogDetailedInformation, TEXT("Added CmdConsFiles, return = %2!u!"), 0, d);
  824. }
  825. }
  826. }
  827. if((d == NO_ERROR) && OemPreinstall && MakeBootMedia) {
  828. //
  829. // Add a special directory entry for oem boot files.
  830. // The oem boot files come from $OEM$\TEXTMODE on the source
  831. // and go to localboot\$OEM$ on the target.
  832. //
  833. //
  834. // It's possible that the user has given us a network share for
  835. // the $OEM$ directory in the unattend file. If so, we need to
  836. // use that as the source instead of WINNT_OEM_TEXTMODE_DIR.
  837. //
  838. if( UserSpecifiedOEMShare ) {
  839. lstrcpy( buffer, UserSpecifiedOEMShare );
  840. ConcatenatePaths(buffer, TEXT("TEXTMODE"),MAX_PATH);
  841. DirectoryStruct = AddDirectory(
  842. NULL,
  843. &MasterCopyList,
  844. buffer,
  845. WINNT_OEM_DIR,
  846. DIR_NEED_TO_FREE_SOURCENAME | DIR_ABSOLUTE_PATH | DIR_USE_SUBDIR
  847. );
  848. } else {
  849. PCTSTR arch;
  850. buffer[0] = 0;
  851. arch = InfGetFieldByKey(MainInf, TEXT("Miscellaneous"), TEXT("DestinationPlatform"), 0);
  852. if (arch) {
  853. lstrcpy (buffer, arch);
  854. }
  855. ConcatenatePaths (buffer, WINNT_OEM_TEXTMODE_DIR, MAX_PATH);
  856. DirectoryStruct = AddDirectory(
  857. NULL,
  858. &MasterCopyList,
  859. buffer,
  860. WINNT_OEM_DIR,
  861. DIR_NEED_TO_FREE_SOURCENAME | DIR_USE_SUBDIR
  862. );
  863. }
  864. if(DirectoryStruct) {
  865. POEM_BOOT_FILE p;
  866. for(p=OemBootFiles; (d==NO_ERROR) && p; p=p->Next) {
  867. //
  868. // we're not fetching the file size, so in the oem preinstall case
  869. // when there are oem boot files, the size check is not accurate.
  870. //
  871. if(!AddFile(&MasterCopyList,p->Filename,NULL,DirectoryStruct,FILE_IN_LOCAL_BOOT,0)) {
  872. d = ERROR_NOT_ENOUGH_MEMORY;
  873. break;
  874. }
  875. }
  876. } else {
  877. d = ERROR_NOT_ENOUGH_MEMORY;
  878. }
  879. }
  880. #endif // defined(_AMD64_) || defined(_X86_)
  881. } else {
  882. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  883. //
  884. // ARC case. Add setupldr.
  885. //
  886. FileStruct = AddFile(
  887. &MasterCopyList,
  888. SETUPLDR_FILENAME,
  889. NULL,
  890. LookUpDirectory(&MasterCopyList,DUMMY_DIRID),
  891. FILE_ON_SYSTEM_PARTITION_ROOT,
  892. 0
  893. );
  894. d = FileStruct ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY;
  895. #endif // UNICODE
  896. } // if (!IsArc())
  897. }
  898. if(d != NO_ERROR) {
  899. goto c1;
  900. }
  901. if (AsrQuickTest) {
  902. //
  903. // Add asr.sif
  904. //
  905. FileStruct = AddFile(
  906. &MasterCopyList,
  907. TEXT("asr.sif"),
  908. NULL,
  909. DirectoryStruct,
  910. FILE_IN_LOCAL_BOOT,
  911. 0
  912. );
  913. d = FileStruct ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY;
  914. if(d != NO_ERROR) {
  915. DebugLog (Winnt32LogError, TEXT("ERROR: AsrQuitTest - could not add asr.sif!"), 0);
  916. goto c1;
  917. }
  918. }
  919. //
  920. // If there were any threads created to build the file lists for
  921. // optional directories, wait for them to terminate now.
  922. // If they were all successful then add the lists they created
  923. // to the master list.
  924. //
  925. if(thread) {
  926. WaitForMultipleObjects(thread,BuildThreads,TRUE,INFINITE);
  927. TempError = NO_ERROR;
  928. for(u=0; u<thread; u++) {
  929. if(!GetExitCodeThread(BuildThreads[u],&TempError)) {
  930. TempError = GetLastError();
  931. }
  932. //
  933. // Preserve first error.
  934. //
  935. if((TempError != NO_ERROR) && (d == NO_ERROR)) {
  936. d = TempError;
  937. }
  938. if (d != NO_ERROR) {
  939. break;
  940. }
  941. CloseHandle(BuildThreads[u]);
  942. BuildThreads[u] = NULL;
  943. //
  944. // Merge the copy list into the master copy list.
  945. // When we've done that, clean out the per-thread copy list
  946. // structure to avoid problems later if we have a failure and
  947. // have to clean up.
  948. //
  949. MasterCopyList.FileCount += BuildParams[u].CopyList.FileCount;
  950. MasterCopyList.DirectoryCount += BuildParams[u].CopyList.DirectoryCount;
  951. if(MasterCopyList.Directories) {
  952. #ifndef SLOWER_WAY
  953. if (BuildParams[u].CopyList.Directories) {
  954. PVOID p;
  955. p = BuildParams[u].CopyList.Directories->Prev;
  956. BuildParams[u].CopyList.Directories->Prev = MasterCopyList.Directories->Prev;
  957. MasterCopyList.Directories->Prev->Next = BuildParams[u].CopyList.Directories;
  958. MasterCopyList.Directories->Prev = p;
  959. }
  960. #else
  961. for(DirectoryStruct=MasterCopyList.Directories;
  962. DirectoryStruct->Next;
  963. DirectoryStruct=DirectoryStruct->Next) {
  964. ;
  965. }
  966. DirectoryStruct->Next = BuildParams[u].CopyList.Directories;
  967. #endif
  968. } else {
  969. MasterCopyList.Directories = BuildParams[u].CopyList.Directories;
  970. }
  971. if(MasterCopyList.Files) {
  972. #ifndef SLOWER_WAY
  973. if (BuildParams[u].CopyList.Files) {
  974. PVOID p;
  975. p = BuildParams[u].CopyList.Files->Prev;
  976. BuildParams[u].CopyList.Files->Prev = MasterCopyList.Files->Prev;
  977. MasterCopyList.Files->Prev->Next = BuildParams[u].CopyList.Files;
  978. MasterCopyList.Files->Prev = p ;
  979. }
  980. #else
  981. for(FileStruct=MasterCopyList.Files;
  982. FileStruct->Next;
  983. FileStruct=FileStruct->Next) {
  984. ;
  985. }
  986. FileStruct->Next = BuildParams[u].CopyList.Files;
  987. #endif
  988. } else {
  989. MasterCopyList.Files = BuildParams[u].CopyList.Files;
  990. }
  991. ZeroMemory(&BuildParams[u].CopyList,sizeof(COPY_LIST));
  992. }
  993. if(d != NO_ERROR) {
  994. goto c1;
  995. }
  996. }
  997. //
  998. // Success.
  999. //
  1000. return(TRUE);
  1001. c1:
  1002. //
  1003. // Clean up the copy list.
  1004. //
  1005. TearDownCopyList(&MasterCopyList);
  1006. c0:
  1007. //
  1008. // Close thread handles and free per-thread copy lists that may still
  1009. // be unmerged into the master list.
  1010. //
  1011. for(u=0; u<thread; u++) {
  1012. if(BuildThreads[u]) {
  1013. WaitForSingleObject(BuildThreads[u], INFINITE);
  1014. CloseHandle(BuildThreads[u]);
  1015. }
  1016. TearDownCopyList(&BuildParams[u].CopyList);
  1017. }
  1018. //
  1019. // Tell the user what went wrong.
  1020. //
  1021. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  1022. MessageBoxFromMessageAndSystemError(
  1023. hdlg,
  1024. MSG_CANT_BUILD_SOURCE_LIST,
  1025. d,
  1026. AppTitleStringId,
  1027. MB_OK | MB_ICONWARNING
  1028. );
  1029. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  1030. return(FALSE);
  1031. }
  1032. DWORD
  1033. BuildCopyListForOptionalDirThread(
  1034. IN PVOID ThreadParam
  1035. )
  1036. {
  1037. //
  1038. // Just call the recursive worker routine.
  1039. //
  1040. return(AddFilesInDirToCopyList(ThreadParam));
  1041. }
  1042. DWORD
  1043. AddFilesInDirToCopyList(
  1044. IN OUT PBUILD_LIST_THREAD_PARAMS Params
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Recursively adds directories and their contents to the copy list.
  1049. The function takes care to overlay OEM-specified files so that they
  1050. are copied to proper location in the local source.
  1051. Arguments:
  1052. Params - pointer to BUILD_LIST_THREAD_PARAMS structure indicating
  1053. the files to be copied.
  1054. Return Value:
  1055. Win32 error code indicating outcome.
  1056. --*/
  1057. {
  1058. HANDLE FindHandle;
  1059. LPTSTR pchSrcLim;
  1060. LPTSTR pchDstLim;
  1061. DWORD d;
  1062. PDIR DirectoryDescriptor;
  1063. PFIL FileDescriptor;
  1064. UINT Flags;
  1065. LPTSTR PatternMatch;
  1066. TCHAR *DestinationDirectory;
  1067. TCHAR tmp[MAX_PATH];
  1068. Flags = DIR_NEED_TO_FREE_SOURCENAME;
  1069. if (Params->OptionalDirFlags & OPTDIR_PLATFORM_INDEP) {
  1070. Flags |= DIR_IS_PLATFORM_INDEPEND;
  1071. }
  1072. if (Params->OptionalDirFlags & OPTDIR_IN_LOCAL_BOOT) {
  1073. Flags |= DIR_USE_SUBDIR;
  1074. }
  1075. if (Params->OptionalDirFlags & OPTDIR_SUPPORT_DYNAMIC_UPDATE) {
  1076. Flags |= DIR_SUPPORT_DYNAMIC_UPDATE;
  1077. }
  1078. if (Params->OptionalDirFlags & OPTDIR_DOESNT_SUPPORT_PRIVATES) {
  1079. Flags |= DIR_DOESNT_SUPPORT_PRIVATES;
  1080. }
  1081. //
  1082. // Add the directory to the directory list.
  1083. // Note that the directory is added in a form relative to the
  1084. // source root.
  1085. //
  1086. //
  1087. // Check for a floating $OEM$ directory
  1088. //
  1089. if( (DestinationDirectory=_tcsstr( Params->CurrentDirectory, WINNT_OEM_DIR )) &&
  1090. UserSpecifiedOEMShare ) {
  1091. //
  1092. // We need to manually specify the Target directory
  1093. // name because it's not the same as the source. We
  1094. // want the destination directory to look exactly like
  1095. // the source from "$OEM$" down.
  1096. //
  1097. DirectoryDescriptor = AddDirectory(
  1098. NULL,
  1099. &Params->CopyList,
  1100. Params->CurrentDirectory,
  1101. DupString( DestinationDirectory ),
  1102. Flags | DIR_ABSOLUTE_PATH
  1103. );
  1104. } else if( Params->OptionalDirFlags & (OPTDIR_OVERLAY) ) {
  1105. DirectoryDescriptor = AddDirectory(
  1106. NULL,
  1107. &Params->CopyList,
  1108. TEXT("\\"),
  1109. NULL,
  1110. Flags | DIR_ABSOLUTE_PATH
  1111. );
  1112. } else {
  1113. DirectoryDescriptor = AddDirectory(
  1114. NULL,
  1115. &Params->CopyList,
  1116. Params->CurrentDirectory,
  1117. DupString( Params->DestinationDirectory ),
  1118. ((Params->OptionalDirFlags & OPTDIR_ABSOLUTE)? DIR_ABSOLUTE_PATH : 0)
  1119. | Flags
  1120. );
  1121. }
  1122. if(!DirectoryDescriptor) {
  1123. return(ERROR_NOT_ENOUGH_MEMORY);
  1124. }
  1125. //
  1126. // Windows 95 has a bug in some IDE CD-ROM drivers that causes FindFirstFile to fail
  1127. // if used with a pattern of "*". It needs to use "*.*" instead. Appease its brokenness.
  1128. //
  1129. if (!ISNT()) {
  1130. PatternMatch = TEXT("*.*");
  1131. }
  1132. else {
  1133. PatternMatch = TEXT("*");
  1134. }
  1135. //
  1136. // Form the search spec. We overload the SourceRoot member of
  1137. // the parameters structure for this to avoid a stack-sucking
  1138. // large local variable.
  1139. //
  1140. //
  1141. // Go look at the absolute path given in CurrentDirectory if we're
  1142. // processing a floating $OEM$ directory.
  1143. //
  1144. if (AlternateSourcePath[0]) {
  1145. _tcscpy( tmp, AlternateSourcePath );
  1146. pchSrcLim = tmp + lstrlen(tmp);
  1147. ConcatenatePaths( tmp, Params->CurrentDirectory, MAX_PATH );
  1148. ConcatenatePaths( tmp, PatternMatch, MAX_PATH );
  1149. FindHandle = FindFirstFile( tmp, &Params->FindData );
  1150. if (FindHandle != INVALID_HANDLE_VALUE) {
  1151. *pchSrcLim = 0;
  1152. _tcscpy( Params->SourceRoot, tmp );
  1153. }
  1154. } else {
  1155. FindHandle = INVALID_HANDLE_VALUE;
  1156. }
  1157. if (FindHandle == INVALID_HANDLE_VALUE) {
  1158. if( DirectoryDescriptor->Flags & DIR_ABSOLUTE_PATH ) {
  1159. pchSrcLim = Params->CurrentDirectory + lstrlen(Params->CurrentDirectory);
  1160. ConcatenatePaths(Params->CurrentDirectory,PatternMatch,MAX_PATH);
  1161. FindHandle = FindFirstFile(Params->CurrentDirectory,&Params->FindData);
  1162. } else {
  1163. pchSrcLim = Params->SourceRoot + lstrlen(Params->SourceRoot);
  1164. ConcatenatePaths(Params->SourceRoot,Params->CurrentDirectory,MAX_PATH);
  1165. ConcatenatePaths(Params->SourceRoot,PatternMatch,MAX_PATH);
  1166. FindHandle = FindFirstFile(Params->SourceRoot,&Params->FindData);
  1167. }
  1168. *pchSrcLim = 0;
  1169. }
  1170. if(!FindHandle || (FindHandle == INVALID_HANDLE_VALUE)) {
  1171. //
  1172. // We might be failing on the $OEM$ directory. He's optional
  1173. // so let's not fail for him.
  1174. //
  1175. if (Params->OptionalDirFlags & (OPTDIR_OEMSYS)
  1176. && !UserSpecifiedOEMShare) {
  1177. return(NO_ERROR);
  1178. }
  1179. else {
  1180. DebugLog (
  1181. Winnt32LogError,
  1182. TEXT("Unable to copy dir %1"),
  1183. 0,
  1184. Params->CurrentDirectory
  1185. );
  1186. return(GetLastError());
  1187. }
  1188. }
  1189. pchSrcLim = Params->CurrentDirectory + lstrlen(Params->CurrentDirectory);
  1190. pchDstLim = Params->DestinationDirectory + lstrlen(Params->DestinationDirectory);
  1191. Flags = FILE_NEED_TO_FREE_SOURCENAME;
  1192. if( !(Params->OptionalDirFlags & (OPTDIR_OVERLAY)) &&
  1193. (!(Params->OptionalDirFlags & OPTDIR_TEMPONLY) ||
  1194. (Params->OptionalDirFlags & (OPTDIR_OEMSYS))) ) {
  1195. Flags |= FILE_IN_PLATFORM_INDEPEND_DIR;
  1196. }
  1197. if (Params->OptionalDirFlags & OPTDIR_PLATFORM_INDEP) {
  1198. Flags |= FILE_IN_PLATFORM_INDEPEND_DIR;
  1199. }
  1200. if (Params->OptionalDirFlags & OPTDIR_IN_LOCAL_BOOT) {
  1201. Flags |= FILE_IN_LOCAL_BOOT;
  1202. }
  1203. d = NO_ERROR;
  1204. do {
  1205. if(Params->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1206. //
  1207. // Directory. Ignore . and .. entries.
  1208. //
  1209. if( lstrcmp(Params->FindData.cFileName,TEXT(".")) &&
  1210. lstrcmp(Params->FindData.cFileName,TEXT("..")) &&
  1211. !(Params->OptionalDirFlags & (OPTDIR_OVERLAY)) ) {
  1212. //
  1213. // Restore the current directory name and then form
  1214. // the name of the subdirectory and recurse into it.
  1215. //
  1216. *pchSrcLim = 0;
  1217. ConcatenatePaths(Params->CurrentDirectory,Params->FindData.cFileName,MAX_PATH);
  1218. *pchDstLim = 0;
  1219. ConcatenatePaths(Params->DestinationDirectory,Params->FindData.cFileName,MAX_PATH);
  1220. d = AddFilesInDirToCopyList(Params);
  1221. }
  1222. } else {
  1223. FileDescriptor = AddFile(
  1224. &Params->CopyList,
  1225. Params->FindData.cFileName,
  1226. NULL,
  1227. DirectoryDescriptor,
  1228. Flags,
  1229. MAKEULONGLONG(Params->FindData.nFileSizeLow,Params->FindData.nFileSizeHigh)
  1230. );
  1231. if(!FileDescriptor) {
  1232. d = ERROR_NOT_ENOUGH_MEMORY;
  1233. }
  1234. }
  1235. } while((d == NO_ERROR) && FindNextFile(FindHandle,&Params->FindData));
  1236. //
  1237. // Check loop termination condition. If d is NO_ERROR, then FindNextFile
  1238. // failed. We want to make sure it failed because it ran out of files
  1239. // and not for some other reason. If we don't check this, the list of
  1240. // files in the directory could wind up truncated without any indication
  1241. // that something went wrong.
  1242. //
  1243. if(d == NO_ERROR) {
  1244. d = GetLastError();
  1245. if(d == ERROR_NO_MORE_FILES) {
  1246. d = NO_ERROR;
  1247. }
  1248. }
  1249. FindClose(FindHandle);
  1250. return(d);
  1251. }
  1252. PVOID
  1253. PopulateDriverCacheStringTable(
  1254. VOID
  1255. )
  1256. /*
  1257. This function populates a string table (hashing table) with the files listed in the
  1258. driver cab (drvindex.inf). It assosciates a Boolean ExtraData with each element of
  1259. value TRUE. Once done with that it goest through the [ForceCopyDriverCabFiles]
  1260. section in dosnet.inf and marks those files as FALSE in the string table. Hence we now
  1261. have a hash table that has TRUE marked for all files that don't need to be copied.
  1262. The function FileToBeCopied can be used to query the string table. The caller is responsible
  1263. for destroying the string table.
  1264. Return values:
  1265. Pointer to string table.
  1266. */
  1267. {
  1268. #define MAX_SECTION_NAME 256
  1269. TCHAR DriverInfName[MAX_PATH], Section[MAX_SECTION_NAME], FileName[MAX_PATH];
  1270. HINF InfHandle, DosnetInfHandle;
  1271. DWORD i, Count = 0;
  1272. PVOID StringTable = NULL;
  1273. INFCONTEXT InfContext;
  1274. INFCONTEXT LineContext;
  1275. BOOL Err = FALSE, Present = TRUE, Absent = FALSE;
  1276. LONG Hash = 0;
  1277. InfHandle = NULL;
  1278. DosnetInfHandle = NULL;
  1279. FindPathToInstallationFile( DRVINDEX_INF, DriverInfName, MAX_PATH );
  1280. InfHandle = SetupapiOpenInfFile( DriverInfName, NULL, INF_STYLE_WIN4, NULL );
  1281. if (!InfHandle) {
  1282. DebugLog (Winnt32LogError, TEXT("Unable to open INF file %1"), 0, DriverInfName);
  1283. Err = TRUE;
  1284. return(NULL);
  1285. }
  1286. if( (StringTable = pSetupStringTableInitializeEx(sizeof(BOOL), 0)) == NULL ){
  1287. DebugLog (Winnt32LogError, TEXT("Unable to create string table for %1"), 0, DriverInfName);
  1288. Err = TRUE;
  1289. goto cleanup;
  1290. }
  1291. // Populate the string table
  1292. //
  1293. // Now get the section names that we have to search.
  1294. //
  1295. if( SetupapiFindFirstLine( InfHandle, TEXT("Version"), TEXT("CabFiles"), &InfContext)){
  1296. Count = SetupapiGetFieldCount( &InfContext );
  1297. for( i=1; i<=Count; i++ ){
  1298. if(SetupapiGetStringField( &InfContext, i, Section, MAX_SECTION_NAME, 0)){
  1299. if( SetupapiFindFirstLine( InfHandle, Section, NULL, &LineContext )){
  1300. do{
  1301. if( SetupapiGetStringField( &LineContext, 0, FileName, MAX_PATH, 0)){
  1302. if( (-1 == pSetupStringTableAddStringEx( StringTable, FileName, (STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE), &Present, sizeof(BOOL)))){
  1303. DebugLog (Winnt32LogError, TEXT("Out of memory adding string %1 to DriverCache INF string table"), 0, FileName);
  1304. Err = TRUE;
  1305. goto cleanup;
  1306. }
  1307. }
  1308. }while( SetupapiFindNextLine( &LineContext, &LineContext ));
  1309. }
  1310. }else{
  1311. DebugLog (Winnt32LogError, TEXT("Unable to get section name in INF %1"), 0, DriverInfName);
  1312. Err = TRUE;
  1313. goto cleanup;
  1314. }
  1315. }
  1316. }
  1317. // Remove entries pertaining to [ForceCopyDriverCabFiles]
  1318. DosnetInfHandle = SetupapiOpenInfFile( FullInfName, NULL, INF_STYLE_WIN4, NULL );
  1319. if (!DosnetInfHandle) {
  1320. DebugLog (Winnt32LogError, TEXT("Unable to open INF file %1"), 0, FullInfName);
  1321. Err = TRUE;
  1322. goto cleanup;
  1323. }
  1324. if( SetupapiFindFirstLine( DosnetInfHandle, TEXT("ForceCopyDriverCabFiles"), NULL, &LineContext )){
  1325. do{
  1326. if( SetupapiGetStringField( &LineContext, 0, FileName, MAX_PATH, 0)){
  1327. Hash = pSetupStringTableLookUpString( StringTable, FileName, STRTAB_CASE_INSENSITIVE);
  1328. if (-1 != Hash ) {
  1329. pSetupStringTableSetExtraData( StringTable, Hash, &Absent, sizeof(BOOL));
  1330. }
  1331. }
  1332. }while( SetupapiFindNextLine( &LineContext, &LineContext ));
  1333. }
  1334. cleanup:
  1335. if( InfHandle != INVALID_HANDLE_VALUE){
  1336. SetupapiCloseInfFile( InfHandle );
  1337. }
  1338. if( DosnetInfHandle != INVALID_HANDLE_VALUE){
  1339. SetupapiCloseInfFile( DosnetInfHandle );
  1340. }
  1341. if( Err ){
  1342. if(StringTable)
  1343. pSetupStringTableDestroy( StringTable );
  1344. StringTable = NULL;
  1345. }
  1346. return( StringTable );
  1347. }
  1348. BOOL
  1349. FileToBeCopied(
  1350. IN PVOID StringTable,
  1351. IN PTSTR FileName
  1352. )
  1353. /*
  1354. Function to check presence of a driver cab file in the string table.
  1355. Arguments:
  1356. StringTable - Pointer to initialized stringtable
  1357. FileName - Name of file to look for
  1358. Return value;
  1359. TRUE - If the file is in the driver cab and not one of the files that are listed in
  1360. [ForceCopyDriverCabFiles]
  1361. else it returns FALSE.
  1362. */
  1363. {
  1364. BOOL Present = FALSE;
  1365. if( (-1 != pSetupStringTableLookUpStringEx( StringTable, FileName, STRTAB_CASE_INSENSITIVE, &Present, sizeof(BOOL)))){
  1366. if( Present == TRUE ){
  1367. return( TRUE );
  1368. }
  1369. }
  1370. //
  1371. // If we get here, we didn't find a match.
  1372. //
  1373. return( FALSE );
  1374. }
  1375. DWORD
  1376. AddSection(
  1377. IN PVOID Inf,
  1378. IN OUT PCOPY_LIST CopyList,
  1379. IN LPCTSTR SectionName,
  1380. OUT UINT *ErrorLine,
  1381. IN UINT FileFlags,
  1382. IN BOOL SimpleList,
  1383. IN BOOL DoDriverCabPruning
  1384. )
  1385. {
  1386. LPCTSTR DirSymbol, TargetName;
  1387. LPTSTR SourceName;
  1388. unsigned Count;
  1389. BOOL b;
  1390. PDIR Directory;
  1391. PVOID p;
  1392. DWORD Err = NO_ERROR;
  1393. PVOID DriverCacheStringTable = NULL;
  1394. Count = 0;
  1395. *ErrorLine = (UINT)(-1);
  1396. // Open up drvindex.inf if we have to do driver cab pruning
  1397. if( DoDriverCabPruning){
  1398. //Initialize sptils
  1399. if(pSetupInitializeUtils()) {
  1400. //POpulate our Driver Cab list string table for fast lookup later
  1401. if( (DriverCacheStringTable = PopulateDriverCacheStringTable( )) == NULL){
  1402. return(ERROR_NOT_ENOUGH_MEMORY);
  1403. }
  1404. }else
  1405. return(ERROR_NOT_ENOUGH_MEMORY);
  1406. }
  1407. if(SimpleList) {
  1408. while((LPCTSTR)SourceName = InfGetFieldByIndex(Inf,SectionName,Count,0)) {
  1409. if( Cancelled == TRUE ) {
  1410. //
  1411. // The user is trying to exit, and the clean up code
  1412. // is waiting for us to finish. Break out.
  1413. //
  1414. break;
  1415. }
  1416. // If the file is present in drvindex.inf and not in the
  1417. // [ForceCopyDriverCabFiles] section then don't add it to the copylist
  1418. //
  1419. // This is the section in dosnet.inf that we cross check against when making the filelists.
  1420. // Files in this section are in the driver cab and also should reside in the local source
  1421. // The idea here is that these files are once that are not in the FloppyFiles.x sections and yet
  1422. // need to remain outside the driver cab.
  1423. //
  1424. if( DoDriverCabPruning){
  1425. if (FileToBeCopied( DriverCacheStringTable, SourceName )){
  1426. Count++;
  1427. continue;
  1428. }
  1429. }
  1430. TargetName = InfGetFieldByIndex(Inf,SectionName,Count,1);
  1431. Directory = LookUpDirectory(CopyList,DUMMY_DIRID);
  1432. Count++;
  1433. if(!AddFile(CopyList,SourceName,TargetName,Directory,FileFlags,0)) {
  1434. Err = ERROR_NOT_ENOUGH_MEMORY;
  1435. goto cleanup;
  1436. }
  1437. }
  1438. } else {
  1439. #if defined(_X86_)
  1440. TCHAR diskID[4];
  1441. wsprintf (diskID, TEXT("d%u"), MLSDiskID);
  1442. #endif
  1443. while((DirSymbol = InfGetFieldByIndex(Inf,SectionName,Count,0))) {
  1444. if( Cancelled == TRUE ) {
  1445. //
  1446. // The user is trying to exit, and the clean up code
  1447. // is waiting for us to finish. Break out.
  1448. //
  1449. break;
  1450. }
  1451. SourceName = (LPTSTR) InfGetFieldByIndex(Inf,SectionName,Count,1);
  1452. if(NULL == SourceName) {
  1453. *ErrorLine = Count;
  1454. Err = ERROR_INVALID_DATA;
  1455. DebugLog (
  1456. Winnt32LogError,
  1457. TEXT("ERROR: Could not look up source name in section %1 line = %2!u!"),
  1458. 0,
  1459. SectionName,
  1460. Count
  1461. );
  1462. goto cleanup;
  1463. }
  1464. //
  1465. // move this check here to help catch build errors in dosnet.inf
  1466. //
  1467. Directory = LookUpDirectory(CopyList,DirSymbol);
  1468. if(!Directory) {
  1469. *ErrorLine = Count;
  1470. Err = ERROR_INVALID_DATA;
  1471. DebugLog (
  1472. Winnt32LogError,
  1473. TEXT("ERROR: Could not look up directory %1 in section %2 line = %3!u!"),
  1474. 0,
  1475. DirSymbol,
  1476. SectionName,
  1477. Count
  1478. );
  1479. goto cleanup;
  1480. }
  1481. #if defined(_X86_)
  1482. if (MLSDiskID) {
  1483. //
  1484. //restrict copy to files on this disk only
  1485. //
  1486. if (_tcsicmp (diskID, DirSymbol) != 0) {
  1487. Count++;
  1488. continue;
  1489. }
  1490. }
  1491. #endif
  1492. // If the file is present in drvindex.inf and not in the
  1493. // [ForceCopyDriverCabFiles] section then don't add it to the copylist
  1494. //
  1495. // This is the section in dosnet.inf that we cross check against when making the filelists.
  1496. // Files in this section are in the driver cab and also should reside in the local source
  1497. // The idea here is that these files are once that are not in the FloppyFiles.x sections and yet
  1498. // need to remain outside the driver cab.
  1499. //
  1500. if( DoDriverCabPruning){
  1501. if (FileToBeCopied( DriverCacheStringTable, SourceName )){
  1502. Count++;
  1503. continue;
  1504. }
  1505. }
  1506. TargetName = InfGetFieldByIndex(Inf,SectionName,Count,2);
  1507. Count++;
  1508. if(NumberOfLicensedProcessors
  1509. && !(FileFlags & FILE_NEED_TO_FREE_SOURCENAME)
  1510. && !TargetName
  1511. && !lstrcmpi(SourceName,TEXT("SETUPREG.HIV"))) {
  1512. TargetName = MALLOC(20*sizeof(TCHAR));
  1513. if(!TargetName) {
  1514. Err = ERROR_NOT_ENOUGH_MEMORY;
  1515. goto cleanup;
  1516. }
  1517. if (_sntprintf((PTSTR)TargetName,20,TEXT("IDW\\SETUP\\SETUP%uP.HIV"),NumberOfLicensedProcessors) < 0) {
  1518. ((PTSTR)TargetName)[20 - 1] = 0;
  1519. }
  1520. p = AddFile(
  1521. CopyList,
  1522. TargetName,
  1523. SourceName,
  1524. Directory,
  1525. FileFlags | FILE_NEED_TO_FREE_SOURCENAME,
  1526. 0
  1527. );
  1528. } else {
  1529. p = AddFile(
  1530. CopyList,
  1531. SourceName,
  1532. TargetName,
  1533. Directory,
  1534. FileFlags,
  1535. 0
  1536. );
  1537. }
  1538. if(!p) {
  1539. Err = ERROR_NOT_ENOUGH_MEMORY;
  1540. goto cleanup;
  1541. }
  1542. }
  1543. }
  1544. cleanup:
  1545. if( DriverCacheStringTable )
  1546. pSetupStringTableDestroy( DriverCacheStringTable );
  1547. if( DoDriverCabPruning){
  1548. pSetupUninitializeUtils();
  1549. }
  1550. return(Err);
  1551. }
  1552. PDIR
  1553. AddDirectory(
  1554. IN LPCTSTR InfSymbol, OPTIONAL
  1555. IN OUT PCOPY_LIST CopyList,
  1556. IN LPCTSTR SourceName,
  1557. IN LPCTSTR TargetName, OPTIONAL
  1558. IN UINT Flags
  1559. )
  1560. /*++
  1561. Routine Description:
  1562. Add a directory to a copy list.
  1563. No attempt is made to eliminate duplicates.
  1564. Directories will be listed in the copy list in the order in which they
  1565. were added.
  1566. Arguments:
  1567. InfSymbol - if specified, supplies the symbol from the [Directories]
  1568. section of the master inf that identifies the directory. This pointer
  1569. is used as-is; no copy of the string is made.
  1570. CopyList - supplies the copy list to which the directory is added.
  1571. SourceName - supplies name of directory on the source. If the
  1572. DIR_NEED_TO_FREE_SOURCENAME flag is set in the Flags parameter then
  1573. a copy is made of this string, otherwise this pointer is used as-is
  1574. in the copy list.
  1575. TargetName - if specified, supplies the name for the directory on the
  1576. target. This name is used as-is (no copy is made). If not specified
  1577. then the target name is the same as the source name.
  1578. Flags - supplies flags that control the directory's entry in
  1579. the copy list.
  1580. Return Value:
  1581. If successful, returns a pointer to the new FIL structure for the file.
  1582. Otherwise returns NULL (the caller can assume out of memory).
  1583. --*/
  1584. {
  1585. PDIR dir;
  1586. PDIR x;
  1587. PDIR p;
  1588. //
  1589. // We assume the directory isn't already in the list.
  1590. // Make a copy of the directory string and stick it in a DIR struct.
  1591. //
  1592. dir = MALLOC(sizeof(DIR));
  1593. if(!dir) {
  1594. return(NULL);
  1595. }
  1596. ZeroMemory(dir,sizeof(DIR));
  1597. if(Flags & DIR_NEED_TO_FREE_SOURCENAME) {
  1598. dir->SourceName = DupString(SourceName);
  1599. if(!dir->SourceName) {
  1600. FREE(dir);
  1601. return(NULL);
  1602. }
  1603. } else {
  1604. dir->SourceName = SourceName;
  1605. }
  1606. dir->InfSymbol = InfSymbol;
  1607. dir->TargetName = TargetName ? TargetName : dir->SourceName;
  1608. dir->Flags = Flags;
  1609. DebugLog(
  1610. Winnt32LogDetailedInformation,
  1611. NULL,
  1612. MSG_LOG_ADDED_DIR_TO_COPY_LIST,
  1613. dir->SourceName,
  1614. dir->TargetName,
  1615. dir->InfSymbol ? dir->InfSymbol : TEXT("-")
  1616. );
  1617. #ifndef SLOWER_WAY
  1618. p = CopyList->Directories;
  1619. if (p) {
  1620. dir->Prev = p->Prev;
  1621. dir->Next = NULL;
  1622. p->Prev->Next = dir;
  1623. p->Prev = dir;
  1624. } else {
  1625. CopyList->Directories = dir;
  1626. dir->Prev = dir;
  1627. dir->Next = NULL;
  1628. }
  1629. #else
  1630. if(CopyList->Directories) {
  1631. //
  1632. // Preserve order.
  1633. //
  1634. for(p=CopyList->Directories; p->Next; p=p->Next) {
  1635. ;
  1636. }
  1637. p->Next = dir;
  1638. } else {
  1639. CopyList->Directories = dir;
  1640. }
  1641. #endif
  1642. CopyList->DirectoryCount++;
  1643. return(dir);
  1644. }
  1645. PFIL
  1646. AddFile(
  1647. IN OUT PCOPY_LIST CopyList,
  1648. IN LPCTSTR SourceFilename,
  1649. IN LPCTSTR TargetFilename, OPTIONAL
  1650. IN PDIR Directory,
  1651. IN UINT Flags,
  1652. IN ULONGLONG FileSize OPTIONAL
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. Add a single file to a copy list, noting which directory the file
  1657. is in as well as any flags, etc.
  1658. No attempt is made to eliminate duplicates.
  1659. Files will be listed in the copy list in the order in which they
  1660. were added.
  1661. Arguments:
  1662. CopyList - supplies the copy list to which the file is added.
  1663. SourceFilename - supplies the name of the file to be added. If the
  1664. FILE_NEED_TO_FREE_SOURCENAME argument is specified, then this
  1665. string is duplicated. Otherwise it is not duplicated and this
  1666. pointer is stored directly in the copy list node.
  1667. TargetFilename - if specified, then the file has a different name on
  1668. the target than on the source and this is its name on the target.
  1669. If the FILE_NEED_TO_FREE_TARGETNAME argument is specified, then this
  1670. string is duplicated. Otherwise it is not duplicated and this
  1671. pointer is stored directly in the copy list node.
  1672. Directory - supplies a pointer to the directory structure for the
  1673. directory in which the file lives.
  1674. Flags - supplies FILE_xxx flags to control the file's entry in the list.
  1675. FileSize - if specified, supplies the size of the file.
  1676. Return Value:
  1677. If successful, returns a pointer to the new FIL structure for the file.
  1678. Otherwise returns NULL (the caller can assume out of memory).
  1679. --*/
  1680. {
  1681. PFIL fil;
  1682. PFIL p;
  1683. TCHAR FlagsText[500];
  1684. TCHAR SizeText[256];
  1685. //
  1686. // Make a new FIL struct.
  1687. //
  1688. fil = MALLOC(sizeof(FIL));
  1689. if(!fil) {
  1690. return(NULL);
  1691. }
  1692. ZeroMemory(fil,sizeof(FIL));
  1693. if(Flags & FILE_NEED_TO_FREE_SOURCENAME) {
  1694. fil->SourceName = DupString(SourceFilename);
  1695. if(!fil->SourceName) {
  1696. FREE(fil);
  1697. return(NULL);
  1698. }
  1699. } else {
  1700. fil->SourceName = SourceFilename;
  1701. }
  1702. if(TargetFilename) {
  1703. if (Flags & FILE_NEED_TO_FREE_TARGETNAME) {
  1704. fil->TargetName = DupString(TargetFilename);
  1705. if(!fil->TargetName) {
  1706. if(Flags & FILE_NEED_TO_FREE_SOURCENAME) {
  1707. FREE((PVOID)fil->SourceName);
  1708. }
  1709. FREE(fil);
  1710. return(NULL);
  1711. }
  1712. } else {
  1713. fil->TargetName = TargetFilename;
  1714. }
  1715. } else {
  1716. fil->TargetName = fil->SourceName;
  1717. Flags &= ~FILE_NEED_TO_FREE_TARGETNAME;
  1718. }
  1719. fil->Directory = Directory;
  1720. fil->Flags = Flags;
  1721. fil->Size = FileSize;
  1722. if (Winnt32LogDetailedInformation < DebugLevel) {
  1723. _sntprintf(FlagsText,ARRAYSIZE(FlagsText),TEXT("0x%x"),Flags);
  1724. if(Flags & FILE_ON_SYSTEM_PARTITION_ROOT) {
  1725. StringCchCat(FlagsText,ARRAYSIZE(FlagsText),TEXT(" FILE_ON_SYSTEM_PARTITION_ROOT"));
  1726. }
  1727. #if defined(REMOTE_BOOT)
  1728. if(Flags & FILE_ON_MACHINE_DIRECTORY_ROOT) {
  1729. StringCchCat(FlagsText,ARRAYSIZE(FlagsText),TEXT(" FILE_ON_MACHINE_DIRECTORY_ROOT"));
  1730. }
  1731. #endif // defined(REMOTE_BOOT)
  1732. if(Flags & FILE_IN_LOCAL_BOOT) {
  1733. StringCchCat(FlagsText,ARRAYSIZE(FlagsText),TEXT(" FILE_IN_LOCAL_BOOT"));
  1734. }
  1735. if(Flags & FILE_PRESERVE_COMPRESSED_NAME) {
  1736. StringCchCat(FlagsText,ARRAYSIZE(FlagsText),TEXT(" FILE_PRESERVE_COMPRESSED_NAME"));
  1737. }
  1738. #if 0
  1739. if(Flags & FILE_DECOMPRESS) {
  1740. StringCchCat(FlagsText,ARRAYSIZE(FlagsText),TEXT(" FILE_DECOMPRESS"));
  1741. }
  1742. #endif
  1743. if (Flags & FILE_IGNORE_COPY_ERROR) {
  1744. StringCchCat(FlagsText,ARRAYSIZE(FlagsText), TEXT("FILE_IGNORE_COPY_ERROR"));
  1745. }
  1746. if (!GetUserPrintableFileSizeString(
  1747. fil->Size,
  1748. SizeText,
  1749. ARRAYSIZE(SizeText))) {
  1750. MYASSERT (ARRAYSIZE(SizeText) >= ARRAYSIZE("0"));
  1751. lstrcpy( SizeText, TEXT("0"));
  1752. }
  1753. DebugLog(
  1754. Winnt32LogDetailedInformation,
  1755. NULL,
  1756. MSG_LOG_ADDED_FILE_TO_COPY_LIST,
  1757. fil->SourceName,
  1758. Directory->SourceName,
  1759. SizeText,
  1760. fil->TargetName,
  1761. FlagsText
  1762. );
  1763. }
  1764. #ifndef SLOWER_WAY
  1765. p = CopyList->Files;
  1766. if (p) {
  1767. fil->Prev = p->Prev;
  1768. fil->Next = NULL;
  1769. p->Prev->Next = fil;
  1770. p->Prev = fil;
  1771. } else {
  1772. CopyList->Files = fil;
  1773. fil->Prev = fil;
  1774. fil->Next = NULL;
  1775. }
  1776. #else
  1777. //
  1778. // Hook into copy list. Preserve order.
  1779. //
  1780. if(CopyList->Files) {
  1781. for(p=CopyList->Files; p->Next; p=p->Next) {
  1782. ;
  1783. }
  1784. p->Next = fil;
  1785. } else {
  1786. CopyList->Files = fil;
  1787. }
  1788. #endif
  1789. CopyList->FileCount++;
  1790. return(fil);
  1791. }
  1792. BOOL
  1793. RemoveFile (
  1794. IN OUT PCOPY_LIST CopyList,
  1795. IN LPCTSTR SourceName,
  1796. IN PDIR Directory, OPTIONAL
  1797. IN DWORD SetFlags OPTIONAL
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. Add a single file to a copy list, noting which directory the file
  1802. is in as well as any flags, etc.
  1803. No attempt is made to eliminate duplicates.
  1804. Files will be listed in the copy list in the order in which they
  1805. were added.
  1806. Arguments:
  1807. CopyList - supplies the copy list from which the file is removed.
  1808. SourceFilename - supplies the name of the file to be removed.
  1809. Directory - supplies a pointer to the directory structure for the
  1810. directory in which the file lives.
  1811. Flags - supplies FILE_xxx flags to match against the file's entry in the list.
  1812. Return Value:
  1813. TRUE if the specified file was found in the list and marked as removed
  1814. FALSE otherwise
  1815. --*/
  1816. {
  1817. PFIL p;
  1818. for (p = CopyList->Files; p; p = p->Next) {
  1819. if (_tcsicmp (p->SourceName, SourceName) == 0 &&
  1820. (!Directory || Directory == p->Directory) &&
  1821. ((p->Flags & SetFlags) == SetFlags)
  1822. ) {
  1823. p->Flags |= FILE_DO_NOT_COPY;
  1824. return TRUE;
  1825. }
  1826. }
  1827. return FALSE;
  1828. }
  1829. PDIR
  1830. LookUpDirectory(
  1831. IN PCOPY_LIST CopyList,
  1832. IN LPCTSTR DirSymbol
  1833. )
  1834. /*++
  1835. Routine Description:
  1836. Looks for an entry for a directory in a copy list that matches
  1837. a given INF symbol.
  1838. Arguments:
  1839. CopyList - supplies the copy list in which the directory is to be
  1840. searched for.
  1841. DirSymbol - supplies the symbol that is expected to match an entry in
  1842. the main inf's [Directories] section.
  1843. Return Value:
  1844. If the dir is found then the return value is a pointer to the
  1845. directory node in the copy list. Otherwise NULL is returned.
  1846. --*/
  1847. {
  1848. PDIR dir;
  1849. for(dir=CopyList->Directories; dir; dir=dir->Next) {
  1850. if(dir->InfSymbol && !lstrcmpi(dir->InfSymbol,DirSymbol)) {
  1851. return(dir);
  1852. }
  1853. }
  1854. return(NULL);
  1855. }
  1856. VOID
  1857. TearDownCopyList(
  1858. IN OUT PCOPY_LIST CopyList
  1859. )
  1860. /*++
  1861. Routine Description:
  1862. Deletes a copy list and frees all associated memory.
  1863. Arguments:
  1864. CopyList - supplies a pointer to the copy list structure for the
  1865. copy list to be freed. The COPY_LIST struct itself is NOT freed
  1866. but all fields in it are zeroed out.
  1867. Return Value:
  1868. None.
  1869. --*/
  1870. {
  1871. PDIR dir;
  1872. PFIL fil;
  1873. PVOID p;
  1874. dir = CopyList->Directories;
  1875. while(dir) {
  1876. p = dir->Next;
  1877. //
  1878. // Free the source and the target if necessary
  1879. //
  1880. if(dir->SourceName && (dir->Flags & DIR_NEED_TO_FREE_SOURCENAME)) {
  1881. FREE((PVOID)dir->SourceName);
  1882. }
  1883. FREE(dir);
  1884. dir = p;
  1885. }
  1886. fil = CopyList->Files;
  1887. while(fil) {
  1888. p = fil->Next;
  1889. //
  1890. // Free the source and the target if necessary
  1891. //
  1892. if(fil->SourceName && (fil->Flags & FILE_NEED_TO_FREE_SOURCENAME)) {
  1893. FREE((PVOID)fil->SourceName);
  1894. }
  1895. if(fil->TargetName && (fil->Flags & FILE_NEED_TO_FREE_TARGETNAME)) {
  1896. FREE((PVOID)fil->TargetName);
  1897. }
  1898. FREE(fil);
  1899. fil = p;
  1900. }
  1901. ZeroMemory(CopyList,sizeof(COPY_LIST));
  1902. }
  1903. BOOL
  1904. GetMainInfValue (
  1905. IN PCTSTR Section,
  1906. IN PCTSTR Key,
  1907. IN DWORD FieldNumber,
  1908. OUT PTSTR Buffer,
  1909. IN DWORD BufChars
  1910. )
  1911. {
  1912. PCTSTR p;
  1913. PTSTR end;
  1914. if (MainInf) {
  1915. p = InfGetFieldByKey (MainInf, Section, Key, FieldNumber);
  1916. if (p) {
  1917. lstrcpyn (Buffer, p, BufChars);
  1918. }
  1919. return p != NULL;
  1920. }
  1921. if (!FullInfName[0]) {
  1922. if (!FindPathToWinnt32File (InfName, FullInfName, ARRAYSIZE(InfName))) {
  1923. InfName[0] = 0;
  1924. return FALSE;
  1925. }
  1926. }
  1927. if (!GetPrivateProfileString (
  1928. Section,
  1929. Key,
  1930. TEXT(""),
  1931. Buffer,
  1932. BufChars,
  1933. FullInfName
  1934. )) {
  1935. return FALSE;
  1936. }
  1937. MYASSERT (FieldNumber <= 1);
  1938. end = _tcschr (Buffer, TEXT(','));
  1939. if (FieldNumber == 1) {
  1940. if (!end) {
  1941. return FALSE;
  1942. }
  1943. lstrcpyn (Buffer, end + 1, BufChars);
  1944. } else {
  1945. if (end) {
  1946. *end = 0 ;
  1947. }
  1948. }
  1949. return TRUE;
  1950. }
  1951. BOOL
  1952. CheckCopyListSpace(
  1953. IN TCHAR DriveLetter,
  1954. IN DWORD BytesPerCluster,
  1955. IN LONGLONG FreeSpace,
  1956. OUT DWORD *RequiredMB,
  1957. IN BOOL CheckBootFiles,
  1958. IN BOOL CheckLocalSource,
  1959. IN BOOL CheckWinntDirectorySpace,
  1960. IN BOOL QuickTest,
  1961. IN LONGLONG AdditionalPadding
  1962. )
  1963. /*++
  1964. Routine Description:
  1965. This routine scans the master copy list and determines, based on cluster
  1966. size, whether the drive contains enough space to hold the files in
  1967. that list.
  1968. Note that the check is not exact because we can't predict exactly how
  1969. much space the directories themselves might occupy, and we assume that
  1970. none of the files already exist on the target, which is not always true
  1971. (for example ntldr, ntdetect.com, etc, which are already on C:\ in the
  1972. amd64/x86 case). We fudge by adding a meg to the requirements.
  1973. Arguments:
  1974. DriveLetter - supplies the drive letter of the drive being checked.
  1975. The FILE_ON_SYSTEM_PARTITION_ROOT and FILE_IN_LOCAL_BOOT flags
  1976. for nodes in the copy list require special handling based on the
  1977. drive letter of the drive being scanned.
  1978. BytesPerCluster - specifies the number of bytes per cluster
  1979. on the drive.
  1980. FreeSpace - supplies the number of free bytes on the drive.
  1981. RequiredMB - receives the amount of space required on this drive, in MB.
  1982. CheckLocalSource - Do we need to check for space on this drive for
  1983. copying all the source local?
  1984. CheckBootFiles - Do we need to check for space on this drive for
  1985. copying all the boot files?
  1986. CheckWinntDirectorySpace - Do we need to add in the space required
  1987. for the final winnt directory?
  1988. Return Value:
  1989. If TRUE then the drive has enough space on it to hold the files
  1990. listed in the copy list. If FALSE then it does not.
  1991. --*/
  1992. {
  1993. PFIL File;
  1994. LONGLONG SpaceRequired = 0;
  1995. LONGLONG SpaceLocalSource = 0;
  1996. LONGLONG SpaceBootFiles = 0;
  1997. LONGLONG SpacePadding = 0;
  1998. LONGLONG SpaceWinDir = 0;
  1999. LONGLONG RoundedSize;
  2000. TCHAR ClusterSizeString[64];
  2001. TCHAR buffer[64];
  2002. PTSTR p;
  2003. if( BytesPerCluster <= 512 ) {
  2004. MYASSERT (ARRAYSIZE(ClusterSizeString) >= ARRAYSIZE("TempDirSpace512"));
  2005. lstrcpy( ClusterSizeString,TEXT("TempDirSpace512") );
  2006. } else if( BytesPerCluster > (256 * 1024) ) {
  2007. MYASSERT (ARRAYSIZE(ClusterSizeString) >= ARRAYSIZE("TempDirSpace32K"));
  2008. lstrcpy( ClusterSizeString, TEXT("TempDirSpace32K") );
  2009. } else {
  2010. if (FAILED (StringCchPrintf (
  2011. ClusterSizeString,
  2012. ARRAYSIZE(ClusterSizeString),
  2013. TEXT("TempDirSpace%uK"),
  2014. BytesPerCluster/1024))) {
  2015. MYASSERT (FALSE);
  2016. }
  2017. }
  2018. //
  2019. // ====================================================
  2020. // If appropriate, add in space needs for the ~LS directory.
  2021. // ====================================================
  2022. //
  2023. if( CheckLocalSource ) {
  2024. BOOL WantThisFile;
  2025. //
  2026. // If we're checking local source, there are so many files that
  2027. // we're going to add in a small fudge factor.
  2028. //
  2029. SpacePadding = AdditionalPadding;
  2030. SpaceLocalSource = 1000000 + AdditionalPadding;
  2031. //
  2032. // Dosnet.inf has sizing info for each possible cluster size.
  2033. // That info tells us how much the files in the [Files] section
  2034. // take up on a drive with that cluster size. That's really
  2035. // handy because then we don't have to hit the sources to actually
  2036. // fetch each file's size.
  2037. //
  2038. // But the inf doesn't include optional directories, so we need to
  2039. // traverse the copy list and add up all the (rounded) sizes, and
  2040. // then add the total to the value from the inf.
  2041. //
  2042. // When we built the copy list, the files in the [Files] section
  2043. // wound up with a Size of 0 since we don't go out to the source
  2044. // to get the size. The files that were in optional dirs have their
  2045. // actual sizes filled in. This allows us to do something a little
  2046. // funky: we traverse the entire list without regard for whether a
  2047. // file was in the [Files] section or was in an optional dir, since
  2048. // the "0-size" files don't hose up the calculation. Then we add
  2049. // that value to the relevent value from the inf.
  2050. //
  2051. for(File=MasterCopyList.Files; File; File=File->Next) {
  2052. if(File->Flags & (FILE_IN_LOCAL_BOOT | FILE_ON_SYSTEM_PARTITION_ROOT
  2053. #if defined(REMOTE_BOOT)
  2054. | FILE_ON_MACHINE_DIRECTORY_ROOT
  2055. #endif // defined(REMOTE_BOOT)
  2056. )) {
  2057. //
  2058. // Special handling based on the system partition.
  2059. //
  2060. WantThisFile = CheckBootFiles;
  2061. } else {
  2062. WantThisFile = CheckLocalSource;
  2063. }
  2064. if(WantThisFile) {
  2065. if(File->Size % BytesPerCluster) {
  2066. RoundedSize = File->Size + (BytesPerCluster - (DWORD)(File->Size % BytesPerCluster));
  2067. } else {
  2068. RoundedSize = File->Size;
  2069. }
  2070. SpaceLocalSource += RoundedSize;
  2071. }
  2072. }
  2073. //
  2074. // If appropriate, add in space needs for the ~LS directory.
  2075. // Note that we go ahead an calculate LocalSourceSpace because
  2076. // we may need that later on.
  2077. //
  2078. if (GetMainInfValue (szDiskSpaceReq, ClusterSizeString, 0, buffer, ARRAYSIZE(buffer)) ||
  2079. //
  2080. // Strange cluster size or inf is broken. Try to use a default of 512
  2081. // since that most closely approximates the actual size of the files.
  2082. //
  2083. GetMainInfValue (szDiskSpaceReq, TEXT("TempDirSpace512"), 0, buffer, ARRAYSIZE(buffer))
  2084. ) {
  2085. SpaceLocalSource += _tcstoul(buffer,NULL,10);
  2086. } else {
  2087. MYASSERT (FALSE);
  2088. }
  2089. }
  2090. //
  2091. // ====================================================
  2092. // If appropriate, add in space needs for the ~BT directory.
  2093. // ====================================================
  2094. //
  2095. if( CheckBootFiles ) {
  2096. if( !IsArc() ) {
  2097. //
  2098. // Go get the space requirements for the boot files
  2099. // from dosnet.inf.
  2100. //
  2101. if (GetMainInfValue (szDiskSpaceReq, ClusterSizeString, 1, buffer, ARRAYSIZE(buffer))) {
  2102. SpaceBootFiles += _tcstoul(buffer,NULL,10);
  2103. } else {
  2104. //
  2105. // Guess about 5Mb for amd64/x86 because we need the entire
  2106. // ~BT directory.
  2107. //
  2108. SpaceBootFiles += (5*1024*1024);
  2109. }
  2110. } else {
  2111. //
  2112. // Guess that we'll need about 1.5Mb for ARC.
  2113. // We can't assume that this will go to 0x0 just
  2114. // because we're doing an upgrade because we might
  2115. // be going from 4.0 to 5.0 (for example). In this
  2116. // case we will create a new directory under the
  2117. // \os tree to hold the hal, osloader, ...
  2118. //
  2119. SpaceBootFiles += (3*512*1024);
  2120. }
  2121. }
  2122. //
  2123. // ====================================================
  2124. // If appropriate, add in space needs for the install directory.
  2125. // ====================================================
  2126. //
  2127. // Note: This is for upgrade.
  2128. // We also need to take in account the space requirements for Program Files, Documents and Settings
  2129. if( CheckWinntDirectorySpace ) {
  2130. if( BytesPerCluster <= 512 ) {
  2131. MYASSERT (ARRAYSIZE(ClusterSizeString) >= ARRAYSIZE("WinDirSpace512"));
  2132. lstrcpy( ClusterSizeString,TEXT("WinDirSpace512") );
  2133. } else if( BytesPerCluster > (256 * 1024) ) {
  2134. MYASSERT (ARRAYSIZE(ClusterSizeString) >= ARRAYSIZE("WinDirSpace32K"));
  2135. lstrcpy( ClusterSizeString, TEXT("WinDirSpace32K") );
  2136. } else {
  2137. if (FAILED (StringCchPrintf (
  2138. ClusterSizeString,
  2139. ARRAYSIZE(ClusterSizeString),
  2140. TEXT("WinDirSpace%uK"),
  2141. BytesPerCluster/1024))) {
  2142. MYASSERT (FALSE);
  2143. }
  2144. }
  2145. //
  2146. // First we figure out how much a fresh install might take.
  2147. //
  2148. if (GetMainInfValue (szDiskSpaceReq, ClusterSizeString, 0, buffer, ARRAYSIZE(buffer))) {
  2149. //
  2150. // Multiply him by 1024 because the values in
  2151. // txtsetup.sif are in Kb instead of bytes.
  2152. //
  2153. SpaceWinDir += (_tcstoul(buffer,NULL,10) * 1024);
  2154. } else {
  2155. // guess...
  2156. SpaceWinDir += (924 * (1024 * 1024));
  2157. }
  2158. // Lets take into account Program Files
  2159. if (GetMainInfValue (szDiskSpaceReq, szPFDocSpaceReq, 0, buffer, ARRAYSIZE(buffer))) {
  2160. //
  2161. // Multiply him by 1024 because the values are in Kb instead of bytes.
  2162. //
  2163. SpaceWinDir += (_tcstoul(buffer,NULL,10) * 1024);
  2164. } else {
  2165. // guess...
  2166. SpaceWinDir += (WINDOWS_DEFAULT_PFDOC_SIZE * 1024);
  2167. }
  2168. WinDirSpaceFor9x = SpaceWinDir;
  2169. if( Upgrade ) {
  2170. LPCTSTR q = 0;
  2171. //
  2172. // We're upgrading, so we need to figure out which
  2173. // build we're running, then subtract off how much
  2174. // a clean install of that build would have taken.
  2175. // This will give us an idea of how much the %windir%
  2176. // will grow.
  2177. //
  2178. if( ISNT() ) {
  2179. BOOL b;
  2180. //
  2181. // NT case.
  2182. //
  2183. if( BuildNumber <= NT351 ) {
  2184. b = GetMainInfValue (szDiskSpaceReq, TEXT("351WinDirSpace"), 0, buffer, ARRAYSIZE(buffer));
  2185. } else if( BuildNumber <= NT40 ) {
  2186. b = GetMainInfValue (szDiskSpaceReq, TEXT("40WinDirSpace"), 0, buffer, ARRAYSIZE(buffer));
  2187. } else if( BuildNumber <= NT50 ) {
  2188. b = GetMainInfValue (szDiskSpaceReq, TEXT("50WinDirSpace"), 0, buffer, ARRAYSIZE(buffer));
  2189. } else {
  2190. b = GetMainInfValue (szDiskSpaceReq, TEXT("51WinDirSpace"), 0, buffer, ARRAYSIZE(buffer));
  2191. }
  2192. if( b ) {
  2193. //
  2194. // Multiply him by 1024 because the values in
  2195. // dosnet.inf are in Kb instead of bytes.
  2196. //
  2197. SpaceWinDir -= (_tcstoul(buffer,NULL,10) * 1024);
  2198. }
  2199. if( BuildNumber <= NT351 ) {
  2200. b = GetMainInfValue (szDiskSpaceReq, TEXT("351PFDocSpace"), 0, buffer, ARRAYSIZE(buffer));
  2201. } else if( BuildNumber <= NT40 ) {
  2202. b = GetMainInfValue (szDiskSpaceReq, TEXT("40PFDocSpace"), 0, buffer, ARRAYSIZE(buffer));
  2203. } else if( BuildNumber <= NT50 ) {
  2204. b = GetMainInfValue (szDiskSpaceReq, TEXT("50PFDocSpace"), 0, buffer, ARRAYSIZE(buffer));
  2205. } else {
  2206. b = GetMainInfValue (szDiskSpaceReq, TEXT("51PFDocSpace"), 0, buffer, ARRAYSIZE(buffer));
  2207. }
  2208. if( b ) {
  2209. //
  2210. // Multiply him by 1024 because the values are in Kb instead of bytes.
  2211. //
  2212. SpaceWinDir -= (_tcstoul(buffer,NULL,10) * 1024);
  2213. }
  2214. //
  2215. // Make sure we don't look bad...
  2216. // At 85 MB, we are near the border line of gui-mode having enough space to run.
  2217. // note:during gui-mode, there is 41MB pagefile
  2218. //
  2219. //
  2220. if( SpaceWinDir < 0 ) {
  2221. SpaceWinDir = (90 * (1024*024));
  2222. }
  2223. } else {
  2224. //
  2225. // Win9X case.
  2226. //
  2227. //
  2228. // Note that the Win9X upgrade DLL can do a much better job of
  2229. // determining disk space requirements for the %windir% than
  2230. // I can. We'll bypass this check if we're not on NT.
  2231. // But, we need about 50MB disk space to run Win9x upgrage.
  2232. //
  2233. SpaceWinDir = 50<<20; //50MB
  2234. }
  2235. } // Upgrade
  2236. } // CheckWinntDirectorySpace
  2237. SpaceRequired = SpaceLocalSource + SpaceBootFiles + SpaceWinDir;
  2238. if( CheckLocalSource ) {
  2239. //
  2240. // We need to remember how much space will be
  2241. // required on the drive where we place the ~LS
  2242. // directory because we send that to the upgrade
  2243. // dll.
  2244. //
  2245. LocalSourceSpaceRequired = SpaceRequired;
  2246. }
  2247. *RequiredMB = (DWORD)((SpaceRequired+1048575) / (1024*1024));
  2248. DebugLog( QuickTest ? Winnt32LogDetailedInformation : Winnt32LogError, NULL, MSG_LOG_DISKSPACE_CHECK,
  2249. DriveLetter,
  2250. (ULONG)BytesPerCluster,
  2251. (ULONG)(FreeSpace / (1024*1024)),
  2252. (ULONG)((SpaceLocalSource+1048575) / (1024*1024)),
  2253. (ULONG)(SpacePadding / (1024*1024)),
  2254. (ULONG)((SpaceBootFiles+1048575) / (1024*1024)),
  2255. (ULONG)((SpaceWinDir+1048575) / (1024*1024)),
  2256. (ULONG)*RequiredMB
  2257. );
  2258. return(SpaceRequired <= FreeSpace);
  2259. }
  2260. #define VALID_DRIVE (32)
  2261. #define INVALID_DRIVE (64)
  2262. #define NOT_ENOUGH_SPACE (128)
  2263. ULONG
  2264. CheckASingleDrive(
  2265. IN TCHAR DriveLetter, OPTIONAL
  2266. IN PCTSTR NtVolumeName, OPTIONAL
  2267. OUT DWORD *ClusterSize,
  2268. OUT DWORD *RequiredMb,
  2269. OUT DWORD *AvailableMb,
  2270. IN BOOL CheckBootFiles,
  2271. IN BOOL CheckLocalSource,
  2272. IN BOOL CheckFinalInstallDir,
  2273. IN BOOL QuickTest,
  2274. IN LONGLONG AdditionalPadding
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. This routine examines a specific drive for its potential to hold
  2279. some or all of the install files.
  2280. First he runs through a series of checks to make sure the drive
  2281. is appropriate. If we get through all of those, we go check for
  2282. drive space requirements.
  2283. Arguments:
  2284. DriveLetter - supplies the drive letter of the drive being checked;
  2285. may be 0 only if NtVolumeName is specified instead
  2286. NtVolumeName - supplies the NT device name of the drive being checked;
  2287. only used if DriveLetter is not specified
  2288. ClusterSize - the clustersize on the we'll check.
  2289. RequiredSpace - receives the amount of space required on this drive.
  2290. AvailableSpace - receives the number of free bytes on the drive.
  2291. CheckBootFiles - Do we need to check for space on this drive for
  2292. copying all the boot files?
  2293. CheckLocalSource - Do we need to check for space on this drive for
  2294. copying all the source local?
  2295. CheckFinalInstallDir - Do we need to add in the space required
  2296. for the final winnt directory?
  2297. Return Value:
  2298. NOT_ENOUGH_SPACE - RequiredSpace > AvailableSpace
  2299. INVALID_DRIVE - The drive is inappropriate for holding install
  2300. source. E.g. it's a floppy, ...
  2301. VALID_DRIVE - The drive is appropriate for holding install source
  2302. AND RequiredSpace < AvailableSpace
  2303. --*/
  2304. {
  2305. TCHAR DriveName[MAX_PATH];
  2306. TCHAR Filesystem[256];
  2307. TCHAR VolumeName[MAX_PATH];
  2308. DWORD SerialNumber;
  2309. DWORD MaxComponent;
  2310. DWORD Flags;
  2311. DWORD SectorsPerCluster = 0;
  2312. DWORD BytesPerSector = 0;
  2313. ULARGE_INTEGER FreeClusters = {0, 0};
  2314. ULARGE_INTEGER TotalClusters = {0, 0};
  2315. BOOL b;
  2316. LONGLONG AvailableBytes;
  2317. DWORD DriveType;
  2318. MYASSERT (DriveLetter || ISNT());
  2319. if (!(DriveLetter || ISNT())) {
  2320. return DRIVE_UNKNOWN;
  2321. }
  2322. if (DriveLetter) {
  2323. DriveName[0] = DriveLetter;
  2324. DriveName[1] = TEXT(':');
  2325. DriveName[2] = TEXT('\\');
  2326. DriveName[3] = 0;
  2327. } else {
  2328. #ifdef UNICODE
  2329. MYASSERT (NtVolumeName);
  2330. #else
  2331. MYASSERT (FALSE);
  2332. return ( DRIVE_UNKNOWN );
  2333. #endif
  2334. }
  2335. //
  2336. // ====================================================
  2337. // Check for appropriate drive.
  2338. // ====================================================
  2339. //
  2340. //
  2341. // Disallow a set of drives...
  2342. //
  2343. if (DriveLetter) {
  2344. DriveType = MyGetDriveType(DriveLetter);
  2345. if(DriveType == DRIVE_UNKNOWN ||
  2346. DriveType == DRIVE_RAMDISK ||
  2347. DriveType == DRIVE_NO_ROOT_DIR
  2348. ) {
  2349. return( DRIVE_UNKNOWN );
  2350. }
  2351. } else {
  2352. #ifdef UNICODE
  2353. DriveType = MyGetDriveType2(NtVolumeName);
  2354. if(DriveType == DRIVE_UNKNOWN ||
  2355. DriveType == DRIVE_RAMDISK ||
  2356. DriveType == DRIVE_NO_ROOT_DIR
  2357. ) {
  2358. return( DRIVE_UNKNOWN );
  2359. }
  2360. #endif
  2361. }
  2362. //
  2363. // Check drive type. Skip anything but hard drives.
  2364. //
  2365. if( CheckLocalSource) {
  2366. if (DriveLetter) {
  2367. if (MyGetDriveType(DriveLetter) != DRIVE_FIXED) {
  2368. if (!QuickTest) {
  2369. DebugLog(
  2370. Winnt32LogInformation,
  2371. NULL,
  2372. MSG_LOG_DRIVE_NOT_HARD,
  2373. DriveLetter
  2374. );
  2375. }
  2376. return( INVALID_DRIVE );
  2377. }
  2378. } else {
  2379. #ifdef UNICODE
  2380. if (MyGetDriveType2(NtVolumeName) != DRIVE_FIXED) {
  2381. if (!QuickTest) {
  2382. DebugLog(
  2383. Winnt32LogInformation,
  2384. NULL,
  2385. MSG_LOG_DRIVE_NOT_HARD2,
  2386. NtVolumeName
  2387. );
  2388. }
  2389. return( INVALID_DRIVE );
  2390. }
  2391. #endif
  2392. }
  2393. }
  2394. //
  2395. // Get filesystem. HPFS is disallowed. We make this check because
  2396. // HPFS was still supported in NT3.51 and we have to upgrade NT 3.51.
  2397. // Strictly speaking this check is not required on win95 but there's
  2398. // no reason not to execute it either, so we avoid the #ifdef's.
  2399. //
  2400. if (DriveLetter) {
  2401. b = GetVolumeInformation(
  2402. DriveName,
  2403. VolumeName,MAX_PATH,
  2404. &SerialNumber,
  2405. &MaxComponent,
  2406. &Flags,
  2407. Filesystem,
  2408. ARRAYSIZE(Filesystem)
  2409. );
  2410. if(!b || !lstrcmpi(Filesystem,TEXT("HPFS"))) {
  2411. DebugLog(
  2412. Winnt32LogInformation,
  2413. NULL,
  2414. MSG_LOG_DRIVE_NO_VOL_INFO,
  2415. DriveLetter
  2416. );
  2417. return( INVALID_DRIVE );
  2418. }
  2419. }
  2420. //
  2421. // Check for FT and firmware accessibility. We rely on the underlying
  2422. // routines to do the right thing on Win95.
  2423. //
  2424. // In the upgrade case, we can put the local source on an NTFT drive.
  2425. //
  2426. // Note that we can't do this for Alpha / ARC.
  2427. //
  2428. if( ( IsArc() || !Upgrade ) && IsDriveNTFT(DriveLetter, NtVolumeName) ) {
  2429. if (!QuickTest) {
  2430. DebugLog(Winnt32LogInformation,NULL,MSG_LOG_DRIVE_NTFT,DriveLetter);
  2431. }
  2432. return( INVALID_DRIVE );
  2433. }
  2434. // Don't allow $win_nt$.~ls to go on a soft partition, because the
  2435. // loader/textmode won't be able to find such partitions.
  2436. //
  2437. if(IsSoftPartition(DriveLetter, NtVolumeName)) {
  2438. if (!QuickTest) {
  2439. DebugLog(Winnt32LogInformation,NULL,MSG_LOG_DRIVE_VERITAS,DriveLetter);
  2440. }
  2441. return( INVALID_DRIVE );
  2442. }
  2443. #if defined(_X86_)
  2444. if( !ISNT() ) {
  2445. //
  2446. // If we're running on win95, then make sure we skip
  2447. // any compressed volumes.
  2448. //
  2449. if( Flags & FS_VOL_IS_COMPRESSED) {
  2450. return( INVALID_DRIVE );
  2451. }
  2452. }
  2453. #endif
  2454. if (IsArc() && DriveLetter) {
  2455. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  2456. LPWSTR ArcPath;
  2457. if(DriveLetterToArcPath (DriveLetter,&ArcPath) != NO_ERROR) {
  2458. if (!QuickTest) {
  2459. DebugLog(Winnt32LogInformation,NULL,MSG_LOG_DRIVE_NO_ARC,DriveLetter);
  2460. }
  2461. return( INVALID_DRIVE );
  2462. }
  2463. FREE(ArcPath);
  2464. #endif // UNICODE
  2465. }
  2466. //
  2467. // Finally, get cluster size on the drive and free space stats.
  2468. // Then go through the copy list and figure out whether the drive
  2469. // has enough space.
  2470. //
  2471. if (DriveLetter) {
  2472. b = Winnt32GetDiskFreeSpaceNew(
  2473. DriveName,
  2474. &SectorsPerCluster,
  2475. &BytesPerSector,
  2476. &FreeClusters,
  2477. &TotalClusters
  2478. );
  2479. } else {
  2480. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  2481. b = MyGetDiskFreeSpace (
  2482. NtVolumeName,
  2483. &SectorsPerCluster,
  2484. &BytesPerSector,
  2485. &FreeClusters.LowPart,
  2486. &TotalClusters.LowPart
  2487. );
  2488. #endif // UNICODE
  2489. }
  2490. if(!b) {
  2491. if (!QuickTest) {
  2492. DebugLog(Winnt32LogWarning,NULL,MSG_LOG_DRIVE_CANT_GET_SPACE,DriveLetter,GetLastError());
  2493. }
  2494. return( INVALID_DRIVE );
  2495. }
  2496. //
  2497. // Fill in some return parameters that are also helpful for the
  2498. // next function call.
  2499. //
  2500. *ClusterSize = BytesPerSector * SectorsPerCluster;
  2501. AvailableBytes = (LONGLONG)(*ClusterSize) * FreeClusters.QuadPart;
  2502. *AvailableMb = (ULONG)(AvailableBytes / (1024 * 1024));
  2503. if( CheckCopyListSpace( DriveLetter,
  2504. *ClusterSize,
  2505. AvailableBytes,
  2506. RequiredMb,
  2507. CheckBootFiles,
  2508. CheckLocalSource,
  2509. CheckFinalInstallDir,
  2510. QuickTest,
  2511. AdditionalPadding) ) {
  2512. return( VALID_DRIVE );
  2513. } else {
  2514. return( NOT_ENOUGH_SPACE );
  2515. }
  2516. }
  2517. BOOL
  2518. FindLocalSourceAndCheckSpaceWorker(
  2519. IN HWND hdlg,
  2520. IN BOOL QuickTest,
  2521. IN LONGLONG AdditionalPadding
  2522. )
  2523. /*++
  2524. Routine Description:
  2525. Based on the master copy list, determine which drive has enough space
  2526. to contain the local source. The check is sensitive to the cluster
  2527. size on each drive.
  2528. The alphabetically lowest local drive that is accessible from the firmware,
  2529. not HPFS, not FT, and has enough space gets the local source.
  2530. Arguments:
  2531. hdlg - supplies the window handle of the window which will own
  2532. any UI displayed by this routine.
  2533. Return Value:
  2534. Boolean value indicating outcome. If FALSE, the user will have been
  2535. informed about why. If TRUE, global variables are set up:
  2536. LocalSourceDrive
  2537. LocalSourceDirectory
  2538. LocalSourceWithPlatform
  2539. If the global flag BlockOnNotEnoughSpace is set to FALSE, this routine
  2540. will return TRUE regardless of wether or not a suitable drive was found.
  2541. It is up to whoever sets this flag to ensure that this is the correct behavior.
  2542. --*/
  2543. {
  2544. TCHAR DriveLetter = 0;
  2545. TCHAR WinntDriveLetter = 0;
  2546. TCHAR MyLocalSourceDrive = 0;
  2547. BOOL MakeBootSource = FALSE;
  2548. ULONG CheckResult;
  2549. ULONG ClusterSize;
  2550. ULONG RequiredMb;
  2551. ULONG AvailableMb;
  2552. LPCTSTR q = 0;
  2553. TCHAR platform[MAX_PATH];
  2554. //
  2555. // ====================================================
  2556. // Check the system partition and make sure we can place any
  2557. // boot files we need.
  2558. // ====================================================
  2559. //
  2560. //
  2561. // Will we be creating a $WIN_NT$.~BT directory?
  2562. // On ARC we still check for this space even if we don't need it, just in case.
  2563. // there should always be at least 5M free on the system partition...
  2564. //
  2565. if( IsArc() || ((MakeBootMedia) && (Floppyless)) )
  2566. //
  2567. // RISC always requires a small amount of space on the system
  2568. // partition because we put the loader, hal, and (in the case
  2569. // of ALPHA) the pal code.
  2570. //
  2571. {
  2572. if (!QuickTest) {
  2573. DebugLog( Winnt32LogInformation,
  2574. TEXT( "\r\n\r\nExamining system partition for adequate space for temporary boot files.\r\n"),
  2575. 0 );
  2576. }
  2577. MakeBootSource = TRUE;
  2578. //
  2579. // use the drive letter
  2580. //
  2581. CheckResult = CheckASingleDrive (
  2582. SystemPartitionDriveLetter,
  2583. #ifdef UNICODE
  2584. SystemPartitionNtName,
  2585. #else
  2586. NULL,
  2587. #endif
  2588. &ClusterSize,
  2589. &RequiredMb,
  2590. &AvailableMb,
  2591. TRUE, // Check boot files space
  2592. FALSE, // Check local source space
  2593. FALSE, // Check final install directory space
  2594. QuickTest,
  2595. AdditionalPadding
  2596. );
  2597. if( CheckResult == NOT_ENOUGH_SPACE ) {
  2598. if (SystemPartitionDriveLetter) {
  2599. if (!QuickTest) {
  2600. DebugLog(
  2601. Winnt32LogInformation,
  2602. NULL,
  2603. MSG_LOG_SYSTEM_PARTITION_TOO_SMALL,
  2604. SystemPartitionDriveLetter,
  2605. AvailableMb,
  2606. RequiredMb
  2607. );
  2608. }
  2609. } else {
  2610. #ifdef UNICODE
  2611. if (!QuickTest) {
  2612. DebugLog(
  2613. Winnt32LogInformation,
  2614. NULL,
  2615. MSG_LOG_SYSTEM_PARTITION_TOO_SMALL2,
  2616. SystemPartitionNtName,
  2617. AvailableMb,
  2618. RequiredMb
  2619. );
  2620. }
  2621. #endif
  2622. }
  2623. if( BlockOnNotEnoughSpace) {
  2624. if (!QuickTest) {
  2625. //
  2626. // We're dead and the user asked us to stop if we
  2627. // can't fit, so put up a dialog telling him that
  2628. // he needs more room on the system partition.
  2629. //
  2630. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  2631. if (SystemPartitionDriveLetter) {
  2632. MessageBoxFromMessage(
  2633. hdlg,
  2634. MSG_SYSTEM_PARTITION_TOO_SMALL,
  2635. FALSE,
  2636. AppTitleStringId,
  2637. MB_OK | MB_ICONWARNING,
  2638. SystemPartitionDriveLetter,
  2639. RequiredMb
  2640. );
  2641. } else {
  2642. #ifdef UNICODE
  2643. MessageBoxFromMessage(
  2644. hdlg,
  2645. MSG_SYSTEM_PARTITION_TOO_SMALL2,
  2646. FALSE,
  2647. AppTitleStringId,
  2648. MB_OK | MB_ICONWARNING,
  2649. SystemPartitionNtName,
  2650. RequiredMb
  2651. );
  2652. #endif
  2653. }
  2654. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  2655. }
  2656. return( FALSE );
  2657. }
  2658. } else if( (CheckResult == INVALID_DRIVE) || (CheckResult == DRIVE_UNKNOWN) ) {
  2659. if (!QuickTest) {
  2660. if (SystemPartitionDriveLetter) {
  2661. DebugLog(
  2662. Winnt32LogInformation,
  2663. NULL,
  2664. MSG_LOG_SYSTEM_PARTITION_INVALID,
  2665. SystemPartitionDriveLetter
  2666. );
  2667. } else {
  2668. #ifdef UNICODE
  2669. DebugLog(
  2670. Winnt32LogInformation,
  2671. NULL,
  2672. MSG_LOG_SYSTEM_PARTITION_INVALID2,
  2673. SystemPartitionNtName
  2674. );
  2675. #endif
  2676. }
  2677. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  2678. MessageBoxFromMessage(
  2679. hdlg,
  2680. MSG_SYSTEM_PARTITION_INVALID,
  2681. FALSE,
  2682. AppTitleStringId,
  2683. MB_OK | MB_ICONERROR | MB_TASKMODAL
  2684. );
  2685. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  2686. }
  2687. return( FALSE );
  2688. } else if( CheckResult == VALID_DRIVE ) {
  2689. if (!QuickTest) {
  2690. if (SystemPartitionDriveLetter) {
  2691. DebugLog(
  2692. Winnt32LogInformation,
  2693. NULL,
  2694. MSG_LOG_SYSTEM_PARTITION_VALID,
  2695. SystemPartitionDriveLetter
  2696. );
  2697. } else {
  2698. #ifdef UNICODE
  2699. DebugLog(
  2700. Winnt32LogInformation,
  2701. NULL,
  2702. MSG_LOG_SYSTEM_PARTITION_VALID2,
  2703. SystemPartitionNtName
  2704. );
  2705. #endif
  2706. }
  2707. }
  2708. }
  2709. }
  2710. //
  2711. // ====================================================
  2712. // Check space for the final installation directory.
  2713. // ====================================================
  2714. //
  2715. if( Upgrade ) {
  2716. TCHAR Text[MAX_PATH];
  2717. MinDiskSpaceRequired = 0x7FFFFFFF,
  2718. MaxDiskSpaceRequired = 0;
  2719. if (!QuickTest) {
  2720. DebugLog( Winnt32LogInformation,
  2721. TEXT( "\r\n\r\nExamining disk for adequate space expand the WinDir.\r\n"),
  2722. 0 );
  2723. }
  2724. //
  2725. // Just check the drive where the current installation is.
  2726. //
  2727. MyGetWindowsDirectory( Text, MAX_PATH );
  2728. WinntDriveLetter = Text[0];
  2729. CheckResult = CheckASingleDrive(
  2730. WinntDriveLetter,
  2731. NULL,
  2732. &ClusterSize,
  2733. &RequiredMb,
  2734. &AvailableMb,
  2735. ((WinntDriveLetter == SystemPartitionDriveLetter) && MakeBootSource),
  2736. FALSE,
  2737. TRUE,
  2738. QuickTest,
  2739. AdditionalPadding
  2740. );
  2741. if( CheckResult == NOT_ENOUGH_SPACE ) {
  2742. if (!QuickTest) {
  2743. DebugLog( Winnt32LogInformation,
  2744. NULL,
  2745. MSG_LOG_INSTALL_DRIVE_TOO_SMALL,
  2746. WinntDriveLetter,
  2747. AvailableMb,
  2748. RequiredMb );
  2749. }
  2750. //
  2751. // If the BlockOnNotEnoughSpace flag is set, then we
  2752. // will throw up a message box and exit setup.
  2753. //
  2754. if (BlockOnNotEnoughSpace) {
  2755. if (!QuickTest) {
  2756. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  2757. MessageBoxFromMessage(
  2758. hdlg,
  2759. MSG_INSTALL_DRIVE_TOO_SMALL,
  2760. FALSE,
  2761. AppTitleStringId,
  2762. MB_OK | MB_ICONWARNING,
  2763. RequiredMb
  2764. );
  2765. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  2766. }
  2767. return( FALSE );
  2768. }
  2769. } else if( (CheckResult == INVALID_DRIVE) || (CheckResult == DRIVE_UNKNOWN) ) {
  2770. if (!QuickTest) {
  2771. DebugLog( Winnt32LogInformation,
  2772. NULL,
  2773. MSG_LOG_INSTALL_DRIVE_INVALID,
  2774. WinntDriveLetter );
  2775. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  2776. MessageBoxFromMessage(
  2777. hdlg,
  2778. MSG_INSTALL_DRIVE_INVALID,
  2779. FALSE,
  2780. AppTitleStringId,
  2781. MB_OK | MB_ICONWARNING,
  2782. RequiredMb
  2783. );
  2784. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  2785. }
  2786. return( FALSE );
  2787. } else if( CheckResult == VALID_DRIVE ) {
  2788. //
  2789. // We need to make one more check here. If the user
  2790. // is upgrading a Domain Controller, then he'll likely
  2791. // need another 250Mb of disk space for DCPROMO to run
  2792. // post gui-mode setup. We need to check for that space
  2793. // here. If we don't have it, we need to warn the user.
  2794. // Note that we're only going to warn.
  2795. //
  2796. // Also note that we're only going to do this *IF* we
  2797. // would have and enough disk space w/o this check.
  2798. //
  2799. if( (ISDC()) &&
  2800. ((RequiredMb + 250) > AvailableMb) &&
  2801. !QuickTest) {
  2802. int i;
  2803. i = MessageBoxFromMessage(
  2804. hdlg,
  2805. MSG_DCPROMO_DISKSPACE,
  2806. FALSE,
  2807. AppTitleStringId,
  2808. MB_OKCANCEL | MB_ICONEXCLAMATION,
  2809. ((RequiredMb + 250) - AvailableMb) + 1 );
  2810. if( i == IDCANCEL ) {
  2811. return( FALSE );
  2812. }
  2813. }
  2814. if (!QuickTest) {
  2815. //
  2816. // Log that we a drive suitable for the install directory.
  2817. //
  2818. DebugLog( Winnt32LogInformation,
  2819. NULL,
  2820. MSG_LOG_INSTALL_DRIVE_OK,
  2821. WinntDriveLetter );
  2822. }
  2823. }
  2824. }
  2825. //
  2826. // ====================================================
  2827. // Check space for the local source (i.e. the ~LS directory).
  2828. // ====================================================
  2829. //
  2830. if( MakeLocalSource ) {
  2831. MinDiskSpaceRequired = 0x7FFFFFFF,
  2832. MaxDiskSpaceRequired = 0;
  2833. if (!QuickTest) {
  2834. DebugLog( Winnt32LogInformation,
  2835. TEXT( "\r\n\r\nExamining Disks for adequate space for temporary setup files.\r\n"),
  2836. 0 );
  2837. }
  2838. if( UserSpecifiedLocalSourceDrive ) {
  2839. //
  2840. // Just check the drive that the user chose.
  2841. //
  2842. CheckResult = CheckASingleDrive(
  2843. UserSpecifiedLocalSourceDrive,
  2844. NULL,
  2845. &ClusterSize,
  2846. &RequiredMb,
  2847. &AvailableMb,
  2848. ((UserSpecifiedLocalSourceDrive == SystemPartitionDriveLetter) && MakeBootSource),
  2849. TRUE, // Check local source space
  2850. (UserSpecifiedLocalSourceDrive == WinntDriveLetter), // Check final install directory space.
  2851. QuickTest,
  2852. AdditionalPadding
  2853. );
  2854. if( CheckResult == NOT_ENOUGH_SPACE ) {
  2855. MinDiskSpaceRequired = RequiredMb - 1;
  2856. MaxDiskSpaceRequired = RequiredMb + 1;
  2857. if (!QuickTest) {
  2858. DebugLog( Winnt32LogInformation,
  2859. NULL,
  2860. MSG_LOG_LOCAL_SOURCE_TOO_SMALL,
  2861. UserSpecifiedLocalSourceDrive,
  2862. AvailableMb,
  2863. RequiredMb );
  2864. }
  2865. if( BlockOnNotEnoughSpace) {
  2866. //
  2867. // We're dead and the user asked us to stop if we
  2868. // can't fit, so put up a dialog telling him that
  2869. // he needs more room.
  2870. //
  2871. if (!QuickTest) {
  2872. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  2873. MessageBoxFromMessage(
  2874. hdlg,
  2875. MSG_USER_LOCAL_SOURCE_TOO_SMALL,
  2876. FALSE,
  2877. AppTitleStringId,
  2878. MB_OK | MB_ICONWARNING,
  2879. UserSpecifiedLocalSourceDrive,
  2880. (DWORD)MaxDiskSpaceRequired );
  2881. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  2882. }
  2883. return( FALSE );
  2884. } else {
  2885. MyLocalSourceDrive = UserSpecifiedLocalSourceDrive;
  2886. }
  2887. } else if( (CheckResult == INVALID_DRIVE) || (CheckResult == DRIVE_UNKNOWN) ) {
  2888. if (!QuickTest) {
  2889. DebugLog( Winnt32LogInformation,
  2890. NULL,
  2891. MSG_LOG_LOCAL_SOURCE_INVALID,
  2892. UserSpecifiedLocalSourceDrive );
  2893. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  2894. MessageBoxFromMessage(
  2895. hdlg,
  2896. MSG_USER_LOCAL_SOURCE_INVALID,
  2897. FALSE,
  2898. AppTitleStringId,
  2899. MB_OK | MB_ICONWARNING,
  2900. UserSpecifiedLocalSourceDrive
  2901. );
  2902. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  2903. }
  2904. return( FALSE );
  2905. } else if( CheckResult == VALID_DRIVE ) {
  2906. if (!QuickTest) {
  2907. DebugLog( Winnt32LogInformation,
  2908. NULL,
  2909. MSG_LOG_LOCAL_SOURCE_VALID,
  2910. UserSpecifiedLocalSourceDrive );
  2911. }
  2912. MyLocalSourceDrive = UserSpecifiedLocalSourceDrive;
  2913. }
  2914. } else {
  2915. //
  2916. // Check all drives.
  2917. //
  2918. for( DriveLetter = TEXT('A'); DriveLetter <= TEXT('Z'); DriveLetter++ ) {
  2919. CheckResult = CheckASingleDrive(
  2920. DriveLetter,
  2921. NULL,
  2922. &ClusterSize,
  2923. &RequiredMb,
  2924. &AvailableMb,
  2925. ((DriveLetter == SystemPartitionDriveLetter) && MakeBootSource),
  2926. TRUE, // Check local source space
  2927. (DriveLetter == WinntDriveLetter), // Check final install directory space.
  2928. QuickTest,
  2929. AdditionalPadding
  2930. );
  2931. if( CheckResult == NOT_ENOUGH_SPACE ) {
  2932. DWORD Size;
  2933. DWORD_PTR my_args[3];
  2934. TCHAR Text0[2048];
  2935. if( MinDiskSpaceRequired > RequiredMb )
  2936. MinDiskSpaceRequired = RequiredMb;
  2937. if( MaxDiskSpaceRequired < RequiredMb )
  2938. MaxDiskSpaceRequired = RequiredMb;
  2939. if (!QuickTest) {
  2940. //
  2941. // Log that we failed the check of this
  2942. // drive for the local source files.
  2943. //
  2944. DebugLog( Winnt32LogInformation,
  2945. NULL,
  2946. MSG_LOG_LOCAL_SOURCE_TOO_SMALL,
  2947. DriveLetter,
  2948. AvailableMb,
  2949. RequiredMb );
  2950. //
  2951. // Log it to a buffer too.
  2952. //
  2953. my_args[0] = DriveLetter;
  2954. my_args[1] = AvailableMb;
  2955. my_args[2] = RequiredMb;
  2956. Size = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  2957. hInst,
  2958. MSG_LOG_LOCAL_SOURCE_TOO_SMALL,
  2959. 0,
  2960. Text0,
  2961. ARRAYSIZE(Text0),
  2962. (va_list *)my_args );
  2963. StringCchCat (DiskDiagMessage, ARRAYSIZE(DiskDiagMessage), Text0 );
  2964. }
  2965. } else if( CheckResult == INVALID_DRIVE ) {
  2966. if (!QuickTest) {
  2967. DWORD Size;
  2968. DWORD_PTR my_args[1];
  2969. TCHAR Text0[2048];
  2970. DebugLog( Winnt32LogInformation,
  2971. NULL,
  2972. MSG_LOG_LOCAL_SOURCE_INVALID,
  2973. DriveLetter );
  2974. //
  2975. // Log it to a buffer too.
  2976. //
  2977. my_args[0] = DriveLetter;
  2978. Size = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  2979. hInst,
  2980. MSG_LOG_LOCAL_SOURCE_INVALID,
  2981. 0,
  2982. Text0,
  2983. ARRAYSIZE(Text0),
  2984. (va_list *)my_args );
  2985. StringCchCat (DiskDiagMessage, ARRAYSIZE(DiskDiagMessage), Text0 );
  2986. }
  2987. } else if( CheckResult == VALID_DRIVE ) {
  2988. if (!QuickTest) {
  2989. DebugLog( Winnt32LogInformation,
  2990. NULL,
  2991. MSG_LOG_LOCAL_SOURCE_VALID,
  2992. DriveLetter );
  2993. }
  2994. MyLocalSourceDrive = DriveLetter;
  2995. break;
  2996. }
  2997. }
  2998. //
  2999. // See if we got it. We can't bypass this failure even
  3000. // if the user has cleared BlockOnNotEnoughSpace because
  3001. // we absolutely have to have a place to put local files.
  3002. // The user can always get around this by either installing
  3003. // from CD, or using /tempdrive and clearing BlockOnNotEnoughSpace.
  3004. //
  3005. if( MyLocalSourceDrive == 0 ) {
  3006. //
  3007. // We failed. Error-out.
  3008. //
  3009. //
  3010. // Just so we don't look bad...
  3011. //
  3012. if( MinDiskSpaceRequired == MaxDiskSpaceRequired ) {
  3013. MaxDiskSpaceRequired += 10;
  3014. }
  3015. if( MinDiskSpaceRequired > MaxDiskSpaceRequired ) {
  3016. MinDiskSpaceRequired = 300;
  3017. MaxDiskSpaceRequired = 500;
  3018. }
  3019. if (!QuickTest) {
  3020. if( CheckUpgradeOnly ) {
  3021. //
  3022. // Just catch the message for the compatibility list.
  3023. //
  3024. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  3025. MessageBoxFromMessage(
  3026. hdlg,
  3027. MSG_NO_VALID_LOCAL_SOURCE,
  3028. FALSE,
  3029. AppTitleStringId,
  3030. MB_OK | MB_ICONWARNING,
  3031. (DWORD)MinDiskSpaceRequired,
  3032. (DWORD)MaxDiskSpaceRequired );
  3033. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  3034. } else {
  3035. //
  3036. // Put up a detailed dialog.
  3037. //
  3038. DialogBox( hInst,
  3039. MAKEINTRESOURCE(IDD_DISKSPACE),
  3040. hdlg,
  3041. DiskDlgProc );
  3042. }
  3043. }
  3044. return( FALSE );
  3045. }
  3046. }
  3047. //
  3048. // If we get here, then we found room for all our
  3049. // needs. Set up some globals.
  3050. //
  3051. LocalSourceDrive = MyLocalSourceDrive;
  3052. LocalSourceDriveOffset = MyLocalSourceDrive - TEXT('A');
  3053. LocalSourceDirectory[0] = MyLocalSourceDrive;
  3054. LocalSourceDirectory[1] = TEXT(':');
  3055. LocalSourceDirectory[2] = TEXT('\\');
  3056. LocalSourceDirectory[3] = 0;
  3057. if (!ConcatenatePaths(LocalSourceDirectory,LOCAL_SOURCE_DIR,ARRAYSIZE(LocalSourceDirectory))) {
  3058. MYASSERT (FALSE);
  3059. }
  3060. MYASSERT (ARRAYSIZE(LocalSourceWithPlatform) >= ARRAYSIZE(LocalSourceDirectory));
  3061. lstrcpy(LocalSourceWithPlatform,LocalSourceDirectory);
  3062. if (!GetMainInfValue (TEXT("Miscellaneous"), TEXT("DestinationPlatform"), 0, platform, ARRAYSIZE(platform))) {
  3063. if (!QuickTest) {
  3064. DebugLog( Winnt32LogSevereError,
  3065. NULL,
  3066. MSG_NO_PLATFORM,
  3067. NULL );
  3068. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  3069. MessageBoxFromMessage(
  3070. hdlg,
  3071. MSG_NO_PLATFORM,
  3072. FALSE,
  3073. AppTitleStringId,
  3074. MB_OK | MB_ICONERROR | MB_TASKMODAL
  3075. );
  3076. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  3077. }
  3078. return( FALSE );
  3079. }
  3080. if (!ConcatenatePaths(
  3081. LocalSourceWithPlatform,
  3082. platform,
  3083. ARRAYSIZE(LocalSourceWithPlatform)
  3084. )) {
  3085. MYASSERT (FALSE);
  3086. }
  3087. LocalSourceDriveClusterSize = ClusterSize;
  3088. }
  3089. return( TRUE );
  3090. }
  3091. DWORD
  3092. CopyWorkerThread(
  3093. IN PVOID ThreadParameter
  3094. )
  3095. /*++
  3096. Routine Description:
  3097. Thread routine to copy files. There may be up to MAX_SOURCE_COUNT of
  3098. these threads running simultaneously.
  3099. Access to shared global data is controlled via a critical section, per-
  3100. thread global data is accessed by using the threads "ordinal number" to
  3101. access the appropriate member of the global data array.
  3102. The copy thread treats the copy list as a LIFO queue. Each time the thread
  3103. is ready to copy a file, it dequeues a file from the list. It then tries
  3104. to copy the file. If this fails, a per-thread vector bit is set so that
  3105. this thread doesn't attempt to copy the file again. It then puts the file
  3106. back into the list (at the head) to allow another thread to attempt to copy
  3107. the file.
  3108. Arguments:
  3109. ThreadParameter - this is actually an ordinal number to indicate which
  3110. thread in the "array" of SourceCount threads is currently
  3111. running
  3112. Return Value:
  3113. Ignored.
  3114. --*/
  3115. {
  3116. UINT SourceOrdinal;
  3117. PFIL CopyEntry,Previous;
  3118. HANDLE Events[2];
  3119. DWORD d;
  3120. UINT ThreadBit;
  3121. BOOL Requeue;
  3122. TCHAR TargetFilename[MAX_PATH];
  3123. ULONGLONG SpaceOccupied;
  3124. TCHAR SizeStr[25];
  3125. BOOL bDone = FALSE;
  3126. SourceOrdinal = (UINT)((ULONG_PTR)ThreadParameter);
  3127. ThreadBit = 1 << SourceOrdinal;
  3128. //
  3129. // Both of these are "manual reset" events, so they will remain signalled
  3130. // until we reset them.
  3131. //
  3132. Events[0] = MasterCopyList.ListReadyEvent[SourceOrdinal];
  3133. Events[1] = MasterCopyList.StopCopyingEvent;
  3134. //
  3135. // Wait for user to cancel, for copying to be done, or the file list
  3136. // to become ready/non-empty.
  3137. //
  3138. while(!Cancelled && (WaitForMultipleObjects(2,Events,FALSE,INFINITE) == WAIT_OBJECT_0)) {
  3139. if(Cancelled) {
  3140. break;
  3141. }
  3142. EnterCriticalSection(&MasterCopyList.CriticalSection);
  3143. //
  3144. // Locate the next file that this thread has not yet
  3145. // tried to copy, if any. If the list is completely
  3146. // empty then reset the list ready event.
  3147. //
  3148. for(Previous=NULL, CopyEntry=MasterCopyList.Files;
  3149. CopyEntry && (CopyEntry->ThreadBitmap & ThreadBit);
  3150. Previous=CopyEntry, CopyEntry=CopyEntry->Next) {
  3151. ;
  3152. }
  3153. //
  3154. // If we found an entry unlink it from the list.
  3155. //
  3156. if(CopyEntry) {
  3157. if(Previous) {
  3158. Previous->Next = CopyEntry->Next;
  3159. } else {
  3160. MasterCopyList.Files = CopyEntry->Next;
  3161. }
  3162. } else {
  3163. //
  3164. // No entry for this thread. Enter a state where we're waiting
  3165. // for an entry to be requeued or for copying to be finished.
  3166. //
  3167. ResetEvent(Events[0]);
  3168. }
  3169. LeaveCriticalSection(&MasterCopyList.CriticalSection);
  3170. if(Cancelled) {
  3171. break;
  3172. }
  3173. //
  3174. // If we got a file entry, go ahead and try to copy the file.
  3175. //
  3176. if(CopyEntry) {
  3177. d = CopyOneFile(CopyEntry,SourceOrdinal,TargetFilename,ARRAYSIZE(TargetFilename),&SpaceOccupied);
  3178. #ifdef TEST_EXCEPTION
  3179. DoException( 3);
  3180. #endif
  3181. Requeue = FALSE;
  3182. if(d == NO_ERROR) {
  3183. MasterCopyList.SpaceOccupied[SourceOrdinal] += SpaceOccupied;
  3184. TotalDataCopied += SpaceOccupied;
  3185. } else {
  3186. if (!Cancelled && !(CopyEntry->Flags & FILE_IGNORE_COPY_ERROR)) {
  3187. //
  3188. // Error. If this is the last thread to try to copy the file,
  3189. // then we want to ask the user what to do. Otherwise requeue
  3190. // the file so other copy threads can try to copy it.
  3191. //
  3192. if((CopyEntry->ThreadBitmap | ThreadBit) == (UINT)((1 << SourceCount)-1)) {
  3193. MYASSERT (d != NO_ERROR);
  3194. switch(FileCopyError(MasterCopyList.hdlg,CopyEntry->SourceName,TargetFilename,d,TRUE)) {
  3195. case COPYERR_EXIT:
  3196. //
  3197. // FileCopyError() already set thhe stop-copying event
  3198. // and set Cancelled to TRUE. We do something a little funky now,
  3199. // namely we simulate a press of the cancel button on the wizard
  3200. // so all abnormal terminations go through the same codepath.
  3201. //
  3202. PropSheet_PressButton(GetParent(MasterCopyList.hdlg),PSBTN_CANCEL);
  3203. break;
  3204. case COPYERR_SKIP:
  3205. //
  3206. // Requeue is aready set to FALSE, which will cause code
  3207. // below to tell the main thread that another file is done.
  3208. // Nothing more to do for this case.
  3209. //
  3210. break;
  3211. case COPYERR_RETRY:
  3212. //
  3213. // Wipe the list of threads that have tried to copy the file
  3214. // so all will take another crack at it.
  3215. //
  3216. CopyEntry->ThreadBitmap = 0;
  3217. Requeue = TRUE;
  3218. break;
  3219. }
  3220. } else {
  3221. //
  3222. // Tell ourselves that we've already tried to copy this file
  3223. // and requeue it at the head of the list.
  3224. //
  3225. CopyEntry->ThreadBitmap |= ThreadBit;
  3226. Requeue = TRUE;
  3227. }
  3228. } else {
  3229. DebugLog (
  3230. Winnt32LogWarning,
  3231. TEXT("Error %1!u! copying %2 to %3 - ignored"),
  3232. 0,
  3233. d,
  3234. CopyEntry->SourceName,
  3235. CopyEntry->TargetName
  3236. );
  3237. }
  3238. }
  3239. if(Requeue) {
  3240. EnterCriticalSection(&MasterCopyList.CriticalSection);
  3241. CopyEntry->Next = MasterCopyList.Files;
  3242. MasterCopyList.Files = CopyEntry;
  3243. //
  3244. // Want to set the event for every thread that might be
  3245. // called on to copy this file.
  3246. //
  3247. for(d=0; d<SourceCount; d++) {
  3248. if(!(CopyEntry->ThreadBitmap & (1 << d))) {
  3249. SetEvent(MasterCopyList.ListReadyEvent[d]);
  3250. }
  3251. }
  3252. LeaveCriticalSection(&MasterCopyList.CriticalSection);
  3253. if(Cancelled) {
  3254. break;
  3255. }
  3256. } else {
  3257. //
  3258. // Inform the UI thread that another file is done.
  3259. // Free the copy list entry and decrement the count
  3260. // of files that have been processed. When that number
  3261. // goes to 0, we are done.
  3262. //
  3263. PostMessage(MasterCopyList.hdlg,WMX_COPYPROGRESS,0,0);
  3264. if(CopyEntry->SourceName
  3265. && (CopyEntry->Flags & FILE_NEED_TO_FREE_SOURCENAME)) {
  3266. FREE((PVOID)CopyEntry->SourceName);
  3267. }
  3268. if(CopyEntry->TargetName
  3269. && (CopyEntry->Flags & FILE_NEED_TO_FREE_TARGETNAME)) {
  3270. FREE((PVOID)CopyEntry->TargetName);
  3271. }
  3272. FREE(CopyEntry);
  3273. if(!InterlockedDecrement(&MasterCopyList.FileCount)) {
  3274. SetEvent(MasterCopyList.StopCopyingEvent);
  3275. if (Cancelled) {
  3276. break;
  3277. }
  3278. //
  3279. // Sum up the total space occupied and write it into
  3280. // size.sif in the local source.
  3281. //
  3282. if(MakeLocalSource) {
  3283. SpaceOccupied = 0;
  3284. for(d=0; d<SourceCount; d++) {
  3285. SpaceOccupied += MasterCopyList.SpaceOccupied[d];
  3286. }
  3287. MYASSERT (LocalSourceDirectory[0]);
  3288. if (!BuildPath (
  3289. TargetFilename,
  3290. LocalSourceDirectory,
  3291. TEXT("SIZE.SIF")
  3292. )) {
  3293. MYASSERT (FALSE);
  3294. }
  3295. wsprintf(SizeStr,TEXT("%u"),SpaceOccupied);
  3296. WritePrivateProfileString(TEXT("Data"),TEXT("Size"),SizeStr,TargetFilename);
  3297. WritePrivateProfileString(NULL,NULL,NULL,TargetFilename);
  3298. }
  3299. PostMessage(MasterCopyList.hdlg,WMX_COPYPROGRESS,0,1);
  3300. bDone = TRUE;
  3301. }
  3302. }
  3303. }
  3304. SetDlgItemText(MasterCopyList.hdlg,IDT_SOURCE1+SourceOrdinal,TEXT(""));
  3305. }
  3306. //
  3307. // StopCopyingEvent was set or the user cancelled
  3308. //
  3309. if (bDone && MasterCopyList.ActiveCS) {
  3310. DeleteCriticalSection(&MasterCopyList.CriticalSection);
  3311. MasterCopyList.ActiveCS = FALSE;
  3312. }
  3313. return(0);
  3314. }
  3315. DWORD
  3316. StartCopyingThread(
  3317. IN PVOID ThreadParameter
  3318. )
  3319. /*++
  3320. Routine Description:
  3321. Starts the actual copying of the files in the file list.
  3322. The multi-thread copy works by creating the appropriate synchronization
  3323. events and worker threads, then signals the worker threads to start
  3324. copying. Control returns to the caller, which will receive UI notifications
  3325. from the worker threads.
  3326. Arguments:
  3327. ThreadParameter - Thread context parameter.
  3328. Return Value:
  3329. TRUE\FALSE failure code.
  3330. --*/
  3331. {
  3332. UINT Source;
  3333. DWORD ThreadId;
  3334. HWND hdlg = ThreadParameter;
  3335. MainCopyStarted = FALSE;
  3336. #if defined(_X86_)
  3337. if (!ISNT()) {
  3338. if (MakeLocalSource) {
  3339. //
  3340. // Win9xupg may want to relocate the local source. If so, we need to update the
  3341. // necessary Localsource directories.
  3342. //
  3343. if ((UINT) (LocalSourceDrive - TEXT('A')) != LocalSourceDriveOffset) {
  3344. MYASSERT (LocalSourceDirectory[0]);
  3345. LocalSourceDrive = (TCHAR) (TEXT('A') + LocalSourceDriveOffset);
  3346. LocalSourceDirectory[0] = LocalSourceDrive;
  3347. LocalSourceWithPlatform[0] = LocalSourceDrive;
  3348. }
  3349. }
  3350. }
  3351. #endif
  3352. InitializeCriticalSection(&MasterCopyList.CriticalSection);
  3353. MasterCopyList.ActiveCS = TRUE;
  3354. //
  3355. // Create a manual reset event that will be used to tell the
  3356. // worker threads to terminate.
  3357. //
  3358. MasterCopyList.StopCopyingEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  3359. if(!MasterCopyList.StopCopyingEvent) {
  3360. MessageBoxFromMessageAndSystemError(
  3361. hdlg,
  3362. MSG_CANT_START_COPYING,
  3363. GetLastError(),
  3364. AppTitleStringId,
  3365. MB_OK | MB_ICONWARNING
  3366. );
  3367. goto c1;
  3368. }
  3369. //
  3370. // Create one thread for each source.
  3371. //
  3372. ZeroMemory(MasterCopyList.ListReadyEvent,sizeof(MasterCopyList.ListReadyEvent));
  3373. ZeroMemory(MasterCopyList.Threads,sizeof(MasterCopyList.Threads));
  3374. if( OemPreinstall ) {
  3375. TCHAR TargetFilename[MAX_PATH];
  3376. //
  3377. // Create $win_nt$.~ls\$OEM$
  3378. //
  3379. MYASSERT (LocalSourceDrive);
  3380. TargetFilename[0] = LocalSourceDrive;
  3381. TargetFilename[1] = TEXT(':');
  3382. TargetFilename[2] = TEXT('\\');
  3383. TargetFilename[3] = 0;
  3384. lstrcpyn(TargetFilename+3, LOCAL_SOURCE_DIR, ARRAYSIZE(TargetFilename) - 3);
  3385. if (ConcatenatePaths(TargetFilename, WINNT_OEM_DIR,ARRAYSIZE(TargetFilename))) {
  3386. CreateMultiLevelDirectory( TargetFilename );
  3387. }
  3388. #if defined(_AMD64_) || defined(_X86_)
  3389. //
  3390. // Create $win_nt$.~bt\$OEM$
  3391. //
  3392. if( !IsArc() && MakeBootMedia ) {
  3393. MYASSERT (SystemPartitionDriveLetter);
  3394. TargetFilename[0] = SystemPartitionDriveLetter;
  3395. lstrcpyn(TargetFilename+3, LOCAL_BOOT_DIR, ARRAYSIZE(TargetFilename) - 3);
  3396. if (ConcatenatePaths(TargetFilename, WINNT_OEM_DIR,MAX_PATH)) {
  3397. CreateMultiLevelDirectory( TargetFilename );
  3398. }
  3399. }
  3400. #endif
  3401. }
  3402. for(Source=0; Source<SourceCount; Source++) {
  3403. MasterCopyList.ListReadyEvent[Source] = CreateEvent(NULL,TRUE,FALSE,NULL);
  3404. if(!MasterCopyList.ListReadyEvent[Source]) {
  3405. MessageBoxFromMessageAndSystemError(
  3406. hdlg,
  3407. MSG_CANT_START_COPYING,
  3408. GetLastError(),
  3409. AppTitleStringId,
  3410. MB_OK | MB_ICONWARNING
  3411. );
  3412. goto c2;
  3413. }
  3414. MasterCopyList.hdlg = hdlg;
  3415. MasterCopyList.SpaceOccupied[Source] = 0;
  3416. MasterCopyList.Threads[Source] = CreateThread(
  3417. NULL,
  3418. 0,
  3419. CopyWorkerThread,
  3420. UIntToPtr( Source ),
  3421. 0,
  3422. &ThreadId
  3423. );
  3424. if(!MasterCopyList.Threads[Source]) {
  3425. MessageBoxFromMessageAndSystemError(
  3426. hdlg,
  3427. MSG_CANT_START_COPYING,
  3428. GetLastError(),
  3429. AppTitleStringId,
  3430. MB_OK | MB_ICONWARNING
  3431. );
  3432. goto c2;
  3433. }
  3434. }
  3435. //
  3436. // OK, now signal all the copy threads -- when we tell them that
  3437. // there's something in their lists they will start copying.
  3438. //
  3439. MainCopyStarted = TRUE;
  3440. for(Source=0; Source<SourceCount; Source++) {
  3441. SetEvent(MasterCopyList.ListReadyEvent[Source]);
  3442. }
  3443. return(TRUE);
  3444. c2:
  3445. //
  3446. // Signal threads and wait for them to terminate.
  3447. // This should be real quick since none of them have started copying yet.
  3448. //
  3449. SetEvent(MasterCopyList.StopCopyingEvent);
  3450. WaitForMultipleObjects(Source,MasterCopyList.Threads,TRUE,INFINITE);
  3451. for(Source=0; Source<SourceCount; Source++) {
  3452. if(MasterCopyList.Threads[Source]) {
  3453. CloseHandle(MasterCopyList.Threads[Source]);
  3454. }
  3455. if(MasterCopyList.ListReadyEvent[Source]) {
  3456. CloseHandle(MasterCopyList.ListReadyEvent[Source]);
  3457. }
  3458. }
  3459. CloseHandle(MasterCopyList.StopCopyingEvent);
  3460. c1:
  3461. if (MasterCopyList.ActiveCS) {
  3462. DeleteCriticalSection(&MasterCopyList.CriticalSection);
  3463. }
  3464. ZeroMemory(&MasterCopyList,sizeof(COPY_LIST));
  3465. return(FALSE);
  3466. }
  3467. VOID
  3468. CancelledMakeSureCopyThreadsAreDead(
  3469. VOID
  3470. )
  3471. /*++
  3472. Routine Description:
  3473. This routine can be called after the user cancels setup (which can happen
  3474. via the main cancel button on the wizard, or at a file copy error) to
  3475. ensure that file copy threads have exited.
  3476. It is assumed that whoever handled the cancel request has already set
  3477. the Cancelled flag, and set the StopCopying event. In other words,
  3478. this routine should only be called after the caller has ensured that
  3479. the threads have actually been requested to exit.
  3480. The purpose of this routine is to ensure that the cleanup code is not
  3481. cleaning up files in the local source directory at the same time
  3482. a lingering copy thread is copying its last file.
  3483. Arguments:
  3484. None.
  3485. Return Value:
  3486. None.
  3487. --*/
  3488. {
  3489. if(MainCopyStarted) {
  3490. MainCopyStarted = FALSE;
  3491. WaitForMultipleObjects(SourceCount,MasterCopyList.Threads,TRUE,INFINITE);
  3492. if (MasterCopyList.ActiveCS) {
  3493. //
  3494. // delete the critical section used
  3495. //
  3496. DeleteCriticalSection(&MasterCopyList.CriticalSection);
  3497. }
  3498. ZeroMemory(&MasterCopyList,sizeof(COPY_LIST));
  3499. }
  3500. }
  3501. BOOL
  3502. OurCopyFile (
  3503. IN PCTSTR ActualSource,
  3504. IN PCTSTR TargetFilename,
  3505. IN BOOL FailIfExist
  3506. )
  3507. {
  3508. BOOL b = FALSE;
  3509. DWORD bytes, bw;
  3510. DWORD rc;
  3511. BY_HANDLE_FILE_INFORMATION fi;
  3512. BOOL fiValid = FALSE;
  3513. PVOID buffer = NULL;
  3514. HANDLE hRead = INVALID_HANDLE_VALUE;
  3515. HANDLE hWrite = INVALID_HANDLE_VALUE;
  3516. DWORD attrib = GetFileAttributes (TargetFilename);
  3517. DWORD readSize;
  3518. if (attrib != (DWORD)-1) {
  3519. if (FailIfExist) {
  3520. SetLastError (ERROR_ALREADY_EXISTS);
  3521. return FALSE;
  3522. }
  3523. SetFileAttributes (TargetFilename, FILE_ATTRIBUTE_NORMAL);
  3524. }
  3525. attrib = GetFileAttributes (ActualSource);
  3526. if (attrib == (DWORD)-1) {
  3527. return FALSE;
  3528. }
  3529. hWrite = CreateFile (
  3530. TargetFilename,
  3531. GENERIC_WRITE,
  3532. 0,
  3533. NULL,
  3534. CREATE_ALWAYS,
  3535. attrib | FILE_FLAG_SEQUENTIAL_SCAN,
  3536. NULL
  3537. );
  3538. if (hWrite == INVALID_HANDLE_VALUE) {
  3539. goto exit;
  3540. }
  3541. hRead = CreateFile (
  3542. ActualSource,
  3543. GENERIC_READ,
  3544. FILE_SHARE_READ,
  3545. NULL,
  3546. OPEN_EXISTING,
  3547. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  3548. NULL
  3549. );
  3550. if (hRead == INVALID_HANDLE_VALUE) {
  3551. goto exit;
  3552. }
  3553. readSize = LocalSourceDriveClusterSize;
  3554. if (!readSize) {
  3555. readSize = 8192;
  3556. }
  3557. buffer = MALLOC (readSize);
  3558. if (!buffer) {
  3559. goto exit;
  3560. }
  3561. if (GetFileInformationByHandle (hRead, &fi)) {
  3562. fiValid = TRUE;
  3563. }
  3564. do {
  3565. if (!ReadFile (hRead, buffer, readSize, &bytes, NULL)) {
  3566. goto exit;
  3567. }
  3568. if (bytes) {
  3569. if (!WriteFile (hWrite, buffer, bytes, &bw, NULL) || bytes != bw) {
  3570. goto exit;
  3571. }
  3572. }
  3573. } while (bytes);
  3574. //
  3575. // apply source file attributes and file time stamps
  3576. //
  3577. if (fiValid) {
  3578. SetFileTime (hWrite, &fi.ftCreationTime, &fi.ftLastAccessTime, &fi.ftLastWriteTime);
  3579. }
  3580. b = TRUE;
  3581. exit:
  3582. rc = GetLastError ();
  3583. if (buffer) {
  3584. FREE (buffer);
  3585. }
  3586. if (hWrite != INVALID_HANDLE_VALUE) {
  3587. CloseHandle (hWrite);
  3588. }
  3589. if (hRead != INVALID_HANDLE_VALUE) {
  3590. CloseHandle (hRead);
  3591. }
  3592. SetLastError (rc);
  3593. return b;
  3594. }
  3595. DWORD
  3596. CopyOneFile(
  3597. IN PFIL File,
  3598. IN UINT SourceOrdinal,
  3599. OUT PTSTR TargetFilename,
  3600. IN INT CchTargetFilename,
  3601. OUT ULONGLONG *SpaceOccupied
  3602. )
  3603. /*++
  3604. Routine Description:
  3605. Routine attempts to copy an individual file in the copy queue.
  3606. The routine builds a full source and destination path. After locating
  3607. the source file (we try to optimize the search by remembering if the last
  3608. file was compressed, guessing that if the last file was compressed, the
  3609. current file will be compressed), the file is either decompressed or
  3610. copied.
  3611. Arguments:
  3612. File - pointer to a FIL structure descibing the file to be copied
  3613. SourceOrdinal - specifies the copy thread ordinal
  3614. TargetFilename - receives the file name of the file that was copied.
  3615. CchTargetFilename - specifies the size (in TCHARS) of TargetFilename
  3616. SpaceOccupied - receives the file size of the file
  3617. Return Value:
  3618. Win32 error code indicating outcome. If the call succeeds, NO_ERROR is
  3619. returned and SpaceOccupied will be updated with the size of the copied
  3620. file.
  3621. --*/
  3622. {
  3623. TCHAR SourceFilename[MAX_PATH];
  3624. TCHAR ActualSource[MAX_PATH];
  3625. HANDLE FindHandle;
  3626. WIN32_FIND_DATA FindData;
  3627. BOOL TryCompressedFirst;
  3628. PTCHAR p;
  3629. DWORD d;
  3630. DWORD OldAttributes;
  3631. NAME_AND_SIZE_CAB NameAndSize;
  3632. BOOL UsedAlternate = FALSE;
  3633. BOOL UsedUpdated = FALSE;
  3634. BOOL b = TRUE;
  3635. if (File->Flags & FILE_DO_NOT_COPY) {
  3636. DebugLog (
  3637. Winnt32LogInformation,
  3638. TEXT("Not copying %1"),
  3639. 0,
  3640. File->SourceName
  3641. );
  3642. return NO_ERROR;
  3643. }
  3644. //
  3645. // Form the full source and target names for this file, based on
  3646. // information in the copy list entry and the source we're supposed to
  3647. // be using for this file.
  3648. //
  3649. // Check to see if this directory's path has been tagged
  3650. // as being an absolute path. If so, then we shouldn't
  3651. // tack him onto the end of the SourcePath. Rather, we
  3652. // can just take as he is.
  3653. //
  3654. if( !(File->Flags & FILE_NT_MIGRATE) ) {
  3655. //
  3656. // Generate a path to copy from (source path).
  3657. //
  3658. if (AlternateSourcePath[0] && !(File->Directory->Flags & DIR_DOESNT_SUPPORT_PRIVATES)) {
  3659. //ConcatenatePaths(SourceFilename,File->Directory->SourceName,MAX_PATH);
  3660. if (BuildPath(SourceFilename,AlternateSourcePath, File->SourceName)) {
  3661. UsedAlternate = TRUE;
  3662. } else {
  3663. b = FALSE;
  3664. }
  3665. } else if (DynamicUpdateSuccessful () &&
  3666. g_DynUpdtStatus->UpdatesPath[0] &&
  3667. (File->Directory->Flags & DIR_SUPPORT_DYNAMIC_UPDATE)
  3668. ) {
  3669. //
  3670. // Files in this directory support Dynamic Update
  3671. //
  3672. WIN32_FIND_DATA fd;
  3673. if (BuildPath (SourceFilename, g_DynUpdtStatus->UpdatesPath, File->Directory->SourceName) &&
  3674. ConcatenatePaths (SourceFilename, File->SourceName, ARRAYSIZE(SourceFilename)) &&
  3675. FileExists (SourceFilename, &fd) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3676. UsedUpdated = TRUE;
  3677. DebugLog (
  3678. Winnt32LogInformation,
  3679. NULL,
  3680. MSG_LOG_USE_UPDATED,
  3681. SourceFilename,
  3682. File->SourceName,
  3683. SourceOrdinal
  3684. );
  3685. }
  3686. }
  3687. if (!(UsedAlternate || UsedUpdated)) {
  3688. if( File->Directory->Flags & DIR_ABSOLUTE_PATH ) {
  3689. b = BuildPath (SourceFilename, File->Directory->SourceName, File->SourceName) != NULL;
  3690. } else {
  3691. b = BuildPath (SourceFilename,SourcePaths[SourceOrdinal], File->Directory->SourceName) != NULL &&
  3692. ConcatenatePaths (SourceFilename, File->SourceName, ARRAYSIZE(SourceFilename));
  3693. }
  3694. }
  3695. } else {
  3696. b = MyGetWindowsDirectory (SourceFilename, ARRAYSIZE(SourceFilename)) > 0 &&
  3697. ConcatenatePaths (SourceFilename, File->Directory->SourceName, ARRAYSIZE(SourceFilename));
  3698. ConcatenatePaths (SourceFilename, File->SourceName, ARRAYSIZE(SourceFilename));
  3699. }
  3700. if (!b) {
  3701. DebugLog (Winnt32LogError, TEXT("Filename too long: [%1\\%2]"), 0, AlternateSourcePath, File->SourceName);
  3702. return ERROR_INSUFFICIENT_BUFFER;
  3703. }
  3704. //
  3705. // generate a target path
  3706. //
  3707. b = TRUE;
  3708. if( !(File->Flags & FILE_NT_MIGRATE) ) {
  3709. #if defined(REMOTE_BOOT)
  3710. if(File->Flags & FILE_ON_MACHINE_DIRECTORY_ROOT) {
  3711. MYASSERT(RemoteBoot);
  3712. b = SUCCEEDED (StringCchCopy (TargetFilename, CchTargetFilename, MachineDirectory));
  3713. } else
  3714. #endif // defined(REMOTE_BOOT)
  3715. if(File->Flags & FILE_ON_SYSTEM_PARTITION_ROOT) {
  3716. #if defined(REMOTE_BOOT)
  3717. if (RemoteBoot) {
  3718. b = MyGetWindowsDirectory(TargetFilename,ARRAYSIZE(TargetFilename));
  3719. if (b) {
  3720. TargetFilename[3] = 0;
  3721. }
  3722. } else
  3723. #endif // defined(REMOTE_BOOT)
  3724. {
  3725. b = BuildSystemPartitionPathToFile (TEXT(""), TargetFilename, CchTargetFilename);
  3726. }
  3727. } else {
  3728. if(File->Flags & FILE_IN_LOCAL_BOOT) {
  3729. b = SUCCEEDED (StringCchCopy (
  3730. TargetFilename,
  3731. CchTargetFilename,
  3732. IsArc() ? LocalSourceWithPlatform : LocalBootDirectory
  3733. ));
  3734. if (b && (File->Directory->Flags & DIR_USE_SUBDIR)) {
  3735. b = ConcatenatePaths(TargetFilename,File->Directory->TargetName, CchTargetFilename);
  3736. }
  3737. } else {
  3738. MYASSERT (LocalSourceDirectory[0]);
  3739. if(File->Flags & FILE_IN_PLATFORM_INDEPEND_DIR) {
  3740. b = SUCCEEDED (StringCchCopy (
  3741. TargetFilename,
  3742. CchTargetFilename,
  3743. LocalSourceDirectory));
  3744. } else {
  3745. b = SUCCEEDED (StringCchCopy (
  3746. TargetFilename,
  3747. CchTargetFilename,
  3748. LocalSourceWithPlatform));
  3749. }
  3750. b = b && ConcatenatePaths(TargetFilename,File->Directory->TargetName,CchTargetFilename);
  3751. }
  3752. }
  3753. } else {
  3754. b = SUCCEEDED (StringCchCopy (
  3755. TargetFilename,
  3756. CchTargetFilename,
  3757. IsArc() ? LocalSourceWithPlatform : LocalBootDirectory));
  3758. }
  3759. b = b && ConcatenatePaths(TargetFilename,File->TargetName,CchTargetFilename);
  3760. if (!b) {
  3761. DebugLog (Winnt32LogError, TEXT("Buffer too small for full dest path of [%1]"), 0, File->TargetName);
  3762. return ERROR_INSUFFICIENT_BUFFER;
  3763. }
  3764. //
  3765. // We have the full source and destination paths. Try to do the actual copy.
  3766. //
  3767. try_again:
  3768. SetDlgItemText(
  3769. MasterCopyList.hdlg,
  3770. IDT_SOURCE1+SourceOrdinal,
  3771. _tcsrchr(TargetFilename,TEXT('\\')) + 1
  3772. );
  3773. //
  3774. // Now see if the file can be located on the server with the compressed
  3775. // form of the name or the name itself, depending on which was successful
  3776. // last time.
  3777. //
  3778. TryCompressedFirst = (File->Flags & FILE_NT_MIGRATE) || UsedUpdated ? FALSE : (TlsGetValue(TlsIndex) != 0);
  3779. if(TryCompressedFirst) {
  3780. GenerateCompressedName(SourceFilename,ActualSource);
  3781. FindHandle = FindFirstFile(ActualSource,&FindData);
  3782. if(FindHandle && (FindHandle != INVALID_HANDLE_VALUE)) {
  3783. //
  3784. // Got the file, leave the name in ActualSource.
  3785. //
  3786. FindClose(FindHandle);
  3787. } else {
  3788. //
  3789. // Don't have the file, try the actual filename.
  3790. // If that works then remember the name in ActualSource.
  3791. //
  3792. FindHandle = FindFirstFile(SourceFilename,&FindData);
  3793. if(FindHandle && (FindHandle != INVALID_HANDLE_VALUE)) {
  3794. FindClose(FindHandle);
  3795. MYASSERT (ARRAYSIZE(ActualSource) >= ARRAYSIZE(SourceFilename));
  3796. lstrcpy(ActualSource,SourceFilename);
  3797. TryCompressedFirst = FALSE;
  3798. } else {
  3799. ActualSource[0] = 0;
  3800. }
  3801. }
  3802. } else {
  3803. FindHandle = FindFirstFile(SourceFilename,&FindData);
  3804. if(FindHandle != INVALID_HANDLE_VALUE) {
  3805. //
  3806. // Found it -- remember the name in ActualSource.
  3807. //
  3808. FindClose(FindHandle);
  3809. MYASSERT (ARRAYSIZE(ActualSource) >= ARRAYSIZE(SourceFilename));
  3810. lstrcpy(ActualSource,SourceFilename);
  3811. } else {
  3812. //
  3813. // Try the compressed-form name.
  3814. //
  3815. GenerateCompressedName(SourceFilename,ActualSource);
  3816. FindHandle = FindFirstFile(ActualSource,&FindData);
  3817. if(FindHandle != INVALID_HANDLE_VALUE) {
  3818. TryCompressedFirst = TRUE;
  3819. FindClose(FindHandle);
  3820. } else {
  3821. //
  3822. // Couldn't find the compressed form name either.
  3823. // Indicate failure.
  3824. //
  3825. ActualSource[0] = 0;
  3826. }
  3827. }
  3828. }
  3829. //
  3830. // At this point ActualSource[0] is 0 if we couldn't find the file.
  3831. //
  3832. if(!ActualSource[0]) {
  3833. if (UsedAlternate) {
  3834. if( File->Directory->Flags & DIR_ABSOLUTE_PATH ) {
  3835. b = BuildPath( SourceFilename, File->Directory->SourceName,File->SourceName) != NULL;
  3836. } else {
  3837. b = BuildPath( SourceFilename,SourcePaths[SourceOrdinal],File->Directory->SourceName) != NULL &&
  3838. ConcatenatePaths(SourceFilename,File->SourceName,ARRAYSIZE(SourceFilename));
  3839. }
  3840. if (!b) {
  3841. DebugLog (Winnt32LogError, TEXT("Buffer too small for full source path of [%1]"), 0, File->SourceName);
  3842. return ERROR_INSUFFICIENT_BUFFER;
  3843. }
  3844. UsedAlternate = FALSE;
  3845. goto try_again;
  3846. }
  3847. return(ERROR_FILE_NOT_FOUND);
  3848. }
  3849. if( !(File->Flags & FILE_NT_MIGRATE) && !UsedUpdated ) {
  3850. TlsSetValue(TlsIndex, UIntToPtr( TryCompressedFirst ) );
  3851. }
  3852. if(TryCompressedFirst && (File->Flags & FILE_PRESERVE_COMPRESSED_NAME)) {
  3853. //
  3854. // Opened the compressed form of the source name, so use
  3855. // a compressed form of the target name. Note that we're not
  3856. // using the SourceFilename buffer anymore, so we use it
  3857. // as temporary storage.
  3858. //
  3859. GenerateCompressedName(TargetFilename,SourceFilename);
  3860. if (FAILED (StringCchCopy(TargetFilename,CchTargetFilename,SourceFilename))) {
  3861. MYASSERT (FALSE);
  3862. DebugLog (Winnt32LogError, TEXT("Buffer too small for full source path of [%1]"), 0, SourceFilename);
  3863. return ERROR_INSUFFICIENT_BUFFER;
  3864. }
  3865. }
  3866. //
  3867. // Now go ahead and try to actually *copy* the file (gasp!)
  3868. // To overcome net glitches, we retry once automatically.
  3869. //
  3870. // As a small touch, we try to preserve file attributes for files
  3871. // that already exist on the system partition root. In other words
  3872. // for a file like ntldr, if the user removed say RHS attribs
  3873. // we try to leave it that way.
  3874. //
  3875. *(p = _tcsrchr(TargetFilename,TEXT('\\'))) = 0;
  3876. d = CreateMultiLevelDirectory(TargetFilename);
  3877. *p = TEXT('\\');
  3878. if(d != NO_ERROR) {
  3879. DebugLog(Winnt32LogError,NULL,MSG_LOG_COPY_ERR,ActualSource,TargetFilename,SourceOrdinal,d);
  3880. return(d);
  3881. }
  3882. OldAttributes = (File->Flags & FILE_ON_SYSTEM_PARTITION_ROOT)
  3883. ? GetFileAttributes(TargetFilename)
  3884. : (DWORD)(-1);
  3885. SetFileAttributes(TargetFilename,FILE_ATTRIBUTE_NORMAL);
  3886. //
  3887. // ISSUE: the condition below is never TRUE because the flag FILE_DECOMPRESS
  3888. // is never set. Besides, even if this was true, decompression would actually
  3889. // fail on NT4 systems (because setupapi didn't support LZX compression)
  3890. //
  3891. #if 0
  3892. if(TryCompressedFirst && (File->Flags & FILE_DECOMPRESS)) {
  3893. //
  3894. // File existed with its compressed-form name and
  3895. // we want to decompress it. Do that now, bypassing the usual
  3896. // filecopy logic below.
  3897. //
  3898. NameAndSize.Name = TargetFilename;
  3899. NameAndSize.Size = 0;
  3900. if(!SetupapiCabinetRoutine(ActualSource,0,DiamondCallback,&NameAndSize)) {
  3901. d = GetLastError();
  3902. DebugLog(Winnt32LogError,NULL,MSG_LOG_DECOMP_ERR,ActualSource,TargetFilename,SourceOrdinal,d);
  3903. return(d);
  3904. }
  3905. //
  3906. // Adjust file size so disk space checks are accurate
  3907. //
  3908. FindData.nFileSizeLow = LOULONG(NameAndSize.Size);
  3909. FindData.nFileSizeHigh = HIULONG(NameAndSize.Size);
  3910. } else {
  3911. #endif
  3912. if(!CopyFile(ActualSource,TargetFilename,FALSE)) {
  3913. Sleep(500);
  3914. if(!CopyFile(ActualSource,TargetFilename,FALSE)) {
  3915. //
  3916. // workaround for Win9x system bug: sometimes it fails to copy some files
  3917. // use our own copy routine
  3918. //
  3919. if (!OurCopyFile (ActualSource,TargetFilename,FALSE)) {
  3920. d = GetLastError();
  3921. DebugLog(Winnt32LogError,NULL,MSG_LOG_COPY_ERR,ActualSource,TargetFilename,SourceOrdinal,d);
  3922. return(d);
  3923. } else {
  3924. #ifdef PRERELEASE
  3925. //
  3926. // log this info; at least we can track it and maybe we can find what's causing this
  3927. //
  3928. DebugLog(Winnt32LogWarning,TEXT("File %1 was successfully copied to %2 using OurCopyFile"),0,ActualSource,TargetFilename);
  3929. #endif
  3930. }
  3931. }
  3932. }
  3933. #if 0
  3934. }
  3935. #endif
  3936. if(OldAttributes != (DWORD)(-1)) {
  3937. //
  3938. // API does nothing with the compression flag; strip it out.
  3939. //
  3940. SetFileAttributes(TargetFilename,OldAttributes & ~FILE_ATTRIBUTE_COMPRESSED);
  3941. }
  3942. DebugLog(Winnt32LogInformation,NULL,MSG_LOG_COPY_OK,ActualSource,TargetFilename,SourceOrdinal);
  3943. //
  3944. // Track size occupied on local source drive.
  3945. //
  3946. if( (LocalSourceDrive) &&
  3947. (MakeLocalSource) &&
  3948. ( (SystemPartitionDriveLetter == LocalSourceDrive) ||
  3949. !(File->Flags & (FILE_ON_SYSTEM_PARTITION_ROOT | FILE_IN_LOCAL_BOOT))) ) {
  3950. DWORD Adjuster;
  3951. ULONGLONG Value;
  3952. Value = MAKEULONGLONG(0,FindData.nFileSizeHigh);
  3953. Adjuster = ((FindData.nFileSizeLow % LocalSourceDriveClusterSize) != 0);
  3954. Value += LocalSourceDriveClusterSize * ((FindData.nFileSizeLow/LocalSourceDriveClusterSize)+Adjuster);
  3955. *SpaceOccupied = Value;
  3956. }
  3957. return(NO_ERROR);
  3958. }
  3959. UINT
  3960. GetTotalFileCount(
  3961. VOID
  3962. )
  3963. {
  3964. return(MasterCopyList.FileCount);
  3965. }
  3966. UINT
  3967. FileCopyError(
  3968. IN HWND ParentWindow,
  3969. IN LPCTSTR SourceFilename,
  3970. IN LPCTSTR TargetFilename,
  3971. IN UINT Win32Error,
  3972. IN BOOL MasterList
  3973. )
  3974. /*++
  3975. Routine Description:
  3976. This routine handles file copy errors, presenting them to the user
  3977. for dispensation (skip, retry, exit).
  3978. Arguments:
  3979. ParentWindow - supplies window handle of window to be used as parent
  3980. for the dialog that this routine displays.
  3981. SourceFilename - supplies name of file that could not be copied.
  3982. Only the final component of this name is used.
  3983. TargetFilename - supplies the target filename for the file. This should
  3984. be a fully qualified win32 path.
  3985. Win32Error - supplies win32 error code that indicated reason for failure.
  3986. MasterList - supplies a flag indicating whether the file being copied
  3987. was on the master list or was just an individual file. If TRUE,
  3988. copy errors are serialized and the master copy list stop copying event
  3989. is set if the user chooses to cancel.
  3990. Return Value:
  3991. One of COPYERR_SKIP, COPYERR_EXIT, or COPYERR_RETRY.
  3992. --*/
  3993. {
  3994. UINT u;
  3995. HANDLE Events[2];
  3996. COPY_ERR_DLG_PARAMS CopyErrDlgParams;
  3997. LPCTSTR p;
  3998. if(AutoSkipMissingFiles) {
  3999. if(p = _tcsrchr(SourceFilename,TEXT('\\'))) {
  4000. p++;
  4001. } else {
  4002. p = SourceFilename;
  4003. }
  4004. DebugLog(Winnt32LogWarning,NULL,MSG_LOG_SKIPPED_FILE,p);
  4005. return(COPYERR_SKIP);
  4006. }
  4007. //
  4008. // Multiple threads can potentially enter this routine simultaneously
  4009. // but we only want a single error dialog up at once. Because each copy
  4010. // thread is independent of the main thread running the wizard/ui,
  4011. // we can block here. But we also need to wake up if the user cancels
  4012. // copying from another thread, so we want on the stop copying event also.
  4013. //
  4014. if(MasterList) {
  4015. Events[0] = UiMutex;
  4016. Events[1] = MasterCopyList.StopCopyingEvent;
  4017. u = WaitForMultipleObjects(2,Events,FALSE,INFINITE);
  4018. if(Cancelled || (u != WAIT_OBJECT_0)) {
  4019. //
  4020. // Stop copying event. This means that some other thread is cancelling
  4021. // setup. We just return skip since we don't need an extra guy running
  4022. // around processing an exit request.
  4023. //
  4024. return(COPYERR_SKIP);
  4025. }
  4026. }
  4027. //
  4028. // OK, put up the actual UI.
  4029. //
  4030. CopyErrDlgParams.Win32Error = Win32Error;
  4031. CopyErrDlgParams.SourceFilename = SourceFilename;
  4032. CopyErrDlgParams.TargetFilename = TargetFilename;
  4033. u = (UINT)DialogBoxParam(
  4034. hInst,
  4035. MAKEINTRESOURCE(IDD_COPYERROR),
  4036. ParentWindow,
  4037. CopyErrDlgProc,
  4038. (LPARAM)&CopyErrDlgParams
  4039. );
  4040. if(u == COPYERR_EXIT) {
  4041. //
  4042. // Set the cancelled flag before releasing the mutex.
  4043. // This guarantees that if any other threads are waiting to stick up
  4044. // a copy error, they'll hit the case above and return COPYERR_SKIP.
  4045. //
  4046. Cancelled = TRUE;
  4047. if(MasterList) {
  4048. SetEvent(MasterCopyList.StopCopyingEvent);
  4049. }
  4050. }
  4051. if(MasterList) {
  4052. ReleaseMutex(UiMutex);
  4053. }
  4054. return(u);
  4055. }
  4056. INT_PTR
  4057. CopyErrDlgProc(
  4058. IN HWND hdlg,
  4059. IN UINT msg,
  4060. IN WPARAM wParam,
  4061. IN LPARAM lParam
  4062. )
  4063. {
  4064. BOOL b;
  4065. int i;
  4066. static WarnedSkip;
  4067. b = FALSE;
  4068. switch(msg) {
  4069. case WM_INITDIALOG:
  4070. //
  4071. // File not found and disk full get special treatment.
  4072. // Others get the standard system message.
  4073. //
  4074. {
  4075. TCHAR text1[500];
  4076. TCHAR text2[1000];
  4077. TCHAR text3[5000];
  4078. PCOPY_ERR_DLG_PARAMS Params;
  4079. DWORD Flags;
  4080. UINT Id;
  4081. LPCTSTR Args[4];
  4082. LPCTSTR source;
  4083. Params = (PCOPY_ERR_DLG_PARAMS)lParam;
  4084. switch(Params->Win32Error) {
  4085. case ERROR_FILE_NOT_FOUND:
  4086. Flags = FORMAT_MESSAGE_FROM_HMODULE;
  4087. Id = MSG_COPY_ERROR_NOSRC;
  4088. break;
  4089. case ERROR_HANDLE_DISK_FULL:
  4090. case ERROR_DISK_FULL:
  4091. Flags = FORMAT_MESSAGE_FROM_HMODULE;
  4092. Id = MSG_COPY_ERROR_DISKFULL;
  4093. break;
  4094. default:
  4095. Flags = FORMAT_MESSAGE_FROM_SYSTEM;
  4096. Id = Params->Win32Error;
  4097. break;
  4098. }
  4099. FormatMessage(
  4100. Flags | FORMAT_MESSAGE_IGNORE_INSERTS,
  4101. hInst,
  4102. Id,
  4103. 0,
  4104. text1,
  4105. ARRAYSIZE(text1),
  4106. NULL
  4107. );
  4108. FormatMessage(
  4109. FORMAT_MESSAGE_FROM_HMODULE,
  4110. hInst,
  4111. MSG_COPY_ERROR_OPTIONS,
  4112. 0,
  4113. text2,
  4114. ARRAYSIZE(text2),
  4115. NULL
  4116. );
  4117. if(source = _tcsrchr(Params->SourceFilename,TEXT('\\'))) {
  4118. source++;
  4119. } else {
  4120. source = Params->SourceFilename;
  4121. }
  4122. Args[0] = source;
  4123. Args[1] = Params->TargetFilename;
  4124. Args[2] = text1;
  4125. Args[3] = text2;
  4126. FormatMessage(
  4127. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4128. hInst,
  4129. MSG_COPY_ERROR_TEMPLATE,
  4130. 0,
  4131. text3,
  4132. ARRAYSIZE(text3),
  4133. (va_list *)Args
  4134. );
  4135. if (BatchMode) {
  4136. //
  4137. // Don't show the UI. Save the error message and pretend the
  4138. // user hit Abort.
  4139. //
  4140. SaveTextForSMS(text3);
  4141. EndDialog(hdlg,COPYERR_EXIT);
  4142. }
  4143. SetDlgItemText(hdlg,IDT_ERROR_TEXT,text3);
  4144. }
  4145. SetFocus(GetDlgItem(hdlg,IDRETRY));
  4146. break;
  4147. case WM_COMMAND:
  4148. switch(LOWORD(wParam)) {
  4149. case IDRETRY:
  4150. if(HIWORD(wParam) == BN_CLICKED) {
  4151. EndDialog(hdlg,COPYERR_RETRY);
  4152. b = TRUE;
  4153. }
  4154. break;
  4155. case IDIGNORE:
  4156. if(HIWORD(wParam) == BN_CLICKED) {
  4157. if(WarnedSkip) {
  4158. i = IDYES;
  4159. } else {
  4160. i = MessageBoxFromMessage(
  4161. hdlg,
  4162. MSG_REALLY_SKIP,
  4163. FALSE,
  4164. AppTitleStringId,
  4165. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2
  4166. );
  4167. WarnedSkip = TRUE;
  4168. }
  4169. if(i == IDYES) {
  4170. EndDialog(hdlg,COPYERR_SKIP);
  4171. }
  4172. b = TRUE;
  4173. }
  4174. break;
  4175. case IDABORT:
  4176. if(HIWORD(wParam) == BN_CLICKED) {
  4177. i = MessageBoxFromMessage(
  4178. hdlg,
  4179. MSG_SURE_EXIT,
  4180. FALSE,
  4181. AppTitleStringId,
  4182. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2
  4183. );
  4184. if(i == IDYES) {
  4185. EndDialog(hdlg,COPYERR_EXIT);
  4186. }
  4187. b = TRUE;
  4188. }
  4189. break;
  4190. }
  4191. break;
  4192. }
  4193. return(b);
  4194. }
  4195. UINT
  4196. DiamondCallback(
  4197. IN PVOID Context,
  4198. IN UINT Code,
  4199. IN UINT_PTR Param1,
  4200. IN UINT_PTR Param2
  4201. )
  4202. {
  4203. UINT u;
  4204. PFILE_IN_CABINET_INFO_A FileInCabInfo;
  4205. PNAME_AND_SIZE_CAB NameAndSize;
  4206. if(Code == SPFILENOTIFY_FILEINCABINET) {
  4207. //
  4208. // Give setupapi the full target path of the file.
  4209. //
  4210. NameAndSize = Context;
  4211. FileInCabInfo = (PFILE_IN_CABINET_INFO_A)Param1;
  4212. #ifdef UNICODE
  4213. u = WideCharToMultiByte(
  4214. CP_ACP,
  4215. 0,
  4216. NameAndSize->Name,
  4217. -1,
  4218. FileInCabInfo->FullTargetName,
  4219. ARRAYSIZE(FileInCabInfo->FullTargetName),
  4220. NULL,
  4221. NULL
  4222. );
  4223. if(!u) {
  4224. FileInCabInfo->Win32Error = GetLastError();
  4225. return(FILEOP_ABORT);
  4226. }
  4227. #else
  4228. if (FAILED (StringCchCopy (
  4229. FileInCabInfo->FullTargetName,
  4230. ARRAYSIZE(FileInCabInfo->FullTargetName),
  4231. NameAndSize->Name))) {
  4232. FileInCabInfo->Win32Error = ERROR_INSUFFICIENT_BUFFER;
  4233. return(FILEOP_ABORT);
  4234. }
  4235. #endif
  4236. //
  4237. // BugBug: cabinet only returns a DWORD file size
  4238. //
  4239. NameAndSize->Size = (ULONGLONG)FileInCabInfo->FileSize;
  4240. u = FILEOP_DOIT;
  4241. } else {
  4242. u = NO_ERROR;
  4243. }
  4244. return(u);
  4245. }
  4246. BOOL
  4247. AddUnsupportedFilesToCopyList(
  4248. IN HWND ParentWindow,
  4249. IN PUNSUPORTED_DRIVER_INFO DriverList
  4250. )
  4251. /*++
  4252. Routine Description:
  4253. Adds unsupported, required drivers to be used during textmode setup.
  4254. This would include 3rd party mass storage drivers, for instance.
  4255. The files are simply appended to the master copy list.
  4256. Arguments:
  4257. ParentWindow - ParentWindow used for UI.
  4258. DriverList - supplies the list of drivers to be added to the copy list.
  4259. Return Value:
  4260. If successful, returns a pointer to the new FIL structure for the file.
  4261. Otherwise returns NULL (the caller can assume out of memory).
  4262. --*/
  4263. {
  4264. PUNSUPORTED_DRIVER_INFO p;
  4265. ULONG Error;
  4266. PUNSUPORTED_DRIVER_FILE_INFO q;
  4267. PDIR r;
  4268. PUNSUPORTED_DRIVER_INSTALL_INFO s;
  4269. UNREFERENCED_PARAMETER(ParentWindow);
  4270. for( p = DriverList; p != NULL; p = p->Next ) {
  4271. for( q = p->FileList; q != NULL; q = q->Next ) {
  4272. r = MALLOC( sizeof( DIR ) );
  4273. if( r == NULL ) {
  4274. return( FALSE );
  4275. }
  4276. r->Next = NULL;
  4277. r->InfSymbol = NULL;
  4278. r->Flags = 0;
  4279. r->TargetName = NULL;
  4280. r->SourceName = DupString( q->TargetDirectory );
  4281. if( r->SourceName == NULL) {
  4282. FREE( r );
  4283. return( FALSE );
  4284. }
  4285. if( !AddFile( &MasterCopyList,
  4286. q->FileName,
  4287. NULL,
  4288. r,
  4289. FILE_NT_MIGRATE | FILE_NEED_TO_FREE_SOURCENAME,
  4290. 0 ) ) {
  4291. FREE( (LPTSTR)(r->SourceName) );
  4292. FREE( r );
  4293. return( FALSE );
  4294. }
  4295. //
  4296. // now make sure the referenced file is not overwritten with an inbox driver
  4297. // with the same name
  4298. //
  4299. RemoveFile (&MasterCopyList, q->FileName, NULL, FILE_IN_LOCAL_BOOT);
  4300. }
  4301. for( s = p->InstallList; s != NULL; s = s->Next ) {
  4302. r = MALLOC( sizeof( DIR ) );
  4303. if( r == NULL ) {
  4304. return( FALSE );
  4305. }
  4306. r->Next = NULL;
  4307. r->InfSymbol = NULL;
  4308. r->Flags = 0;
  4309. r->TargetName = NULL;
  4310. r->SourceName = DupString( s->InfRelPath );
  4311. if( r->SourceName == NULL) {
  4312. FREE( r );
  4313. return( FALSE );
  4314. }
  4315. //
  4316. // add the INF and the CAT (optional)
  4317. //
  4318. if( !AddFile( &MasterCopyList,
  4319. s->InfFileName,
  4320. s->InfOriginalFileName,
  4321. r,
  4322. FILE_NT_MIGRATE | FILE_NEED_TO_FREE_SOURCENAME | FILE_NEED_TO_FREE_TARGETNAME,
  4323. 0 ) ) {
  4324. FREE( (LPTSTR)(r->SourceName) );
  4325. FREE( r );
  4326. return( FALSE );
  4327. }
  4328. if (s->CatalogRelPath && s->CatalogFileName) {
  4329. r = MALLOC( sizeof( DIR ) );
  4330. if( r == NULL ) {
  4331. return( FALSE );
  4332. }
  4333. r->Next = NULL;
  4334. r->InfSymbol = NULL;
  4335. r->Flags = 0;
  4336. r->TargetName = NULL;
  4337. r->SourceName = DupString( s->CatalogRelPath );
  4338. if( r->SourceName == NULL) {
  4339. FREE( r );
  4340. return( FALSE );
  4341. }
  4342. //
  4343. // add the INF and the CAT (optional)
  4344. //
  4345. if( !AddFile( &MasterCopyList,
  4346. s->CatalogFileName,
  4347. s->CatalogOriginalFileName,
  4348. r,
  4349. FILE_NT_MIGRATE | FILE_NEED_TO_FREE_SOURCENAME | FILE_NEED_TO_FREE_TARGETNAME,
  4350. 0 ) ) {
  4351. FREE( (LPTSTR)(r->SourceName) );
  4352. FREE( r );
  4353. return( FALSE );
  4354. }
  4355. }
  4356. }
  4357. }
  4358. return(TRUE);
  4359. }
  4360. BOOL
  4361. AddGUIModeCompatibilityInfsToCopyList(
  4362. VOID
  4363. )
  4364. /*++
  4365. Routine Description:
  4366. Adds the compatibility INF to the copy queue. The compatibility
  4367. inf is used during GUI-setup to remove incompatible drivers.
  4368. Arguments:
  4369. None.
  4370. Return Value:
  4371. If successful, returns TRUE.
  4372. --*/
  4373. {
  4374. PDIR CompDir;
  4375. PLIST_ENTRY Next_Link;
  4376. PCOMPATIBILITY_DATA CompData;
  4377. TCHAR InfLocation[MAX_PATH], *t;
  4378. TCHAR relPath[MAX_PATH];
  4379. WIN32_FIND_DATA fd;
  4380. Next_Link = CompatibilityData.Flink;
  4381. if( Next_Link ){
  4382. while ((ULONG_PTR)Next_Link != (ULONG_PTR)&CompatibilityData) {
  4383. CompData = CONTAINING_RECORD( Next_Link, COMPATIBILITY_DATA, ListEntry );
  4384. Next_Link = CompData->ListEntry.Flink;
  4385. if(CompData->InfName && CompData->InfSection && *CompData->InfName && *CompData->InfSection) {
  4386. BOOL b = FALSE;
  4387. if (FileExists (CompData->InfName, &fd) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  4388. b = SUCCEEDED (StringCchCopy (InfLocation, ARRAYSIZE(InfLocation), CompData->InfName));
  4389. if (b) {
  4390. DebugLog(
  4391. Winnt32LogInformation,
  4392. TEXT("Using private compatibility inf %1"),
  4393. 0,
  4394. InfLocation
  4395. );
  4396. }
  4397. } else {
  4398. b = BuildPath (relPath, TEXT("compdata"), CompData->InfName) &&
  4399. FindPathToWinnt32File (relPath, InfLocation, ARRAYSIZE(InfLocation));
  4400. }
  4401. if (b) {
  4402. b = FALSE;
  4403. t = _tcsrchr (InfLocation, TEXT('\\'));
  4404. if (t) {
  4405. *t = 0;
  4406. CompDir = AddDirectory(
  4407. NULL,
  4408. &MasterCopyList,
  4409. InfLocation,
  4410. TEXT("\\"),
  4411. DIR_NEED_TO_FREE_SOURCENAME | DIR_ABSOLUTE_PATH
  4412. );
  4413. if (CompDir && AddFile (
  4414. &MasterCopyList,
  4415. t + 1,
  4416. NULL,
  4417. CompDir,
  4418. (IsArc() ? 0 : FILE_IN_LOCAL_BOOT) | FILE_NEED_TO_FREE_SOURCENAME,
  4419. 0
  4420. )) {
  4421. b = TRUE;
  4422. }
  4423. }
  4424. }
  4425. if (!b) {
  4426. DebugLog( Winnt32LogError,
  4427. TEXT( "\r\n\r\nError encountered while trying to copy compatibility infs\r\n"),
  4428. 0 );
  4429. return(FALSE);
  4430. }
  4431. }
  4432. }
  4433. }
  4434. return( TRUE );
  4435. }
  4436. LRESULT
  4437. DiskDlgProc(
  4438. IN HWND hdlg,
  4439. IN UINT msg,
  4440. IN WPARAM wParam,
  4441. IN LPARAM lParam
  4442. )
  4443. {
  4444. switch(msg) {
  4445. case WM_INITDIALOG:
  4446. //
  4447. // Fill in the diagnostic list...
  4448. //
  4449. SetDlgItemText( hdlg,
  4450. IDC_DISKDIAG,
  4451. DiskDiagMessage );
  4452. return( TRUE );
  4453. case WM_COMMAND:
  4454. if( (LOWORD(wParam) == IDOK) && (HIWORD(wParam) == BN_CLICKED)) {
  4455. EndDialog(hdlg,TRUE);
  4456. }
  4457. return( TRUE );
  4458. case WM_CTLCOLOREDIT:
  4459. SetBkColor( (HDC)wParam, GetSysColor(COLOR_BTNFACE));
  4460. return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
  4461. break;
  4462. default:
  4463. break;
  4464. }
  4465. return( FALSE );
  4466. }