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

3036 lines
98 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. oemmint.cpp
  5. Abstract:
  6. Simple tool to create a Mini NT image
  7. from a regular NT image
  8. Author:
  9. Vijay Jayaseelan (vijayj) Apr-23-2000
  10. Revision History:
  11. Aug-08-2000 - Major rewrite using setupapi wrapper
  12. class library.
  13. Nov-10-2000 - Made the utility work with actual
  14. distribution CD.
  15. Jan-23-2001 - Add support for version checking.
  16. Feb-09-2002 - Add support for multiple driver cab
  17. file extraction.
  18. Apr-15-2002 - Modify tool to work on both layouts (placement)
  19. of SxS assemblies on release share. It used to be in
  20. ASMS folder but now is in asms*.cab file.
  21. NOTE: This tool needs to be updated on changes to
  22. entries to the disk ordinals for WOW64 files.!!!!
  23. Change needs to go in IsWow64File(..)
  24. --*/
  25. #include <oemmint.h>
  26. #include <iostream>
  27. #include <io.h>
  28. #include <sxsapi.h>
  29. #include "msg.h"
  30. #include <libmsg.h>
  31. using namespace std;
  32. //
  33. // static constant data members
  34. //
  35. const std::basic_string<TCHAR> DriverIndexInfFile<TCHAR>::VersionSectionName = TEXT("version");
  36. const std::basic_string<TCHAR> DriverIndexInfFile<TCHAR>::CabsSectionName = TEXT("cabs");
  37. const std::basic_string<TCHAR> DriverIndexInfFile<TCHAR>::CabsSearchOrderKeyName = TEXT("cabfiles");
  38. //
  39. // Constants
  40. //
  41. const std::wstring REGIONAL_SECTION_NAME = TEXT("regionalsettings");
  42. const std::wstring LANGUAGE_GROUP_KEY = TEXT("languagegroup");
  43. const std::wstring LANGUAGE_KEY = TEXT("language");
  44. const std::wstring LANGGROUP_SECTION_PREFIX = TEXT("lg_install_");
  45. const std::wstring DEFAULT_LANGGROUP_NAME = TEXT("lg_install_1");
  46. const std::wstring LOCALES_SECTION_NAME = TEXT("locales");
  47. const std::wstring FONT_CP_REGSECTION_FMT_STR = TEXT("font.cp%s.%d");
  48. const std::wstring X86_PLATFORM_DIR = TEXT("i386");
  49. const std::wstring IA64_PLATFORM_DIR = TEXT("ia64");
  50. const std::wstring INFCHANGES_SECTION_NAME = TEXT("infchanges");
  51. const DWORD LANG_GROUP1_INDEX = 2;
  52. const DWORD OEM_CP_INDEX = 1;
  53. const DWORD DEFAULT_FONT_SIZE = 96;
  54. //
  55. // Global variables used to get formatted message for this program.
  56. //
  57. HMODULE ThisModule = NULL;
  58. WCHAR Message[4096];
  59. //
  60. // Main entry point
  61. //
  62. int
  63. __cdecl
  64. wmain(int Argc, wchar_t* Argv[])
  65. {
  66. int Result = 0;
  67. ThisModule = GetModuleHandle(NULL);
  68. try{
  69. //
  70. // parse the arguments
  71. //
  72. UnicodeArgs Args(Argc, Argv);
  73. //
  74. // Check to see if we are using this utility to check the version
  75. //
  76. if (!Args.CheckVersion) {
  77. if (Args.Verbose) {
  78. cout << GetFormattedMessage(ThisModule,
  79. FALSE,
  80. Message,
  81. sizeof(Message)/sizeof(Message[0]),
  82. MSG_CREATING_WINPE_FILE_LIST) << endl;
  83. }
  84. //
  85. // open the config.inf file
  86. //
  87. if (Args.Verbose) {
  88. cout << GetFormattedMessage(ThisModule,
  89. FALSE,
  90. Message,
  91. sizeof(Message)/sizeof(Message[0]),
  92. MSG_PARSING_FILE,
  93. Args.ConfigInfFileName.c_str()) << endl;
  94. }
  95. InfFileW ConfigInfFile(Args.ConfigInfFileName);
  96. //
  97. // open the layout.inf file
  98. //
  99. if (Args.Verbose) {
  100. cout << GetFormattedMessage(ThisModule,
  101. FALSE,
  102. Message,
  103. sizeof(Message)/sizeof(Message[0]),
  104. MSG_PARSING_FILE,
  105. Args.LayoutName.c_str()) << endl;
  106. }
  107. InfFileW InputFile(Args.LayoutName);
  108. //
  109. // open the drvindex.inf file
  110. //
  111. if (Args.Verbose) {
  112. cout << GetFormattedMessage(ThisModule,
  113. FALSE,
  114. Message,
  115. sizeof(Message)/sizeof(Message[0]),
  116. MSG_PARSING_FILE,
  117. Args.DriverIndexName.c_str()) << endl;
  118. }
  119. DriverIndexInfFile<WCHAR> DriverIdxFile(Args.DriverIndexName);
  120. //
  121. // open the intl.inf file
  122. //
  123. if (Args.Verbose) {
  124. cout << GetFormattedMessage(ThisModule,
  125. FALSE,
  126. Message,
  127. sizeof(Message)/sizeof(Message[0]),
  128. MSG_PARSING_FILE,
  129. Args.IntlInfFileName.c_str()) << endl;
  130. }
  131. InfFileW IntlInfFile(Args.IntlInfFileName);
  132. //
  133. // open the font.inf file
  134. //
  135. if (Args.Verbose) {
  136. cout << GetFormattedMessage(ThisModule,
  137. FALSE,
  138. Message,
  139. sizeof(Message)/sizeof(Message[0]),
  140. MSG_PARSING_FILE,
  141. Args.FontInfFileName.c_str()) << endl;
  142. }
  143. InfFileW FontInfFile(Args.FontInfFileName);
  144. map<std::basic_string<wchar_t>, Section<wchar_t>* > Sections;
  145. //
  146. // get hold of the sections in the layout file
  147. //
  148. InputFile.GetSections(Sections);
  149. //
  150. // get hold of "[SourceDisksFiles] section
  151. //
  152. map<basic_string<wchar_t>, Section<wchar_t> * >::iterator iter = Sections.find(L"sourcedisksfiles");
  153. Section<wchar_t> *SDSection = 0;
  154. Section<wchar_t> *DirSection = 0;
  155. Section<wchar_t> *PlatSection = 0;
  156. if (iter != Sections.end()) {
  157. SDSection = (*iter).second;
  158. }
  159. //
  160. // get hold of the [WinntDirectories] section
  161. //
  162. iter = Sections.find(L"winntdirectories");
  163. if (iter != Sections.end()) {
  164. DirSection = (*iter).second;
  165. }
  166. //
  167. // get hold of the platform specific source files section
  168. //
  169. basic_string<wchar_t> PlatformSection = SDSection->GetName() + L"." + Args.PlatformSuffix;
  170. iter = Sections.find(PlatformSection);
  171. if (iter != Sections.end()) {
  172. PlatSection = (*iter).second;
  173. }
  174. //
  175. // Merge the platform and common source files section
  176. //
  177. if (PlatSection) {
  178. if (Args.Verbose) {
  179. cout << GetFormattedMessage( ThisModule,
  180. FALSE,
  181. Message,
  182. sizeof(Message)/sizeof(Message[0]),
  183. MSG_MERGING_PLATFORM_AND_COMMON_SRC_FILES,
  184. PlatSection->GetName().c_str(),
  185. SDSection->GetName().c_str()) << endl;
  186. }
  187. *SDSection += *PlatSection;
  188. }
  189. //
  190. // Iterate through each file in the common merged section
  191. // creating a file list of minint image
  192. //
  193. FileListCreatorContext<wchar_t> fl(Args, SDSection,
  194. DirSection, ConfigInfFile,
  195. IntlInfFile, FontInfFile,
  196. DriverIdxFile);
  197. //
  198. // Create the list of files to be copied
  199. //
  200. SDSection->DoForEach(FileListCreator, &fl);
  201. //
  202. // Process Nls files
  203. //
  204. ULONG NlsFileCount = fl.ProcessNlsFiles();
  205. if (Args.Verbose) {
  206. std::cout << GetFormattedMessage( ThisModule,
  207. FALSE,
  208. Message,
  209. sizeof(Message)/sizeof(Message[0]),
  210. MSG_DUMP_PROCESSED_NLS_FILE_COUNT,
  211. NlsFileCount) << std::endl;
  212. }
  213. //
  214. // Process WinSxS files
  215. //
  216. ULONG SxSFileCount = ProcessWinSxSFiles(fl);
  217. if (Args.Verbose) {
  218. std::cout << GetFormattedMessage( ThisModule,
  219. FALSE,
  220. Message,
  221. sizeof(Message)/sizeof(Message[0]),
  222. MSG_DUMP_PROCESSED_SXS_FILE_COUNT,
  223. SxSFileCount) << std::endl;
  224. }
  225. //
  226. // If there are extra files specified then process them and
  227. // add to the file list for minint image
  228. //
  229. if (Args.ExtraFileName.length() > 0) {
  230. ULONG ExtraFiles = ProcessExtraFiles(fl);
  231. if (Args.Verbose) {
  232. cout << GetFormattedMessage(ThisModule,
  233. FALSE,
  234. Message,
  235. sizeof(Message)/sizeof(Message[0]),
  236. MSG_DUMP_PROCESSED_EXTRA_FILES,
  237. ExtraFiles,
  238. fl.Args.ExtraFileName.c_str()) << endl;
  239. }
  240. }
  241. //
  242. // Create all the required destination directories
  243. //
  244. ULONG DirsCreated = PreCreateDirs(fl);
  245. //
  246. // Ok, now copy the list of files
  247. //
  248. ULONG FilesToCopy = fl.GetSourceCount();
  249. if (FilesToCopy) {
  250. ULONG Count = CopyFileList(fl);
  251. Result = FilesToCopy - Count;
  252. if (Result || Args.Verbose) {
  253. cout << GetFormattedMessage(ThisModule,
  254. FALSE,
  255. Message,
  256. sizeof(Message)/sizeof(Message[0]),
  257. MSG_NUMBER_OF_FILES_COPIED,
  258. Count,
  259. FilesToCopy ) << endl;
  260. }
  261. }
  262. //
  263. // Now process the required inf changes
  264. //
  265. wstring ControlInf = Args.CurrentDirectory + L"config.inf";
  266. if (!IsFilePresent(ControlInf)) {
  267. throw new W32Exception<wchar_t>(ERROR_FILE_NOT_FOUND);
  268. }
  269. ProcessInfChanges(Args, ControlInf);
  270. } else {
  271. //
  272. // Check the version of the current OS and the install media
  273. // to make sure that they match
  274. //
  275. Result = CheckMediaVersion(Args) ? 0 : 1;
  276. }
  277. }
  278. catch (InvalidArguments *InvArgs) {
  279. cerr << GetFormattedMessage(ThisModule,
  280. FALSE,
  281. Message,
  282. sizeof(Message)/sizeof(Message[0]),
  283. MSG_PGM_USAGE) << endl;
  284. delete InvArgs;
  285. Result = 1;
  286. }
  287. catch (BaseException<wchar_t> *Exp) {
  288. Exp->Dump(std::cout);
  289. delete Exp;
  290. Result = 1;
  291. }
  292. catch (...) {
  293. Result = 1;
  294. }
  295. return Result;
  296. }
  297. //
  298. // Processes all the inf files and adds them to the copy list
  299. // to copy to the destination\inf directory
  300. // NOTE : This routine only processes net*.inf file automatically.
  301. // Other inf needs to be marked specifically
  302. //
  303. template <class T>
  304. BOOLEAN
  305. InfFileListCreator(
  306. SectionValues<T> &Values,
  307. FileListCreatorContext<T> &Context
  308. )
  309. {
  310. //
  311. // Note : All the inf files in layout always end with ".inf"
  312. // lowercase characters
  313. //
  314. basic_string<T> Key = Values.GetName();
  315. basic_string<T>::size_type InfIdx = Key.find(L".inf");
  316. BOOLEAN Result = FALSE;
  317. static bool DirAdded = false;
  318. basic_string<T>::size_type NetIdx = Key.find(L"net");
  319. if (!Context.SkipInfFiles && (InfIdx != basic_string<T>::npos) && (NetIdx == 0)) {
  320. Result = TRUE;
  321. if (sizeof(T) == sizeof(CHAR)) {
  322. _strlwr((PSTR)Key.c_str());
  323. } else {
  324. _wcslwr((PWSTR)Key.c_str());
  325. }
  326. basic_string<T> SrcFile = Context.Args.SourceDirectory + Key;
  327. basic_string<T> DestFile;
  328. bool DestDirPresent = false;
  329. if (Values.Count() > 12) {
  330. basic_string<T> DestDir = Values.GetValue(12);
  331. //
  332. // remove trailing white spaces
  333. //
  334. unsigned int DestDirLength = DestDir.length();
  335. while (DestDirLength) {
  336. if (DestDir[DestDirLength] != L' ') {
  337. break;
  338. }
  339. DestDir[DestDirLength] = 0;
  340. DestDirLength--;
  341. }
  342. //
  343. // if the destination directory ID is 0 then skip
  344. // the file
  345. //
  346. if (DestDir == L"0") {
  347. return TRUE;
  348. }
  349. if (DestDir.length()) {
  350. basic_string<T> DestDirCode = DestDir;
  351. DestDir = Context.DirsSection->GetValue(DestDir).GetValue(0);
  352. if (DestDir.length()) {
  353. if (DestDir[DestDir.length() - 1] != L'\\') {
  354. DestDir += L"\\";
  355. }
  356. DestDir = Context.Args.DestinationDirectory + DestDir;
  357. //
  358. // Cache the directory, if not already done
  359. //
  360. if (Context.DestDirs.find(DestDirCode) ==
  361. Context.DestDirs.end()) {
  362. Context.DestDirs[DestDirCode] = DestDir;
  363. }
  364. DestDirPresent = true;
  365. DestFile = DestDir;
  366. }
  367. }
  368. }
  369. if (!DestDirPresent) {
  370. DestFile = Context.Args.DestinationDirectory + L"Inf\\";
  371. if (!DirAdded) {
  372. //
  373. // Inf directory's code is 20
  374. //
  375. basic_string<T> DestDirCode(L"20");
  376. //
  377. // Cache the directory, if not already done
  378. //
  379. if (Context.DestDirs.find(DestDirCode) ==
  380. Context.DestDirs.end()) {
  381. Context.DestDirs[DestDirCode] = DestFile;
  382. }
  383. DirAdded = true;
  384. }
  385. }
  386. if (Values.Count() > 10) {
  387. const basic_string<T> &DestName = Values.GetValue(10);
  388. if (DestName.length()) {
  389. DestFile += DestName;
  390. } else {
  391. DestFile += Key;
  392. }
  393. } else {
  394. DestFile += Key;
  395. }
  396. bool AlternateFound = false;
  397. if (Context.Args.OptionalSrcDirectory.length()) {
  398. basic_string<T> OptionalSrcFile = Context.Args.OptionalSrcDirectory + Key;
  399. if (IsFilePresent(OptionalSrcFile)) {
  400. SrcFile = OptionalSrcFile;
  401. AlternateFound = true;
  402. }
  403. }
  404. const basic_string<T> &DriverCabFileName = Context.GetDriverCabFileName(Key);
  405. if (!AlternateFound && DriverCabFileName.length()) {
  406. SrcFile = Key;
  407. }
  408. if (DriverCabFileName.length()) {
  409. Context.AddFileToCabFileList(DriverCabFileName, SrcFile, DestFile);
  410. } else if (Context.ProcessingExtraFiles) {
  411. Context.ExtraFileList[SrcFile] = DestFile;
  412. } else {
  413. Context.FileList[SrcFile] = DestFile;
  414. }
  415. }
  416. return Result;
  417. }
  418. //
  419. // Parses the value to determine, if this file needs
  420. // to be in minint and adds the file to the file list
  421. // if this file is needed
  422. //
  423. template <class T>
  424. void
  425. FileListCreator(SectionValues<T> &Values, void *Context) {
  426. FileListCreatorContext<T> *FlContext = (FileListCreatorContext<T> *)(Context);
  427. unsigned int Count = Values.Count() ;
  428. bool Compressed = false;
  429. if (FlContext && !IsFileSkipped(Values, *FlContext) &&
  430. !InfFileListCreator(Values, *FlContext) && (Count > 12)) {
  431. basic_string<T> SrcDir = Values.GetValue(11);
  432. basic_string<T> DestDir = Values.GetValue(12);
  433. basic_string<T> Key = Values.GetName();
  434. if (sizeof(T) == sizeof(CHAR)) {
  435. _strlwr((PSTR)Key.c_str());
  436. } else {
  437. _wcslwr((PWSTR)Key.c_str());
  438. }
  439. //
  440. // remove trailing white spaces
  441. //
  442. unsigned int DestDirLength = DestDir.length();
  443. while (DestDirLength) {
  444. if (DestDir[DestDirLength] != L' ') {
  445. break;
  446. }
  447. DestDir[DestDirLength] = 0;
  448. DestDirLength--;
  449. }
  450. //
  451. // if the destination directory ID is 0 then skip
  452. // the file
  453. //
  454. if (DestDir == L"0") {
  455. return;
  456. }
  457. basic_string<T> SrcSubDir = FlContext->DirsSection->GetValue(SrcDir).GetValue(0);
  458. basic_string<T> DestSubDir = FlContext->DirsSection->GetValue(DestDir).GetValue(0);
  459. basic_string<T> DestDirCode = DestDir;
  460. //
  461. // Fix up diretory names
  462. //
  463. if (SrcSubDir.length() && (SrcSubDir[SrcSubDir.length() - 1] != L'\\')) {
  464. SrcSubDir += L"\\";
  465. }
  466. if (DestSubDir.length() && (DestSubDir[DestSubDir.length() - 1] != L'\\')) {
  467. DestSubDir += L"\\";
  468. }
  469. basic_string<T> OptSrcDir = FlContext->Args.OptionalSrcDirectory;
  470. SrcDir = FlContext->Args.SourceDirectory;
  471. if (SrcSubDir != L"\\") {
  472. SrcDir += SrcSubDir;
  473. if (OptSrcDir.length()) {
  474. OptSrcDir += SrcSubDir;
  475. }
  476. }
  477. DestDir = FlContext->Args.DestinationDirectory;
  478. if (DestSubDir != L"\\") {
  479. DestDir += DestSubDir;
  480. }
  481. //
  482. // Cache the directory, if not already done
  483. //
  484. if (FlContext->DestDirs.find(DestDirCode) ==
  485. FlContext->DestDirs.end()) {
  486. FlContext->DestDirs[DestDirCode] = DestDir;
  487. }
  488. basic_string<T> SrcFile, DestFile;
  489. bool AltSrcDir = false;
  490. if (OptSrcDir.length()) {
  491. SrcFile = OptSrcDir + Key;
  492. AltSrcDir = IsFilePresent(SrcFile);
  493. }
  494. const basic_string<T> &DriverCabFileName = FlContext->GetDriverCabFileName(Key);
  495. bool DriverCabFile = false;
  496. if (!AltSrcDir) {
  497. SrcFile = SrcDir + Key;
  498. basic_string<T> CompressedSrcName = SrcFile;
  499. CompressedSrcName[CompressedSrcName.length() - 1] = TEXT('_');
  500. if (!IsFilePresent(SrcFile) && !IsFilePresent(CompressedSrcName)) {
  501. if (DriverCabFileName.length()) {
  502. SrcFile = Key;
  503. DriverCabFile = true;
  504. }
  505. }
  506. }
  507. DestFile = Values.GetValue(10);
  508. if (!DestFile.length()) {
  509. DestFile = Key;
  510. }
  511. DestFile = DestDir + DestFile;
  512. if (DriverCabFile) {
  513. FlContext->AddFileToCabFileList(DriverCabFileName, SrcFile, DestFile);
  514. } else if (FlContext->ProcessingExtraFiles) {
  515. FlContext->ExtraFileList[SrcFile] = DestFile;
  516. } else {
  517. FlContext->FileList[SrcFile] = DestFile;
  518. }
  519. }
  520. }
  521. //
  522. // CAB file callback routine, which does the actual
  523. // check of whether to extract the file or skip the
  524. // file
  525. //
  526. template <class T>
  527. UINT
  528. CabinetCallback(
  529. PVOID Context,
  530. UINT Notification,
  531. UINT_PTR Param1,
  532. UINT_PTR Param2
  533. )
  534. {
  535. UINT ReturnCode = NO_ERROR;
  536. FileListCreatorContext<T> *FlContext = (FileListCreatorContext<T> *)Context;
  537. PFILE_IN_CABINET_INFO FileInfo = NULL;
  538. PFILEPATHS FilePaths = NULL;
  539. basic_string<T> &FileName = FlContext->CurrentFileName;
  540. map<basic_string<T>, basic_string<T> >::iterator Iter;
  541. map<basic_string<T>, basic_string<T> >::iterator FlIter;
  542. switch (Notification) {
  543. case SPFILENOTIFY_FILEINCABINET:
  544. {
  545. ReturnCode = FILEOP_SKIP;
  546. FileInfo = (PFILE_IN_CABINET_INFO)Param1;
  547. if (sizeof(T) == sizeof(CHAR)) {
  548. FileName = (const T *)(FileInfo->NameInCabinet);
  549. _strlwr((PSTR)(FileName.c_str()));
  550. } else {
  551. FileName = (const T *)(FileInfo->NameInCabinet);
  552. _wcslwr((PWSTR)(FileName.c_str()));
  553. }
  554. Iter = FlContext->CabFileListMap[FlContext->CurrentCabFileIdx]->find(FileName);
  555. if (Iter != FlContext->CabFileListMap[FlContext->CurrentCabFileIdx]->end()) {
  556. if (!FlContext->Args.SkipFileCopy) {
  557. if (sizeof(T) == sizeof(CHAR)) {
  558. (VOID)StringCchCopyA((PSTR)(FileInfo->FullTargetName),
  559. ARRAY_SIZE(FileInfo->FullTargetName),
  560. (PCSTR)((*Iter).second).c_str());
  561. } else {
  562. (VOID)StringCchCopyW((PWSTR)(FileInfo->FullTargetName),
  563. ARRAY_SIZE(FileInfo->FullTargetName),
  564. (PCWSTR)((*Iter).second).c_str());
  565. }
  566. ReturnCode = FILEOP_DOIT;
  567. } else {
  568. ReturnCode = FILEOP_SKIP;
  569. FlContext->FileCount++;
  570. if (FlContext->Args.Verbose) {
  571. std::cout << GetFormattedMessage(ThisModule,
  572. FALSE,
  573. Message,
  574. sizeof(Message)/sizeof(Message[0]),
  575. MSG_EXTRACT_FILES_FROM_CAB_NOTIFICATION,
  576. FlContext->CurrentCabFileIdx.c_str(),
  577. FileName.c_str(),
  578. (*Iter).second.c_str()) << std::endl;
  579. }
  580. }
  581. }
  582. }
  583. break;
  584. case SPFILENOTIFY_FILEEXTRACTED:
  585. FilePaths = (PFILEPATHS)Param1;
  586. if (FilePaths->Win32Error) {
  587. std::cout << GetFormattedMessage(ThisModule,
  588. FALSE,
  589. Message,
  590. sizeof(Message)/sizeof(Message[0]),
  591. MSG_ERROR_EXTRACTING_FILES,
  592. FilePaths->Win32Error,
  593. FilePaths->Source,
  594. FileName.c_str(),
  595. FilePaths->Target) << std::endl;
  596. } else {
  597. FlContext->FileCount++;
  598. if (FlContext->Args.Verbose) {
  599. std::cout << GetFormattedMessage(ThisModule,
  600. FALSE,
  601. Message,
  602. sizeof(Message)/sizeof(Message[0]),
  603. MSG_EXTRACTED_FILES_FROM_CAB_NOTIFICATION,
  604. FilePaths->Source,
  605. FileName.c_str(),
  606. FilePaths->Target) << std::endl;
  607. }
  608. }
  609. break;
  610. default:
  611. break;
  612. }
  613. return ReturnCode;
  614. }
  615. //
  616. // Copies all the required files in given CAB file to the specified
  617. // destination directory
  618. //
  619. template <class T>
  620. ULONG
  621. CopyCabFileList(
  622. FileListCreatorContext<T> &Context,
  623. const std::basic_string<T> &CabFileName
  624. )
  625. {
  626. ULONG Count = Context.FileCount;
  627. if (Context.CabFileListMap.size()) {
  628. BOOL Result = FALSE;
  629. if (sizeof(T) == sizeof(CHAR)) {
  630. Result = SetupIterateCabinetA((PCSTR)CabFileName.c_str(),
  631. NULL,
  632. (PSP_FILE_CALLBACK_A)CabinetCallback<char>,
  633. &Context);
  634. } else {
  635. Result = SetupIterateCabinetW((PCWSTR)CabFileName.c_str(),
  636. NULL,
  637. (PSP_FILE_CALLBACK_W)CabinetCallback<wchar_t>,
  638. &Context);
  639. }
  640. if (!Result) {
  641. cout << GetFormattedMessage(ThisModule,
  642. FALSE,
  643. Message,
  644. sizeof(Message)/sizeof(Message[0]),
  645. MSG_ERROR_ITERATING_CAB_FILE,
  646. GetLastError(),
  647. CabFileName.c_str()) << endl;
  648. }
  649. }
  650. return Context.FileCount - Count;
  651. }
  652. template <class T>
  653. ULONG
  654. CopySingleFileList(
  655. FileListCreatorContext<T> &Context,
  656. map<basic_string<T>, basic_string<T> > &FileList
  657. )
  658. {
  659. ULONG Count = 0;
  660. map<basic_string<T>, basic_string<T> >::iterator Iter = FileList.begin();
  661. while (Iter != FileList.end()) {
  662. DWORD ErrorCode = 0;
  663. if (!Context.Args.SkipFileCopy) {
  664. if (sizeof(T) == sizeof(CHAR)) {
  665. ErrorCode = SetupDecompressOrCopyFileA(
  666. (PCSTR)((*Iter).first.c_str()),
  667. (PCSTR)((*Iter).second.c_str()),
  668. NULL);
  669. } else {
  670. ErrorCode = SetupDecompressOrCopyFileW(
  671. (PCWSTR)((*Iter).first.c_str()),
  672. (PCWSTR)((*Iter).second.c_str()),
  673. NULL);
  674. }
  675. }
  676. if (!ErrorCode) {
  677. Count++;
  678. if (sizeof(T) == sizeof(CHAR)) {
  679. ErrorCode = SetFileAttributesA((LPCSTR)((*Iter).second.c_str()),
  680. FILE_ATTRIBUTE_NORMAL);
  681. } else {
  682. ErrorCode = SetFileAttributesW((LPCWSTR)((*Iter).second.c_str()),
  683. FILE_ATTRIBUTE_NORMAL);
  684. }
  685. if (Context.Args.SkipFileCopy) {
  686. std::cout << GetFormattedMessage(ThisModule,
  687. FALSE,
  688. Message,
  689. sizeof(Message)/sizeof(Message[0]),
  690. MSG_WILL_COPY) ;
  691. }
  692. if (Context.Args.Verbose) {
  693. std::cout << GetFormattedMessage(ThisModule,
  694. FALSE,
  695. Message,
  696. sizeof(Message)/sizeof(Message[0]),
  697. MSG_FILE_NAME,
  698. (*Iter).first.c_str(),
  699. (*Iter).second.c_str()) << std::endl;
  700. }
  701. } else {
  702. std::cout << GetFormattedMessage(ThisModule,
  703. FALSE,
  704. Message,
  705. sizeof(Message)/sizeof(Message[0]),
  706. MSG_ERROR_COPYING_FILES,
  707. ErrorCode,
  708. (*Iter).first.c_str(),
  709. (*Iter).second.c_str()) << std::endl;
  710. }
  711. Iter++;
  712. }
  713. return Count;
  714. }
  715. //
  716. // Iterates through a file list and copies the files
  717. // from the specified source directory to the destination
  718. // directory
  719. //
  720. template <class T>
  721. ULONG
  722. CopyFileList(
  723. FileListCreatorContext<T> &Context
  724. )
  725. {
  726. ULONG Count = 0;
  727. std::map<std::basic_string<T>,
  728. std::map<std::basic_string<T>, std::basic_string<T> > * >::iterator Iter;
  729. for (Iter = Context.CabFileListMap.begin();
  730. Iter != Context.CabFileListMap.end();
  731. Iter++) {
  732. basic_string<T> FullCabFileName = Context.Args.SourceDirectory + (*Iter).first;
  733. Context.CurrentCabFileIdx = (*Iter).first;
  734. Count += CopyCabFileList(Context, FullCabFileName);
  735. }
  736. Count += CopySingleFileList(Context, Context.FileList);
  737. Context.FileCount += Count;
  738. Count += CopySingleFileList(Context, Context.NlsFileMap);
  739. Context.FileCount += Count;
  740. Count += CopySingleFileList(Context, Context.WinSxSFileList);
  741. Context.FileCount += Count;
  742. Count += CopySingleFileList(Context, Context.ExtraFileList);
  743. Context.FileCount += Count;
  744. return Count;
  745. }
  746. //
  747. // Processes the extra files from the specified file name
  748. // other than those present in the layout.inf file.
  749. // Adds the files to the file list for MiniNT image
  750. //
  751. template <class T>
  752. ULONG
  753. ProcessExtraFiles(FileListCreatorContext<T> &Context) {
  754. ULONG Count = 0;
  755. InfFile<T> ExtraFile(Context.Args.ExtraFileName);
  756. basic_string<T> ExtraSecName = TEXT("extrafiles");
  757. basic_string<T> PlatExtraSecName = ExtraSecName + TEXT(".") + Context.Args.PlatformSuffix;
  758. Section<T> *ExtraFilesSec = ExtraFile.GetSection(ExtraSecName.c_str());
  759. Section<T> *PlatExtraFilesSec = ExtraFile.GetSection(PlatExtraSecName.c_str());
  760. if (ExtraFilesSec) {
  761. Context.ProcessingExtraFiles = true;
  762. ExtraFilesSec->DoForEach(FileListCreator, &Context);
  763. Context.ProcessingExtraFiles = false;
  764. Count += Context.ExtraFileList.size();
  765. }
  766. if (PlatExtraFilesSec) {
  767. Context.ProcessingExtraFiles = true;
  768. PlatExtraFilesSec->DoForEach(FileListCreator, &Context);
  769. Context.ProcessingExtraFiles = false;
  770. Count += (Context.ExtraFileList.size() - Count);
  771. }
  772. return Count;
  773. }
  774. //
  775. // Goes through the list of desination directories and precreates
  776. // them
  777. //
  778. template <class T>
  779. ULONG
  780. PreCreateDirs(
  781. FileListCreatorContext<T> &Context
  782. )
  783. {
  784. ULONG Count = 0;
  785. std::map< std::basic_string<T>, std::basic_string<T> >::iterator
  786. Iter = Context.DestDirs.begin();
  787. while (Iter != Context.DestDirs.end()) {
  788. if (CreateDirectories((*Iter).second, NULL)) {
  789. if (Context.Args.Verbose) {
  790. std::cout << GetFormattedMessage(ThisModule,
  791. FALSE,
  792. Message,
  793. sizeof(Message)/sizeof(Message[0]),
  794. MSG_CREATING_DIRECTORIES,
  795. (*Iter).second.c_str()) << std::endl;
  796. }
  797. Count++;
  798. }
  799. Iter++;
  800. }
  801. return Count;
  802. }
  803. //
  804. // Creates the directory (including subdirectories)
  805. //
  806. template <class T>
  807. bool
  808. CreateDirectories(const basic_string<T> &DirName,
  809. LPSECURITY_ATTRIBUTES SecurityAttrs) {
  810. bool Result = false;
  811. std::vector<std::basic_string<T> > Dirs;
  812. std::basic_string<T> Delimiters((T *)TEXT("\\"));
  813. std::basic_string<T> NextDir;
  814. if (Tokenize(DirName, Delimiters, Dirs)) {
  815. std::vector<std::basic_string<T> >::iterator Iter = Dirs.begin();
  816. while (Iter != Dirs.end()) {
  817. NextDir += (*Iter);
  818. if (sizeof(T) == sizeof(CHAR)) {
  819. if (_access((PCSTR)NextDir.c_str(), 0)) {
  820. Result = (CreateDirectoryA((PCSTR)NextDir.c_str(),
  821. SecurityAttrs) == TRUE);
  822. }
  823. } else {
  824. if (_waccess((PCWSTR)NextDir.c_str(), 0)) {
  825. Result = (CreateDirectoryW((PCWSTR)NextDir.c_str(),
  826. SecurityAttrs) == TRUE);
  827. }
  828. }
  829. Iter++;
  830. NextDir += (T *)TEXT("\\");
  831. }
  832. }
  833. return Result;
  834. }
  835. //
  836. // Determines if the given file (or directory) is present
  837. //
  838. template <class T>
  839. bool
  840. IsFilePresent(const basic_string<T> &FileName) {
  841. bool Result = false;
  842. if (sizeof(T) == sizeof(CHAR)) {
  843. Result = (::_access((PCSTR)FileName.c_str(), 0) == 0);
  844. } else {
  845. Result = (::_waccess((PCWSTR)FileName.c_str(), 0) == 0);
  846. }
  847. return Result;
  848. }
  849. //
  850. // Determines if the file is Wow64 file (only valid in IA64) case
  851. //
  852. template <class T>
  853. bool
  854. IsWow64File(
  855. SectionValues<T> &Values,
  856. FileListCreatorContext<T> &Context
  857. )
  858. {
  859. bool Result = false;
  860. if (Values.Count() > 0) {
  861. //
  862. // NOTE : DiskID == 55 for wowfiles. In XPSP1 it is 155.
  863. //
  864. Result = ((Values.GetValue(0) == L"55")||
  865. (Values.GetValue(0) == L"155"));
  866. }
  867. return Result;
  868. }
  869. //
  870. // Determines if the record (file) needs to be skipped or not
  871. //
  872. template <class T>
  873. bool
  874. IsFileSkipped(
  875. SectionValues<T> &Values,
  876. FileListCreatorContext<T> &Context
  877. )
  878. {
  879. bool Result = false;
  880. if (Context.Args.WowFilesPresent && Context.Args.SkipWowFiles) {
  881. Result = IsWow64File(Values, Context);
  882. }
  883. return Result;
  884. }
  885. //
  886. // InfProcessing context
  887. //
  888. template <class T>
  889. struct InfProcessingErrors {
  890. vector<basic_string<T> > FileList;
  891. Arguments<T> &Args;
  892. InfProcessingErrors(Arguments<T> &TempArgs) : Args(TempArgs){}
  893. };
  894. //
  895. // Inf processing worker routine
  896. //
  897. template <class T>
  898. VOID
  899. InfFileChangeWorker(
  900. SectionValues<T> &Values,
  901. PVOID CallbackContext
  902. )
  903. {
  904. InfProcessingErrors<T> *ProcessingContext =
  905. (InfProcessingErrors<T> *)CallbackContext;
  906. if (ProcessingContext) {
  907. InfProcessingErrors<T> &Context = *ProcessingContext;
  908. T Buffer[4096] = {0};
  909. DWORD CharsCopied = 0;
  910. BOOL WriteResult = FALSE;
  911. basic_string<T> FileName;
  912. FileName = Context.Args.DestinationDirectory;
  913. FileName += Values.GetValue(0);
  914. basic_string<T> Value = Values.GetValue(2);
  915. if (Value.find(L' ') != Value.npos) {
  916. Value = L"\"" + Value + L"\"";
  917. }
  918. if (sizeof(T) == sizeof(CHAR)) {
  919. WriteResult = WritePrivateProfileStringA((PCSTR)Values.GetValue(1).c_str(),
  920. (PCSTR)Values.GetName().c_str(),
  921. (PCSTR)Value.c_str(),
  922. (PCSTR)FileName.c_str());
  923. } else {
  924. WriteResult = WritePrivateProfileStringW((PCWSTR)Values.GetValue(1).c_str(),
  925. (PCWSTR)Values.GetName().c_str(),
  926. (PCWSTR)Value.c_str(),
  927. (PCWSTR)FileName.c_str());
  928. }
  929. if (!WriteResult) {
  930. Context.FileList.push_back(Values.GetName());
  931. }
  932. }
  933. }
  934. //
  935. // Given the control inf, reads the [infchanges] section
  936. // and changes each of the specified value of the specified
  937. // inf in destination directory to given value
  938. //
  939. // The format for the [infchanges] section is
  940. // <[sub-directory]\><inf-name>=<section-name>,<key-name>,<new-value>
  941. //
  942. template <class T>
  943. bool
  944. ProcessInfChanges(
  945. Arguments<T> &Args,
  946. const basic_string<T> &InfName
  947. )
  948. {
  949. bool Result = false;
  950. try{
  951. InfFile<T> ControlInf(InfName);
  952. Section<T> *ChangeSection = ControlInf.GetSection(INFCHANGES_SECTION_NAME);
  953. T SectionStringBuffer[16] = {0};
  954. if (sizeof(T) == sizeof(CHAR)) {
  955. (VOID)StringCchPrintfA((PSTR)SectionStringBuffer,
  956. ARRAY_SIZE(SectionStringBuffer),
  957. "%d",
  958. Args.MajorBuildNumber);
  959. } else {
  960. (VOID)StringCchPrintfW((PWSTR)SectionStringBuffer,
  961. ARRAY_SIZE(SectionStringBuffer),
  962. TEXT("%d"),
  963. Args.MajorBuildNumber);
  964. }
  965. basic_string<T> BuildSpecificInfChangeSecName = INFCHANGES_SECTION_NAME +
  966. TEXT(".") +
  967. SectionStringBuffer;
  968. Section<T> *BuildSpecificInfChangeSection = ControlInf.GetSection(BuildSpecificInfChangeSecName.c_str());
  969. InfProcessingErrors<T> ProcessingErrors(Args);
  970. //
  971. // There needs to be atleast one entry with "/minint" load option change
  972. // for txtsetup.sif
  973. //
  974. if (!ChangeSection) {
  975. throw new InvalidInfSection<T>(L"infchanges", InfName);
  976. }
  977. else {
  978. ChangeSection->DoForEach(InfFileChangeWorker, &ProcessingErrors);
  979. if (BuildSpecificInfChangeSection){
  980. BuildSpecificInfChangeSection->DoForEach(InfFileChangeWorker, &ProcessingErrors);
  981. }
  982. }
  983. if (ProcessingErrors.FileList.size()) {
  984. vector<basic_string<T> >::iterator Iter = ProcessingErrors.FileList.begin();
  985. cout << GetFormattedMessage(ThisModule,
  986. FALSE,
  987. Message,
  988. sizeof(Message)/sizeof(Message[0]),
  989. MSG_ERROR_PROCESSING_INF_FILES) << endl;
  990. while (Iter != ProcessingErrors.FileList.end()) {
  991. cout << GetFormattedMessage(ThisModule,
  992. FALSE,
  993. Message,
  994. sizeof(Message)/sizeof(Message[0]),
  995. MSG_FILE,
  996. (*Iter).c_str()) << endl;
  997. Iter++;
  998. }
  999. } else {
  1000. Result = true;
  1001. }
  1002. }
  1003. catch (BaseException<wchar_t> *Exp) {
  1004. Exp->Dump(std::cout);
  1005. delete Exp;
  1006. Result = false;
  1007. }
  1008. catch(...) {
  1009. Result = false;
  1010. }
  1011. return Result;
  1012. }
  1013. //
  1014. // Arguments (constructor)
  1015. //
  1016. template <class T>
  1017. Arguments<T>::Arguments(int Argc, T *Argv[]) : Verbose(false) {
  1018. bool ValidArguments = false;
  1019. SkipWowFiles = true;
  1020. WowFilesPresent = false;
  1021. SkipFileCopy = false;
  1022. CheckVersion = false;
  1023. IA64Image = false;
  1024. MajorBuildNumber = 0;
  1025. MajorVersionNumber = 0;
  1026. MinorVersionNumber = 0;
  1027. T Buffer[MAX_PATH] = {0};
  1028. DWORD CharsCopied = 0;
  1029. if (sizeof(T) == sizeof(CHAR)) {
  1030. CharsCopied = GetCurrentDirectoryA(sizeof(Buffer)/sizeof(T),
  1031. (PSTR)Buffer);
  1032. } else {
  1033. CharsCopied = GetCurrentDirectoryW(sizeof(Buffer)/sizeof(T),
  1034. (PWSTR)Buffer);
  1035. }
  1036. if (!CharsCopied) {
  1037. throw new W32Exception<T>();
  1038. }
  1039. if (Buffer[CharsCopied - 1] != L'\\') {
  1040. Buffer[CharsCopied] = L'\\';
  1041. Buffer[CharsCopied + 1] = NULL;
  1042. }
  1043. CurrentDirectory = Buffer;
  1044. if (Argc >= 2) {
  1045. for (int Index = 0; Index < Argc; Index++) {
  1046. if (wcsstr(Argv[Index], L"/s:")) {
  1047. SourceDirectory = Argv[Index] + 3;
  1048. } else if (wcsstr(Argv[Index], L"/d:")) {
  1049. DestinationDirectory = Argv[Index] + 3;
  1050. } else if (wcsstr(Argv[Index], L"/m:")) {
  1051. OptionalSrcDirectory = Argv[Index] + 3;
  1052. } else if (wcsstr(Argv[Index], L"/e:")) {
  1053. ExtraFileName = Argv[Index] + 3;
  1054. } else if (wcsstr(Argv[Index], L"/l:")) {
  1055. LayoutName = Argv[Index] + 3;
  1056. } else if (wcsstr(Argv[Index], L"/p:")) {
  1057. PlatformSuffix = Argv[Index] + 3;
  1058. } else if (wcsstr(Argv[Index], L"/v")) {
  1059. Verbose = true;
  1060. } else if (!_wcsicmp(Argv[Index], L"/#u:nocopy")) {
  1061. SkipFileCopy = true;
  1062. } else if (!_wcsicmp(Argv[Index], L"/#u:checkversion")) {
  1063. CheckVersion = true;
  1064. }
  1065. }
  1066. if (SourceDirectory.length() &&
  1067. SourceDirectory[SourceDirectory.length() - 1] != L'\\') {
  1068. SourceDirectory += L"\\";
  1069. SourceDirectoryRoot = SourceDirectory;
  1070. std::basic_string<T> ia64Dir = SourceDirectory + L"ia64";
  1071. std::basic_string<T> x86Dir = SourceDirectory + L"i386";
  1072. if (IsFilePresent(ia64Dir)) {
  1073. PlatformSuffix = L"ia64";
  1074. SourceDirectory += L"ia64\\";
  1075. WowFilesPresent = true;
  1076. IA64Image = true;
  1077. } else if (IsFilePresent(x86Dir)) {
  1078. PlatformSuffix = L"x86";
  1079. SourceDirectory += L"i386\\";
  1080. }
  1081. }
  1082. if (DestinationDirectory.length() &&
  1083. DestinationDirectory[DestinationDirectory.length() - 1] != L'\\') {
  1084. DestinationDirectory += L'\\';
  1085. }
  1086. if (!LayoutName.length()) {
  1087. LayoutName = SourceDirectory + L"layout.inf";
  1088. }
  1089. if (OptionalSrcDirectory.length() &&
  1090. OptionalSrcDirectory[OptionalSrcDirectory.length() - 1] != L'\\') {
  1091. OptionalSrcDirectory += L"\\";
  1092. }
  1093. DriverIndexName = SourceDirectory + L"drvindex.inf";
  1094. if (OptionalSrcDirectory.length()) {
  1095. IntlInfFileName = OptionalSrcDirectory + L"intl.inf";
  1096. FontInfFileName = OptionalSrcDirectory + L"font.inf";
  1097. ConfigInfFileName = OptionalSrcDirectory + L"config.inf";
  1098. } else {
  1099. IntlInfFileName = SourceDirectory + L"intl.inf";
  1100. FontInfFileName = SourceDirectory + L"font.inf";
  1101. ConfigInfFileName = SourceDirectory + L"config.inf";
  1102. }
  1103. DosNetFileName = SourceDirectory + L"dosnet.inf";
  1104. //
  1105. // Get the SxS assembly layout (in ASMS directory or CAB).
  1106. //
  1107. IdentifySxSLayout();
  1108. if (!CheckVersion) {
  1109. ValidArguments = SourceDirectory.length() && DestinationDirectory.length() &&
  1110. LayoutName.length() &&
  1111. ((PlatformSuffix == L"x86") || (PlatformSuffix == L"ia64"));
  1112. } else {
  1113. ValidArguments = (SourceDirectory.length() > 0) &&
  1114. IsFilePresent(DosNetFileName);
  1115. }
  1116. }
  1117. if (!ValidArguments) {
  1118. throw new InvalidArguments();
  1119. }
  1120. }
  1121. template <class T>
  1122. VOID
  1123. Arguments<T>::IdentifySxSLayout(
  1124. VOID
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This routine determines the file layout for SXS files.
  1129. Arguments:
  1130. None.
  1131. Return Value:
  1132. None.
  1133. --*/
  1134. {
  1135. WCHAR DriverVer[MAX_PATH] = {0};
  1136. WinSxSLayout = SXS_LAYOUT_TYPE_CAB; // by default assumes latest layout
  1137. if (GetPrivateProfileString(L"Version",
  1138. L"DriverVer",
  1139. NULL,
  1140. DriverVer,
  1141. sizeof(DriverVer)/sizeof(DriverVer[0]),
  1142. DosNetFileName.c_str())){
  1143. basic_string<T> DriverVerStr = DriverVer;
  1144. basic_string<T>::size_type VerStartPos = DriverVerStr.find(L',');
  1145. basic_string<T> VersionStr = DriverVerStr.substr(VerStartPos + 1);
  1146. vector<basic_string<T> > VersionTokens;
  1147. if (Tokenize(VersionStr, basic_string<T>(L"."), VersionTokens) > 2) {
  1148. T *EndChar;
  1149. MajorVersionNumber = wcstoul(VersionTokens[0].c_str(),
  1150. &EndChar, 10);
  1151. MinorVersionNumber = wcstoul(VersionTokens[1].c_str(),
  1152. &EndChar, 10);
  1153. MajorBuildNumber = wcstoul(VersionTokens[2].c_str(),
  1154. &EndChar, 10);
  1155. //
  1156. // This can be expanded in future for more products.
  1157. //
  1158. if ((MajorVersionNumber == 5) && (MajorBuildNumber < SXS_CAB_LAYOUT_BUILD_NUMBER)) {
  1159. WinSxSLayout = SXS_LAYOUT_TYPE_DIRECTORY;
  1160. }
  1161. } else {
  1162. throw new InvalidInfSection<T>(L"Version", DosNetFileName.c_str());
  1163. }
  1164. } else {
  1165. throw new W32Exception<T>();
  1166. }
  1167. }
  1168. //
  1169. // Checks the media version against the current OS version
  1170. //
  1171. template <class T>
  1172. bool
  1173. CheckMediaVersion(
  1174. Arguments<T> &Args
  1175. )
  1176. {
  1177. bool Result = false;
  1178. #ifdef _IA64_
  1179. bool IA64Build = true;
  1180. #else
  1181. bool IA64Build = false;
  1182. #endif
  1183. try {
  1184. WCHAR DriverVer[MAX_PATH] = {0};
  1185. WCHAR ProductType[MAX_PATH] = {0};
  1186. if (GetPrivateProfileString(L"Version",
  1187. L"DriverVer",
  1188. NULL,
  1189. DriverVer,
  1190. sizeof(DriverVer)/sizeof(DriverVer[0]),
  1191. Args.DosNetFileName.c_str()) &&
  1192. GetPrivateProfileString(L"Miscellaneous",
  1193. L"ProductType",
  1194. NULL,
  1195. ProductType,
  1196. sizeof(ProductType)/sizeof(ProductType[0]),
  1197. Args.DosNetFileName.c_str())) {
  1198. basic_string<T> DriverVerStr = DriverVer;
  1199. basic_string<T> ProductTypeStr = ProductType;
  1200. basic_string<T>::size_type VerStartPos = DriverVerStr.find(L',');
  1201. T *EndPtr;
  1202. DWORD ProductType = wcstoul(ProductTypeStr.c_str(), &EndPtr, 10);
  1203. //
  1204. // For the time being only worry about CD type
  1205. // Allow only from Pro, Server, Blade and ADS SKU's.
  1206. //
  1207. Result = ((0 == ProductType) ||
  1208. (1 == ProductType) ||
  1209. (5 == ProductType) ||
  1210. (2 == ProductType));
  1211. /*
  1212. //
  1213. // make sure that the CD is pro CD and the version is the same
  1214. // version as we are running from
  1215. //
  1216. if ((ProductType == 0) && (VerStartPos != basic_string<T>::npos)) {
  1217. basic_string<T> VersionStr = DriverVerStr.substr(VerStartPos + 1);
  1218. vector<basic_string<T> > VersionTokens;
  1219. if (Tokenize(VersionStr, basic_string<T>(L"."), VersionTokens) >= 3) {
  1220. T *EndChar;
  1221. DWORD MajorVer = wcstoul(VersionTokens[0].c_str(),
  1222. &EndChar, 10);
  1223. DWORD MinorVer = wcstoul(VersionTokens[1].c_str(),
  1224. &EndChar, 10);
  1225. DWORD BuildNumber = wcstoul(VersionTokens[2].c_str(),
  1226. &EndChar, 10);
  1227. OSVERSIONINFO VersionInfo;
  1228. ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFO));
  1229. VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1230. if (MajorVer && MinorVer && BuildNumber &&
  1231. ::GetVersionEx(&VersionInfo)) {
  1232. Result = (VersionInfo.dwMajorVersion == MajorVer) &&
  1233. (VersionInfo.dwMinorVersion == MinorVer) &&
  1234. (VersionInfo.dwBuildNumber == BuildNumber);
  1235. }
  1236. }
  1237. }
  1238. */
  1239. }
  1240. } catch (...) {
  1241. Result = false;
  1242. }
  1243. return Result;
  1244. }
  1245. //
  1246. // Computes a SxS string hash, used in creating assembly identity
  1247. //
  1248. template <class T>
  1249. bool
  1250. ComputeStringHash(
  1251. const std::basic_string<T> &String,
  1252. ULONG &HashValue
  1253. )
  1254. {
  1255. bool Result = false;
  1256. ULONG TmpHashValue = 0;
  1257. if (String.length()) {
  1258. std::basic_string<T>::const_iterator Iter = String.begin();
  1259. while (Iter != String.end()) {
  1260. TmpHashValue = (TmpHashValue * 65599) + toupper(*Iter);
  1261. Iter++;
  1262. }
  1263. HashValue = TmpHashValue;
  1264. Result = true;
  1265. }
  1266. return Result;
  1267. }
  1268. //
  1269. // Computes an assembly identity hash for the specified
  1270. // Name and attribute pairs
  1271. //
  1272. template <class T>
  1273. bool
  1274. ComputeWinSxSHash(
  1275. IN std::map<std::basic_string<T>, std::basic_string<T> > &Attributes,
  1276. ULONG &Hash
  1277. )
  1278. {
  1279. bool Result = false;
  1280. std::map<std::basic_string<T>, std::basic_string<T> >::iterator Iter = Attributes.begin();
  1281. Hash = 0;
  1282. while (Iter != Attributes.end()) {
  1283. ULONG NameHash = 0;
  1284. ULONG ValueHash = 0;
  1285. ULONG AttrHash = 0;
  1286. if (ComputeStringHash((*Iter).first, NameHash) &&
  1287. ComputeStringHash((*Iter).second, ValueHash)) {
  1288. Result = true;
  1289. AttrHash = (NameHash * 65599) + ValueHash;
  1290. Hash = (Hash * 65599) + AttrHash;
  1291. }
  1292. Iter++;
  1293. }
  1294. return Result;
  1295. }
  1296. //
  1297. // Given a manifest file name generates a unique
  1298. // assmebly name (with ID) to be used as destination
  1299. // directory for the assembly
  1300. //
  1301. template <class T>
  1302. bool
  1303. GenerateWinSxSName(
  1304. IN std::basic_string<T> &ManifestName,
  1305. IN ULONG FileSize,
  1306. OUT std::basic_string<T> &SxSName
  1307. )
  1308. {
  1309. bool Result = false;
  1310. if (FileSize) {
  1311. bool Read = false;
  1312. PUCHAR Buffer = new UCHAR[FileSize + 1];
  1313. PWSTR UnicodeBuffer = new WCHAR[FileSize + 1];
  1314. std::wstring FileContent;
  1315. if (Buffer && UnicodeBuffer) {
  1316. HANDLE FileHandle;
  1317. //
  1318. // Open the manifest file
  1319. //
  1320. FileHandle = CreateFile(ManifestName.c_str(),
  1321. GENERIC_READ,
  1322. FILE_SHARE_READ,
  1323. NULL,
  1324. OPEN_EXISTING,
  1325. FILE_ATTRIBUTE_NORMAL,
  1326. NULL);
  1327. if (FileHandle != INVALID_HANDLE_VALUE) {
  1328. DWORD BytesRead = 0;
  1329. //
  1330. // Read the entire contents of the file
  1331. //
  1332. if (ReadFile(FileHandle,
  1333. Buffer,
  1334. FileSize,
  1335. &BytesRead,
  1336. NULL)) {
  1337. Read = (BytesRead == FileSize);
  1338. }
  1339. CloseHandle(FileHandle);
  1340. }
  1341. if (Read) {
  1342. //
  1343. // null terminate the buffer
  1344. //
  1345. Buffer[FileSize] = NULL;
  1346. //
  1347. // Convert the string to unicode string
  1348. //
  1349. if (MultiByteToWideChar(CP_UTF8,
  1350. 0,
  1351. (LPCSTR)Buffer,
  1352. FileSize + 1,
  1353. UnicodeBuffer,
  1354. FileSize + 1)) {
  1355. FileContent = UnicodeBuffer;
  1356. }
  1357. }
  1358. delete []Buffer;
  1359. delete []UnicodeBuffer;
  1360. } else {
  1361. if (Buffer) {
  1362. delete []Buffer;
  1363. }
  1364. if (UnicodeBuffer)
  1365. delete []UnicodeBuffer;
  1366. }
  1367. if (FileContent.length()) {
  1368. std::wstring IdentityKey = L"<" SXS_ASSEMBLY_MANIFEST_STD_ELEMENT_NAME_ASSEMBLY_IDENTITY;
  1369. std::wstring::size_type IdentityStartPos = FileContent.find(IdentityKey);
  1370. std::wstring::size_type IdentityEndPos = FileContent.find(L"/>", IdentityStartPos);
  1371. //
  1372. // Create name, value pairs for all the identity attributes specified
  1373. // in the manifest
  1374. //
  1375. if ((IdentityStartPos != IdentityKey.npos) &&
  1376. (IdentityEndPos != IdentityKey.npos)) {
  1377. std::map<std::wstring, std::wstring> IdentityPairs;
  1378. WCHAR *KeyNames[] = { SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  1379. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
  1380. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE,
  1381. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN,
  1382. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE,
  1383. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE,
  1384. NULL };
  1385. for (ULONG Index = 0; KeyNames[Index]; Index++) {
  1386. std::wstring::size_type ValueStartPos;
  1387. std::wstring::size_type ValueEndPos;
  1388. std::wstring KeyName = KeyNames[Index];
  1389. KeyName += L"=\"";
  1390. ValueStartPos = FileContent.find(KeyName, IdentityStartPos);
  1391. if (ValueStartPos != std::wstring::npos) {
  1392. ValueStartPos += KeyName.length();
  1393. ValueEndPos = FileContent.find(L"\"", ValueStartPos);
  1394. if ((ValueEndPos != std::wstring::npos) &&
  1395. (ValueEndPos > ValueStartPos) &&
  1396. (ValueEndPos <= IdentityEndPos)) {
  1397. IdentityPairs[KeyNames[Index]] = FileContent.substr(ValueStartPos,
  1398. ValueEndPos - ValueStartPos);
  1399. }
  1400. }
  1401. }
  1402. ULONG Hash = 0;
  1403. //
  1404. // Compute the assembly identity hash
  1405. //
  1406. if (ComputeWinSxSHash(IdentityPairs, Hash)) {
  1407. WCHAR *KeyValues[] = {
  1408. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE,
  1409. NULL,
  1410. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  1411. NULL,
  1412. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN,
  1413. NULL,
  1414. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
  1415. NULL,
  1416. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE,
  1417. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_LANGUAGE_MISSING_VALUE,
  1418. NULL};
  1419. std::wstring Name;
  1420. Result = true;
  1421. //
  1422. // Generate the unique assembly name based on
  1423. // its identity attribute name, value pairs
  1424. //
  1425. for (Index = 0; KeyValues[Index]; Index += 2) {
  1426. std::wstring Key(KeyValues[Index]);
  1427. std::wstring Value(IdentityPairs[Key]);
  1428. //
  1429. // Use default value, if none specified
  1430. //
  1431. if ((Value.length() == 0) && KeyValues[Index + 1]) {
  1432. Value = KeyValues[Index + 1];
  1433. }
  1434. if (Value.length()) {
  1435. Name += Value;
  1436. if (KeyValues[Index + 2]) {
  1437. Name += TEXT("_");
  1438. }
  1439. } else {
  1440. Result = false;
  1441. break; // required value is missing
  1442. }
  1443. }
  1444. if (Result) {
  1445. WCHAR Buffer[32] = {0};
  1446. (VOID)StringCchPrintfW(Buffer,
  1447. ARRAY_SIZE(Buffer),
  1448. L"%x",
  1449. Hash);
  1450. SxSName = Name + TEXT("_") + Buffer;
  1451. }
  1452. }
  1453. }
  1454. }
  1455. }
  1456. return Result;
  1457. }
  1458. //
  1459. // Processes the fusion assembly in the specified directory
  1460. //
  1461. template <class T>
  1462. ULONG
  1463. ProcessWinSxSFilesInDirectory(
  1464. IN FileListCreatorContext<T> &Context,
  1465. IN std::basic_string<T> &DirName
  1466. )
  1467. {
  1468. //
  1469. // persistent state
  1470. //
  1471. static basic_string<T> WinSxSDirCode = TEXT("124");
  1472. static basic_string<T> WinSxSManifestDirCode = TEXT("125");
  1473. static basic_string<T> WinSxSDir = Context.DirsSection->GetValue(WinSxSDirCode).GetValue(0);
  1474. static basic_string<T> WinSxSManifestDir = Context.DirsSection->GetValue(WinSxSManifestDirCode).GetValue(0);
  1475. static ULONG NextDirIndex = 123456; // some random number not used in layout.inx
  1476. ULONG FileCount = 0;
  1477. WIN32_FIND_DATA FindData = {0};
  1478. std::basic_string<T> SearchName = DirName + TEXT("\\*.MAN");
  1479. HANDLE SearchHandle;
  1480. //
  1481. // Search for the *.man file in the specfied directory
  1482. //
  1483. SearchHandle = FindFirstFile(SearchName.c_str(), &FindData);
  1484. if (SearchHandle != INVALID_HANDLE_VALUE) {
  1485. std::basic_string<T> ManifestName = DirName + TEXT("\\") + FindData.cFileName;
  1486. std::basic_string<T> WinSxSName;
  1487. bool NameGenerated = false;
  1488. //
  1489. // Generate the WinSxS destination name for the manifest
  1490. //
  1491. NameGenerated = GenerateWinSxSName(ManifestName,
  1492. FindData.nFileSizeLow,
  1493. WinSxSName);
  1494. FindClose(SearchHandle);
  1495. if (NameGenerated) {
  1496. T NextDirCode[64] = {0};
  1497. std::basic_string<T> SxSDirName = Context.Args.DestinationDirectory + WinSxSDir + TEXT("\\");
  1498. std::basic_string<T> ManifestDirName = Context.Args.DestinationDirectory + WinSxSManifestDir + TEXT("\\");
  1499. //
  1500. // Cache the directory, if not already done
  1501. //
  1502. if (Context.DestDirs.find(WinSxSDirCode) == Context.DestDirs.end()) {
  1503. Context.DestDirs[WinSxSDirCode] = SxSDirName;
  1504. }
  1505. if (Context.DestDirs.find(WinSxSManifestDirCode) == Context.DestDirs.end()) {
  1506. Context.DestDirs[WinSxSManifestDirCode] = ManifestDirName;
  1507. }
  1508. ZeroMemory(&FindData, sizeof(WIN32_FIND_DATA));
  1509. //
  1510. // Search for all the files in the specified directory
  1511. //
  1512. SearchName = DirName + TEXT("\\*");
  1513. SearchHandle = FindFirstFile(SearchName.c_str(), &FindData);
  1514. if (SearchHandle != INVALID_HANDLE_VALUE) {
  1515. std::basic_string<T> SrcFileName, DestFileName;
  1516. std::basic_string<T> ManifestDirCode;
  1517. if (sizeof(T) == sizeof(CHAR)) {
  1518. (VOID)StringCchPrintfA((PSTR)NextDirCode,
  1519. ARRAY_SIZE(NextDirCode),
  1520. "%d",
  1521. NextDirIndex++);
  1522. } else {
  1523. (VOID)StringCchPrintfW((PWSTR)NextDirCode,
  1524. ARRAY_SIZE(NextDirCode),
  1525. TEXT("%d"),
  1526. NextDirIndex++);
  1527. }
  1528. ManifestDirCode = NextDirCode;
  1529. do {
  1530. if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1531. SrcFileName = DirName + TEXT("\\") + FindData.cFileName;
  1532. DestFileName = SxSDirName;
  1533. std::basic_string<T> FileName(FindData.cFileName);
  1534. std::basic_string<T>::size_type DotPos = FileName.find(TEXT("."));
  1535. std::basic_string<T> Extension;
  1536. if (DotPos != FileName.npos) {
  1537. Extension = FileName.substr(DotPos + 1);
  1538. }
  1539. //
  1540. // *.man and *.cat go to the WinSxS\Manifest directory
  1541. //
  1542. if ((Extension == TEXT("man")) ||
  1543. (Extension == TEXT("MAN")) ||
  1544. (Extension == TEXT("cat")) ||
  1545. (Extension == TEXT("CAT"))) {
  1546. DestFileName = ManifestDirName;
  1547. DestFileName += WinSxSName;
  1548. if ((Extension == TEXT("man")) ||
  1549. (Extension == TEXT("MAN"))) {
  1550. DestFileName += TEXT(".Manifest");
  1551. } else {
  1552. DestFileName += TEXT(".");
  1553. DestFileName += Extension;
  1554. }
  1555. } else {
  1556. //
  1557. // Cache the directory, if not already done
  1558. //
  1559. if (Context.DestDirs.find(ManifestDirCode) == Context.DestDirs.end()) {
  1560. Context.DestDirs[ManifestDirCode] = SxSDirName + WinSxSName;
  1561. }
  1562. //
  1563. // Each file other than *.man & *.cat go the unique
  1564. // assembly directory created
  1565. //
  1566. DestFileName += WinSxSName;
  1567. DestFileName += TEXT("\\");
  1568. DestFileName += FileName;
  1569. }
  1570. //
  1571. // Queue this file for copying
  1572. //
  1573. Context.WinSxSFileList[SrcFileName] = DestFileName;
  1574. FileCount++;
  1575. }
  1576. }
  1577. while (FindNextFile(SearchHandle, &FindData));
  1578. FindClose(SearchHandle);
  1579. }
  1580. }
  1581. }
  1582. return FileCount;
  1583. }
  1584. template<class T>
  1585. bool
  1586. WinSxsExtractVersionInfo(
  1587. IN basic_string<T> ManifestName,
  1588. OUT basic_string<T> &Version
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. Extracts the version information string (like 1.0.0.1) from
  1593. the given manifest name.
  1594. NOTE: Assumes that version information is the third-last (third
  1595. from the last) value in the assembly Id.
  1596. Arguments:
  1597. ManifestName - full manifest name
  1598. Version - placeholder for extracted version information
  1599. Return Value:
  1600. true on success, otherwise false
  1601. --*/
  1602. {
  1603. bool Result = false;
  1604. basic_string<T>::size_type VersionEnd = ManifestName.rfind((T)TEXT('_'));
  1605. if (VersionEnd != ManifestName.npos) {
  1606. VersionEnd = ManifestName.rfind((T)TEXT('_'), VersionEnd - 1);
  1607. if (VersionEnd != ManifestName.npos) {
  1608. basic_string<T>::size_type VersionStart = ManifestName.rfind((T)TEXT('_'), VersionEnd - 1);
  1609. VersionEnd--;
  1610. if (VersionStart != ManifestName.npos) {
  1611. Version = ManifestName.substr(VersionStart + 1, VersionEnd - VersionStart);
  1612. Result = (Version.length() > 0);
  1613. }
  1614. }
  1615. }
  1616. return Result;
  1617. }
  1618. template <class T>
  1619. bool
  1620. WinSxsFixFilePaths(
  1621. IN FileListCreatorContext<T> &Context,
  1622. IN OUT FILE_IN_CABINET_INFO &FileInfo
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. This routine fixes the destination path in the
  1627. FileInfo argument
  1628. Arguments:
  1629. Context - FileListCreatorContext instance as PVOID.
  1630. FileInfo - Cab file iteration FileInfo instance
  1631. Return Value:
  1632. true if the destination name was fixed otherwise false.
  1633. --*/
  1634. {
  1635. bool Result = true;
  1636. basic_string<T> SourceName;
  1637. static basic_string<T> ManifestExtension((T *)TEXT(".Manifest"));
  1638. static basic_string<T> PolicyExtension((T *)TEXT(".Policy"));
  1639. static basic_string<T> PolicyKey((T *)TEXT("_policy"));
  1640. static basic_string<T> ManExtKey((T *)TEXT(".man"));
  1641. static basic_string<T> CatExtKey((T *)TEXT(".cat"));
  1642. static basic_string<T> WinSxSDirCode((T *)TEXT("124"));
  1643. static basic_string<T> WinSxSManifestDirCode((T *)TEXT("125"));
  1644. static basic_string<T> WinSxSDir = Context.Args.DestinationDirectory +
  1645. Context.DirsSection->GetValue(WinSxSDirCode).GetValue(0)
  1646. + (T *)TEXT("\\") ;
  1647. static basic_string<T> WinSxSManifestDir = Context.Args.DestinationDirectory +
  1648. Context.DirsSection->GetValue(WinSxSManifestDirCode).GetValue(0)
  1649. + (T *)TEXT("\\") ;
  1650. static basic_string<T> WinSxSPoliciesDir = WinSxSDir + (T *)TEXT("Policies\\");
  1651. if (sizeof(T) == sizeof(CHAR)) {
  1652. SourceName = (T *)(_strlwr((PSTR)(FileInfo.NameInCabinet)));
  1653. } else {
  1654. SourceName = (T *)(_wcslwr((PWSTR)(FileInfo.NameInCabinet)));
  1655. }
  1656. basic_string<T> SourcePath;
  1657. basic_string<T> AssemblyId;
  1658. basic_string<T> SourceFileName;
  1659. basic_string<T> SourceFilePart;
  1660. basic_string<T> SourceFileExt;
  1661. basic_string<T>::size_type SlashPos = SourceName.npos;
  1662. basic_string<T> DestinationName;
  1663. if (sizeof(T) == sizeof(CHAR)) {
  1664. SlashPos = SourceName.rfind('\\');
  1665. } else {
  1666. SlashPos = SourceName.rfind(L'\\');
  1667. }
  1668. if (SlashPos != SourceName.npos) {
  1669. //
  1670. // extract required substrings from the source name
  1671. //
  1672. AssemblyId = SourceName.substr(0, SlashPos);
  1673. SourcePath = SourceName.substr(0, SlashPos + 1);
  1674. SlashPos++;
  1675. SourceFileName = SourceName.substr(SlashPos);
  1676. SourceFilePart = SourceFileName.substr(0, SourceFileName.rfind((T *)TEXT(".")));
  1677. SourceFileExt = SourceFileName.substr(SourceFileName.rfind((T *)TEXT(".")));
  1678. //
  1679. // what kind of file is it?
  1680. //
  1681. bool PolicyFile = (SourcePath.find(PolicyKey) != SourcePath.npos);
  1682. bool ManifestFile = (SourceName.find(ManExtKey) != SourcePath.npos);
  1683. bool CatalogFile = (SourceName.find(CatExtKey) != SourcePath.npos);
  1684. if (PolicyFile) {
  1685. basic_string<T> VersionPart;
  1686. if (WinSxsExtractVersionInfo(SourcePath, VersionPart)) {
  1687. DestinationName = WinSxSPoliciesDir + SourcePath + VersionPart;
  1688. if (ManifestFile) {
  1689. DestinationName += PolicyExtension;
  1690. } else {
  1691. DestinationName += SourceFileExt;
  1692. }
  1693. } else {
  1694. Result = false; // couldn't extract the version information
  1695. }
  1696. } else if (ManifestFile) {
  1697. DestinationName = WinSxSManifestDir + AssemblyId + ManifestExtension;
  1698. } else if (CatalogFile) {
  1699. DestinationName = WinSxSManifestDir + AssemblyId + SourceFileExt;
  1700. } else {
  1701. DestinationName = WinSxSDir + SourcePath + SourceFileName;
  1702. }
  1703. } else {
  1704. Result = false; // invalid source file name
  1705. }
  1706. if (Result) {
  1707. if (sizeof(T) == sizeof(CHAR)) {
  1708. (VOID)StringCchCopyA((PSTR)(FileInfo.FullTargetName),
  1709. ARRAY_SIZE(FileInfo.FullTargetName),
  1710. (PCSTR)DestinationName.c_str());
  1711. } else {
  1712. (VOID)StringCchCopyW((PWSTR)(FileInfo.FullTargetName),
  1713. ARRAY_SIZE(FileInfo.FullTargetName),
  1714. (PCWSTR)DestinationName.c_str());
  1715. }
  1716. }
  1717. return Result;
  1718. }
  1719. template <class T>
  1720. UINT
  1721. WinSxsCabinetCallback(
  1722. IN PVOID Context,
  1723. IN UINT Notification,
  1724. IN UINT_PTR Param1,
  1725. IN UINT_PTR Param2
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This routine processes WinSxS files in Cabinet.
  1730. Arguments:
  1731. Context - FileListCreatorContext instance as PVOID.
  1732. Notification - CAB Iteration Code
  1733. Param1 - First parameter for Notification.
  1734. Param2 - Second parameter for Notification.
  1735. Return Value:
  1736. Appropriate return code to continue iterating, copy the file or skip
  1737. the file in cab.
  1738. --*/
  1739. {
  1740. UINT ReturnCode = NO_ERROR;
  1741. FileListCreatorContext<T> *FlContext = (FileListCreatorContext<T> *)Context;
  1742. PFILE_IN_CABINET_INFO FileInfo = NULL;
  1743. PFILEPATHS FilePaths = NULL;
  1744. basic_string<T> &FileName = FlContext->CurrentFileName;
  1745. switch (Notification) {
  1746. case SPFILENOTIFY_FILEINCABINET:
  1747. ReturnCode = FILEOP_SKIP;
  1748. FileInfo = (PFILE_IN_CABINET_INFO)Param1;
  1749. if (WinSxsFixFilePaths(*FlContext, *FileInfo)) {
  1750. if (sizeof(T) == sizeof(CHAR)) {
  1751. FileName = (const T *)(FileInfo->NameInCabinet);
  1752. } else {
  1753. FileName = (const T *)(FileInfo->NameInCabinet);
  1754. }
  1755. if (!FlContext->Args.SkipFileCopy) {
  1756. //
  1757. // create the destination directory if it doesnot exist
  1758. //
  1759. basic_string<T> DestinationName = (T *)(FileInfo->FullTargetName);
  1760. basic_string<T> DestinationDir = DestinationName.substr(0, DestinationName.rfind((T *)TEXT("\\")));
  1761. if (sizeof(T) == sizeof(CHAR)) {
  1762. if (_access((PCSTR)(DestinationDir.c_str()), 0)) {
  1763. CreateDirectories(DestinationDir, NULL);
  1764. }
  1765. } else {
  1766. if (_waccess((PCWSTR)(DestinationDir.c_str()), 0)) {
  1767. CreateDirectories(DestinationDir, NULL);
  1768. }
  1769. }
  1770. ReturnCode = FILEOP_DOIT;
  1771. } else {
  1772. ReturnCode = FILEOP_SKIP;
  1773. FlContext->FileCount++;
  1774. if (FlContext->Args.Verbose) {
  1775. std::cout << GetFormattedMessage(ThisModule,
  1776. FALSE,
  1777. Message,
  1778. sizeof(Message)/sizeof(Message[0]),
  1779. MSG_EXTRACT_FILES_FROM_CAB_NOTIFICATION,
  1780. FlContext->WinSxsCabinetFileName.c_str(),
  1781. FileInfo->NameInCabinet,
  1782. FileInfo->FullTargetName) << std::endl;
  1783. }
  1784. }
  1785. } else {
  1786. ReturnCode = FILEOP_ABORT;
  1787. }
  1788. break;
  1789. case SPFILENOTIFY_FILEEXTRACTED:
  1790. FilePaths = (PFILEPATHS)Param1;
  1791. if (FilePaths->Win32Error) {
  1792. std::cout << GetFormattedMessage(ThisModule,
  1793. FALSE,
  1794. Message,
  1795. sizeof(Message)/sizeof(Message[0]),
  1796. MSG_ERROR_EXTRACTING_FILES,
  1797. FilePaths->Win32Error,
  1798. FilePaths->Source,
  1799. FileName.c_str(),
  1800. FilePaths->Target) << std::endl;
  1801. } else {
  1802. FlContext->FileCount++;
  1803. if (FlContext->Args.Verbose) {
  1804. std::cout << GetFormattedMessage(ThisModule,
  1805. FALSE,
  1806. Message,
  1807. sizeof(Message)/sizeof(Message[0]),
  1808. MSG_EXTRACTED_FILES_FROM_CAB_NOTIFICATION,
  1809. FilePaths->Source,
  1810. FileName.c_str(),
  1811. FilePaths->Target) << std::endl;
  1812. }
  1813. }
  1814. break;
  1815. default:
  1816. break;
  1817. }
  1818. return ReturnCode;
  1819. }
  1820. //
  1821. // Copies all the required files in given CAB file to the specified
  1822. // destination directory
  1823. //
  1824. template <class T>
  1825. ULONG
  1826. ProcessWinSxsCabFiles(
  1827. IN FileListCreatorContext<T> &Context,
  1828. IN const std::basic_string<T> &CabFileName
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. This routine processes the given CAB file for WinSxS. It extracts
  1833. the required manifest, catalog and policy files and installs them
  1834. to the the appropriate assembly on the destination.
  1835. Arguments:
  1836. Context - FileListCreatorContext instance as PVOID.
  1837. CabFileName - Fully qualitifed cab file name that needs to be processed.
  1838. Return Value:
  1839. Number of files processed.
  1840. --*/
  1841. {
  1842. ULONG Count = Context.FileCount;
  1843. BOOL Result = FALSE;
  1844. Context.WinSxsCabinetFileName = CabFileName;
  1845. if (sizeof(T) == sizeof(CHAR)) {
  1846. Result = SetupIterateCabinetA((PCSTR)CabFileName.c_str(),
  1847. NULL,
  1848. (PSP_FILE_CALLBACK_A)WinSxsCabinetCallback<char>,
  1849. &Context);
  1850. } else {
  1851. Result = SetupIterateCabinetW((PCWSTR)CabFileName.c_str(),
  1852. NULL,
  1853. (PSP_FILE_CALLBACK_W)WinSxsCabinetCallback<wchar_t>,
  1854. &Context);
  1855. }
  1856. if (!Result) {
  1857. cout << GetFormattedMessage(ThisModule,
  1858. FALSE,
  1859. Message,
  1860. sizeof(Message)/sizeof(Message[0]),
  1861. MSG_ERROR_ITERATING_CAB_FILE,
  1862. GetLastError(),
  1863. CabFileName.c_str()) << endl;
  1864. }
  1865. return Context.FileCount - Count;
  1866. }
  1867. template <class T>
  1868. ULONG
  1869. ProcessWinSxSFilesForCabLayout(
  1870. IN FileListCreatorContext<T> &Context,
  1871. IN std::basic_string<T> &SearchPattern
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. Processes Win SXS files for CAB layout.
  1876. Arguments:
  1877. Context : Current Processing Context.
  1878. SearchPattern : The search pattern for cab files.
  1879. Return Value:
  1880. The number of files which were processed.
  1881. --*/
  1882. {
  1883. ULONG FileCount = 0;
  1884. WIN32_FIND_DATA FindData = {0};
  1885. std::basic_string<T> SearchName = Context.Args.SourceDirectory + SearchPattern;
  1886. HANDLE SearchHandle;
  1887. SearchHandle = FindFirstFile(SearchName.c_str(), &FindData);
  1888. if (SearchHandle != INVALID_HANDLE_VALUE) {
  1889. do {
  1890. if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1891. basic_string<T> FullCabFileName = Context.Args.SourceDirectory + FindData.cFileName;
  1892. //
  1893. // Process any manifests present in the current directory
  1894. //
  1895. FileCount += ProcessWinSxsCabFiles(Context, FullCabFileName);
  1896. }
  1897. }
  1898. while (FindNextFile(SearchHandle, &FindData));
  1899. FindClose(SearchHandle);
  1900. }
  1901. return FileCount;
  1902. }
  1903. template <class T>
  1904. ULONG
  1905. ProcessWinSxSFilesForDirectoryLayout(
  1906. IN FileListCreatorContext<T> &Context,
  1907. IN std::basic_string<T> &DirName
  1908. )
  1909. /*++
  1910. Routine Description:
  1911. Processes Win SXS files for flat/directory layout.
  1912. Arguments:
  1913. Context: Current Processing context.
  1914. DirName: Current directory to be processed.
  1915. Return Value:
  1916. The number of files which were processed.
  1917. --*/
  1918. {
  1919. WIN32_FIND_DATA FindData = {0};
  1920. std::basic_string<T> SearchName;
  1921. static std::basic_string<T> CurrDir = TEXT(".");
  1922. static std::basic_string<T> ParentDir = TEXT("..");
  1923. ULONG FileCount = 0;
  1924. HANDLE SearchHandle;
  1925. SearchName = DirName + TEXT("\\*");
  1926. SearchHandle = FindFirstFile(SearchName.c_str(), &FindData);
  1927. if (SearchHandle != INVALID_HANDLE_VALUE) {
  1928. do {
  1929. if ((CurrDir != FindData.cFileName) && (ParentDir != FindData.cFileName)) {
  1930. //
  1931. // If we hit a directory then search again in that directory
  1932. //
  1933. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1934. std::basic_string<T> NewDirName = DirName + TEXT("\\") + FindData.cFileName;
  1935. FileCount += ProcessWinSxSFilesForDirectoryLayout(Context, NewDirName);
  1936. } else {
  1937. //
  1938. // Process any manifests present in the current directory
  1939. //
  1940. FileCount += ProcessWinSxSFilesInDirectory(Context, DirName);
  1941. //
  1942. // done with this directory and sub-directories
  1943. //
  1944. break;
  1945. }
  1946. }
  1947. }
  1948. while (FindNextFile(SearchHandle, &FindData));
  1949. FindClose(SearchHandle);
  1950. }
  1951. return FileCount;
  1952. }
  1953. //
  1954. // Processes the asms directory and installs fusion assemblies in an
  1955. // offline fashion
  1956. //
  1957. template <class T>
  1958. ULONG
  1959. ProcessWinSxSFiles(
  1960. IN FileListCreatorContext<T> &Context
  1961. )
  1962. {
  1963. ULONG FileCount = 0;
  1964. if (Context.Args.WinSxSLayout == SXS_LAYOUT_TYPE_DIRECTORY) {
  1965. basic_string<T> AsmsDir = Context.Args.SourceDirectory + TEXT("asms");
  1966. FileCount = ProcessWinSxSFilesForDirectoryLayout(Context, AsmsDir);
  1967. } else {
  1968. basic_string<T> SearchPattern = TEXT("asms*.cab");
  1969. FileCount = ProcessWinSxSFilesForCabLayout(Context, SearchPattern);
  1970. }
  1971. return FileCount;
  1972. }
  1973. //
  1974. // Process NLS specific files
  1975. //
  1976. template <class T>
  1977. FileListCreatorContext<T>::FileListCreatorContext(
  1978. Arguments<T> &PrgArgs,
  1979. Section<T> *Curr,
  1980. Section<T> *Dirs,
  1981. InfFile<T> &ConfigInf,
  1982. InfFile<T> &IntlInf,
  1983. InfFile<T> &FontInf,
  1984. DriverIndexInfFile<T> &DrvIdxFile
  1985. ): Args(PrgArgs),
  1986. ConfigInfFile(ConfigInf),
  1987. IntlInfFile(IntlInf),
  1988. FontInfFile(FontInf),
  1989. DriverIdxFile(DrvIdxFile)
  1990. /*++
  1991. Routine Description:
  1992. Constructor
  1993. Arguments:
  1994. Bunch of them.
  1995. Return Value:
  1996. FileListCreatorContext object instance.
  1997. --*/
  1998. {
  1999. CurrentSection = Curr;
  2000. DirsSection = Dirs;
  2001. SkipInfFiles = false;
  2002. FileCount = 0;
  2003. ProcessingExtraFiles = false;
  2004. DummyDirectoryId = 50000; // we start with 50000 and count upwards
  2005. //
  2006. // get hold of the windows directory which we need to prune the NLS
  2007. // copy file list
  2008. //
  2009. DWORD Length;
  2010. T WindowsDirBuffer[MAX_PATH] = {0};
  2011. if (sizeof(T) == sizeof(CHAR)) {
  2012. Length = GetWindowsDirectoryA((PSTR)WindowsDirBuffer, sizeof(WindowsDirBuffer)/sizeof(T));
  2013. if (Length){
  2014. if (((PSTR)WindowsDirBuffer)[Length] != '\\') {
  2015. (VOID)StringCchCatA((PSTR)WindowsDirBuffer,
  2016. ARRAY_SIZE(WindowsDirBuffer),
  2017. "\\");
  2018. }
  2019. _strlwr((PSTR)WindowsDirBuffer);
  2020. WindowsDirectory = basic_string<T>((const T*)WindowsDirBuffer);
  2021. }
  2022. } else {
  2023. Length = GetWindowsDirectoryW((PWSTR)WindowsDirBuffer, sizeof(WindowsDirBuffer)/sizeof(T));
  2024. if (Length) {
  2025. if (((PWSTR)WindowsDirBuffer)[Length] != L'\\') {
  2026. (VOID)StringCchCatW((PWSTR)WindowsDirBuffer,
  2027. ARRAY_SIZE(WindowsDirBuffer),
  2028. L"\\");
  2029. }
  2030. _wcslwr((PWSTR)WindowsDirBuffer);
  2031. WindowsDirectory = basic_string<T>((const T*)WindowsDirBuffer);
  2032. }
  2033. }
  2034. if (!WindowsDirBuffer[0]) {
  2035. throw new W32Exception<T>();
  2036. }
  2037. }
  2038. template <class T>
  2039. ULONG
  2040. FileListCreatorContext<T>::ProcessNlsFiles(
  2041. VOID
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. Does the necessary work to process the NLS files from INTL.INF
  2046. & FONT.INF files.
  2047. NOTE : For all locales language group 1 (LG_INSTALL_1 section) is
  2048. processed.
  2049. Arguments:
  2050. None.
  2051. Return Value:
  2052. Number of NLS files that were added to the files to copy list.
  2053. --*/
  2054. {
  2055. ULONG FileCount = 0;
  2056. //
  2057. // get hold of the necessary copy file sections
  2058. //
  2059. Section<T> *RegionalSection = ConfigInfFile.GetSection(REGIONAL_SECTION_NAME);
  2060. if (!RegionalSection) {
  2061. throw new InvalidInfSection<T>(REGIONAL_SECTION_NAME,
  2062. ConfigInfFile.GetName());
  2063. }
  2064. SectionValues<T> *LangGroups;
  2065. //
  2066. // [LanguageGroup] section is optional
  2067. //
  2068. try {
  2069. LangGroups = &(RegionalSection->GetValue(LANGUAGE_GROUP_KEY));
  2070. } catch (...) {
  2071. LangGroups = NULL;
  2072. }
  2073. SectionValues<T> &Language = RegionalSection->GetValue(LANGUAGE_KEY);
  2074. ULONG LangGroupCount = LangGroups ? LangGroups->Count() : 0;
  2075. //
  2076. // go through all language group sections and create a list of unique
  2077. // language group sections that need to be processed.
  2078. //
  2079. std::map< std::basic_string<T>, std::basic_string<T> > RegSectionsToProcess;
  2080. for (ULONG Index = 0; Index < LangGroupCount; Index++) {
  2081. //
  2082. // get the language group section
  2083. //
  2084. std::basic_string<T> LangGroupName = LANGGROUP_SECTION_PREFIX;
  2085. LangGroupName += LangGroups->GetValue(Index);
  2086. //std::cout << LangGroupName << std::endl;
  2087. if (sizeof(T) == sizeof(CHAR)) {
  2088. _strlwr((PSTR)LangGroupName.c_str());
  2089. } else {
  2090. _wcslwr((PWSTR)LangGroupName.c_str());
  2091. }
  2092. //
  2093. // if the section is not already there then add it
  2094. //
  2095. if (RegSectionsToProcess.find(LangGroupName) == RegSectionsToProcess.end()) {
  2096. // std::cout << "Adding : " << LangGroupName << std::endl;
  2097. RegSectionsToProcess[LangGroupName] = LangGroupName;
  2098. }
  2099. }
  2100. //
  2101. // process the language section
  2102. //
  2103. T LanguageIdStr[64];
  2104. T *EndPtr;
  2105. DWORD LanguageId;
  2106. if (sizeof(T) == sizeof(CHAR)) {
  2107. LanguageId = strtoul((PSTR)Language.GetValue(0).c_str(),
  2108. (PSTR *)&EndPtr,
  2109. 16);
  2110. (VOID)StringCchPrintfA((PSTR)LanguageIdStr,
  2111. ARRAY_SIZE(LanguageIdStr),
  2112. "%08x",
  2113. LanguageId);
  2114. _strlwr((PSTR)LanguageIdStr);
  2115. } else {
  2116. LanguageId = wcstoul((PWSTR)Language.GetValue(0).c_str(),
  2117. (PWSTR *)&EndPtr,
  2118. 16);
  2119. (VOID)StringCchPrintfW((PWSTR)LanguageIdStr,
  2120. ARRAY_SIZE(LanguageIdStr),
  2121. L"%08x",
  2122. LanguageId);
  2123. _wcslwr((PWSTR)LanguageIdStr);
  2124. }
  2125. std::basic_string<T> LangSectionName = LanguageIdStr;
  2126. RegSectionsToProcess[LangSectionName] = LangSectionName;
  2127. //
  2128. // make sure the required language groups for this
  2129. // language are also processed
  2130. //
  2131. Section<T> *LocaleSection = IntlInfFile.GetSection(LOCALES_SECTION_NAME);
  2132. if (!LocaleSection) {
  2133. throw new InvalidInfSection<T>(LOCALES_SECTION_NAME,
  2134. IntlInfFile.GetName());
  2135. }
  2136. SectionValues<T> &LocaleValues = LocaleSection->GetValue(LangSectionName);
  2137. std::basic_string<T> NeededLangGroup = LANGGROUP_SECTION_PREFIX + LocaleValues.GetValue(LANG_GROUP1_INDEX);
  2138. RegSectionsToProcess[NeededLangGroup] = NeededLangGroup;
  2139. //
  2140. // add the font registry entries also
  2141. //
  2142. T FontSectionName[MAX_PATH];
  2143. if (sizeof(T) == sizeof(CHAR)) {
  2144. (VOID)StringCchPrintfA((PSTR)FontSectionName,
  2145. ARRAY_SIZE(FontSectionName),
  2146. (PSTR)FONT_CP_REGSECTION_FMT_STR.c_str(),
  2147. (PSTR)LocaleValues.GetValue(OEM_CP_INDEX).c_str(),
  2148. DEFAULT_FONT_SIZE);
  2149. } else {
  2150. (VOID)StringCchPrintfW((PWSTR)FontSectionName,
  2151. ARRAY_SIZE(FontSectionName),
  2152. (PWSTR)FONT_CP_REGSECTION_FMT_STR.c_str(),
  2153. (PWSTR)LocaleValues.GetValue(OEM_CP_INDEX).c_str(),
  2154. DEFAULT_FONT_SIZE);
  2155. }
  2156. RegSectionsToProcess[FontSectionName] = FontSectionName;
  2157. std::map< std::wstring, std::wstring >::iterator Iter = RegSectionsToProcess.find(DEFAULT_LANGGROUP_NAME);
  2158. if (Iter == RegSectionsToProcess.end()) {
  2159. RegSectionsToProcess[DEFAULT_LANGGROUP_NAME] = DEFAULT_LANGGROUP_NAME;
  2160. }
  2161. //
  2162. // NOTE : Rather than parsing INTL.INF and FONT.INF files manually
  2163. // we use file queue to populate the queue and then later use the file
  2164. // queue to initialize our copy list map data structure.
  2165. //
  2166. //
  2167. // Initialize file queue
  2168. //
  2169. HINF IntlInfHandle = (HINF)IntlInfFile.GetInfHandle();
  2170. HINF FontInfHandle = (HINF)FontInfFile.GetInfHandle();
  2171. if (sizeof(T) == sizeof(CHAR)) {
  2172. if (!SetupOpenAppendInfFileA((PSTR)Args.LayoutName.c_str(),
  2173. IntlInfHandle,
  2174. NULL)) {
  2175. throw new W32Exception<T>();
  2176. }
  2177. if (!SetupOpenAppendInfFileA((PSTR)Args.LayoutName.c_str(),
  2178. FontInfHandle,
  2179. NULL)) {
  2180. throw new W32Exception<T>();
  2181. }
  2182. } else {
  2183. if (!SetupOpenAppendInfFileW((PWSTR)Args.LayoutName.c_str(),
  2184. IntlInfHandle,
  2185. NULL)) {
  2186. throw new W32Exception<T>();
  2187. }
  2188. if (!SetupOpenAppendInfFileW((PWSTR)Args.LayoutName.c_str(),
  2189. FontInfHandle,
  2190. NULL)) {
  2191. throw new W32Exception<T>();
  2192. }
  2193. }
  2194. HSPFILEQ FileQueueHandle = SetupOpenFileQueue();
  2195. if (FileQueueHandle == INVALID_HANDLE_VALUE) {
  2196. throw new W32Exception<T>();
  2197. }
  2198. //
  2199. // add copy file sections to the queue
  2200. //
  2201. BOOL Result;
  2202. Iter = RegSectionsToProcess.begin();
  2203. while (Iter != RegSectionsToProcess.end()) {
  2204. // cout << (*Iter).first << endl;
  2205. //
  2206. // process each section
  2207. //
  2208. if (sizeof(T) == sizeof(CHAR)) {
  2209. Result = SetupInstallFilesFromInfSectionA(IntlInfHandle,
  2210. NULL,
  2211. FileQueueHandle,
  2212. (PCSTR)(*Iter).first.c_str(),
  2213. (PCSTR)Args.SourceDirectoryRoot.c_str(),
  2214. 0);
  2215. } else {
  2216. Result = SetupInstallFilesFromInfSectionW(IntlInfHandle,
  2217. NULL,
  2218. FileQueueHandle,
  2219. (PCWSTR)(*Iter).first.c_str(),
  2220. (PCWSTR)Args.SourceDirectoryRoot.c_str(),
  2221. 0);
  2222. }
  2223. if (!Result) {
  2224. throw new W32Exception<T>();
  2225. }
  2226. Iter++;
  2227. }
  2228. //
  2229. // scan the queue and populate FileListCreatorContext<T> copy list
  2230. // data structure
  2231. //
  2232. DWORD ScanResult = 0;
  2233. if (sizeof(T) == sizeof(CHAR)) {
  2234. Result = SetupScanFileQueueA(FileQueueHandle,
  2235. SPQ_SCAN_USE_CALLBACKEX,
  2236. NULL,
  2237. (PSP_FILE_CALLBACK_A)NlsFileQueueScanWorker,
  2238. this,
  2239. &ScanResult);
  2240. } else {
  2241. Result = SetupScanFileQueueW(FileQueueHandle,
  2242. SPQ_SCAN_USE_CALLBACKEX,
  2243. NULL,
  2244. (PSP_FILE_CALLBACK_W)NlsFileQueueScanWorker,
  2245. this,
  2246. &ScanResult);
  2247. }
  2248. SetupCloseFileQueue(FileQueueHandle);
  2249. //
  2250. // Add the Nls directory entries to main directory map
  2251. //
  2252. ProcessNlsDirMapEntries();
  2253. //
  2254. // Remove duplicate Nls file entries
  2255. //
  2256. RemoveDuplicateNlsEntries();
  2257. //
  2258. // Move the driver cab files to driver cab list
  2259. //
  2260. MoveDriverCabNlsFiles();
  2261. //
  2262. // After all this work, how many NLS files do we actually
  2263. // want to copy ?
  2264. //
  2265. return NlsFileMap.size();
  2266. }
  2267. template <class T>
  2268. void
  2269. FileListCreatorContext<T>::MoveDriverCabNlsFiles(
  2270. void
  2271. )
  2272. /*++
  2273. Routine Description:
  2274. Takes each NLS file entry to be copied and moves it to
  2275. the driver cab file copy list if the file is present
  2276. in driver cab so that we can extract the file from
  2277. driver cab.
  2278. Arguments:
  2279. None.
  2280. Return Value:
  2281. None.
  2282. --*/
  2283. {
  2284. std::map<std::basic_string<T>, std::basic_string<T> >::iterator NlsIter, DelIter;
  2285. T Slash;
  2286. if (sizeof(T) == sizeof(CHAR)) {
  2287. Slash = (T)'\\';
  2288. } else {
  2289. Slash = (T)L'\\';
  2290. }
  2291. for (NlsIter = NlsFileMap.begin(); NlsIter != NlsFileMap.end();) {
  2292. const std::basic_string<T> &Key = (*NlsIter).first;
  2293. std::basic_string<T>::size_type KeyStart = Key.rfind(Slash);
  2294. std::basic_string<T> FileKey;
  2295. DelIter = NlsFileMap.end();
  2296. if (KeyStart != Key.npos) {
  2297. FileKey = Key.substr(Key.rfind(Slash) + 1);
  2298. }
  2299. if (FileKey.length()) {
  2300. if (sizeof(T) == sizeof(CHAR)) {
  2301. _strlwr((PSTR)FileKey.c_str());
  2302. } else {
  2303. _wcslwr((PWSTR)FileKey.c_str());
  2304. }
  2305. const basic_string<T> &DriverCabFileName = GetDriverCabFileName(FileKey);
  2306. if (DriverCabFileName.length()) {
  2307. // std::cout << "Moved to driver cab list : (" << FileKey << ")" << std::endl;
  2308. AddFileToCabFileList(DriverCabFileName,
  2309. FileKey,
  2310. (*NlsIter).second);
  2311. DelIter = NlsIter;
  2312. } else {
  2313. // std::cout << "Not present in driver cab list : (" << FileKey << ")" << std::endl;
  2314. }
  2315. }
  2316. NlsIter++;
  2317. if (DelIter != NlsFileMap.end()) {
  2318. NlsFileMap.erase(DelIter);
  2319. }
  2320. }
  2321. }
  2322. template <class T>
  2323. UINT
  2324. FileListCreatorContext<T>::NlsFileQueueScanWorker(
  2325. PVOID Context,
  2326. UINT Notification,
  2327. UINT_PTR Param1,
  2328. UINT_PTR Param2
  2329. )
  2330. /*++
  2331. Routine Description:
  2332. The callback routine for the file queue scan. Takes each
  2333. node and copies the relevant information to Nls file copy
  2334. list and caches the directory names in Nls directory map.
  2335. Arguments:
  2336. Context - FileListCreatorContext in disguise.
  2337. Notification - Type of notification.
  2338. Param1 & Param2 - Polymorphic arguments based on type of
  2339. notification.
  2340. Return Value:
  2341. 0 to continue the scan or 1 to stop the scan.
  2342. --*/
  2343. {
  2344. UINT Result = 0; // continue on
  2345. // cout << "Scanning (" << std::hex << Notification << ")" << endl;
  2346. if (Notification == SPFILENOTIFY_QUEUESCAN_EX) {
  2347. FileListCreatorContext<T> &fl = *(FileListCreatorContext<T> *)Context;
  2348. std::basic_string<T> SrcFileName, DestFileName, SrcFileKey, DestFileKey;
  2349. T TargetFileNameBuffer[MAX_PATH];
  2350. bool ProcessEntry = false;
  2351. if (sizeof(T) == sizeof(CHAR)) {
  2352. PFILEPATHS_A FileNodeInfo = (PFILEPATHS_A)Param1;
  2353. if (FileNodeInfo) {
  2354. SrcFileName = std::basic_string<T>((const T*)FileNodeInfo->Source);
  2355. DestFileName = std::basic_string<T>((const T*)FileNodeInfo->Target);
  2356. _strlwr((PSTR)SrcFileName.c_str());
  2357. _strlwr((PSTR)DestFileName.c_str());
  2358. basic_string<T>::size_type SlashPos = SrcFileName.rfind((T)'\\');
  2359. if (SlashPos != SrcFileName.npos) {
  2360. SrcFileKey = SrcFileName.substr(SlashPos + 1);
  2361. SlashPos = DestFileName.rfind((T)L'\\');
  2362. if (SlashPos != DestFileName.npos) {
  2363. DestFileKey = DestFileName.substr(SlashPos + 1);
  2364. DestFileName[fl.WindowsDirectory.length()] = 0;
  2365. if (_stricmp((PCSTR)DestFileName.c_str(), (PCSTR)fl.WindowsDirectory.c_str()) == 0) {
  2366. (VOID)StringCchCopyA((PSTR)TargetFileNameBuffer,
  2367. ARRAY_SIZE(TargetFileNameBuffer),
  2368. (PCSTR)fl.Args.DestinationDirectory.c_str());
  2369. (VOID)StringCchCatA((PSTR)TargetFileNameBuffer,
  2370. ARRAY_SIZE(TargetFileNameBuffer),
  2371. ((PCSTR)(FileNodeInfo->Target)) +
  2372. fl.WindowsDirectory.length());
  2373. DestFileName = (const T *)TargetFileNameBuffer;
  2374. ProcessEntry = true;
  2375. }
  2376. }
  2377. }
  2378. }
  2379. } else {
  2380. PFILEPATHS_W FileNodeInfo = (PFILEPATHS_W)Param1;
  2381. if (FileNodeInfo) {
  2382. SrcFileName = std::basic_string<T>((const T*)FileNodeInfo->Source);
  2383. DestFileName = std::basic_string<T>((const T*)FileNodeInfo->Target);
  2384. _wcslwr((PWSTR)SrcFileName.c_str());
  2385. _wcslwr((PWSTR)DestFileName.c_str());
  2386. basic_string<T>::size_type SlashPos = SrcFileName.rfind((T)L'\\');
  2387. if (SlashPos != SrcFileName.npos) {
  2388. SrcFileKey = SrcFileName.substr(SlashPos + 1);
  2389. SlashPos = DestFileName.rfind((T)L'\\');
  2390. if (SlashPos != DestFileName.npos) {
  2391. DestFileKey = DestFileName.substr(SlashPos + 1);
  2392. DestFileName[fl.WindowsDirectory.length()] = 0;
  2393. if (_wcsicmp((PCWSTR)DestFileName.c_str(), (PCWSTR)fl.WindowsDirectory.c_str()) == 0) {
  2394. (VOID)StringCchCopyW((PWSTR)TargetFileNameBuffer,
  2395. ARRAY_SIZE(TargetFileNameBuffer),
  2396. (PCWSTR)fl.Args.DestinationDirectory.c_str());
  2397. (VOID)StringCchCatW((PWSTR)TargetFileNameBuffer,
  2398. ARRAY_SIZE(TargetFileNameBuffer),
  2399. ((PCWSTR)(FileNodeInfo->Target)) +
  2400. fl.WindowsDirectory.length());
  2401. DestFileName = (const T *)TargetFileNameBuffer;
  2402. ProcessEntry = true;
  2403. }
  2404. }
  2405. }
  2406. }
  2407. }
  2408. if (ProcessEntry) {
  2409. bool SkipFileEntry = false;
  2410. if (fl.CurrentSection && fl.Args.IA64Image) {
  2411. SectionValues<T> *Values = NULL;
  2412. try {
  2413. Values = &(fl.CurrentSection->GetValue(SrcFileKey));
  2414. }
  2415. catch(...) {
  2416. }
  2417. if (Values) {
  2418. SkipFileEntry = IsWow64File(*Values, fl);
  2419. }
  2420. if (!SkipFileEntry) {
  2421. if (sizeof(T) == sizeof(CHAR)) {
  2422. SkipFileEntry = ( 0 == _stricmp((PCSTR)SrcFileKey.c_str() + 1, (PCSTR)DestFileKey.c_str())) &&
  2423. (((T)SrcFileKey[0] == (T)'w') || ((T)SrcFileKey[0] == (T)'W'));
  2424. } else {
  2425. SkipFileEntry = ( 0 == _wcsicmp((PCWSTR)SrcFileKey.c_str() + 1, (PCWSTR)DestFileKey.c_str())) &&
  2426. (((T)SrcFileKey[0] == (T)L'w') || ((T)SrcFileKey[0] == (T)L'W'));
  2427. }
  2428. }
  2429. }
  2430. if (!SkipFileEntry) {
  2431. if (fl.Args.IA64Image) {
  2432. basic_string<T>::size_type PlatDirPos = SrcFileName.find(X86_PLATFORM_DIR.c_str());
  2433. if (PlatDirPos != SrcFileName.npos) {
  2434. basic_string<T> NewSrcFileName = SrcFileName.substr(0, PlatDirPos);
  2435. NewSrcFileName += IA64_PLATFORM_DIR;
  2436. NewSrcFileName += SrcFileName.substr(PlatDirPos + X86_PLATFORM_DIR.length());
  2437. // std::cout << "Remapping " << SrcFileName << "->" << NewSrcFileName << std::endl;
  2438. SrcFileName = NewSrcFileName;
  2439. }
  2440. }
  2441. fl.NlsFileMap[SrcFileName] = DestFileName;
  2442. fl.AddDirectoryToNlsDirMap(DestFileName);
  2443. } else {
  2444. // std::cout << "Skipping " << SrcFileName << " WOW64 file" << std::endl;
  2445. }
  2446. }
  2447. }
  2448. return Result;
  2449. }