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.

485 lines
14 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. For Internal use only!
  4. Module Name:
  5. INFSCAN
  6. parseinfctx.cpp
  7. Abstract:
  8. Information about an individual INF (either primary INF
  9. being parsed by InfScan or a secondary included INF)
  10. WARNING! WARNING!
  11. All of this implementation relies on intimate knowledge of
  12. SetupAPI/TextMode Setup/GuiMode Setup parsing of INF files.
  13. It is re-implemented here for speed due to having to process
  14. 700+ INF's in a single go at the cost of having to maintain
  15. this.
  16. DO NOT (I repeat) DO NOT re-implement the code here without
  17. consultation with SetupAPI owner.
  18. History:
  19. Created July 2001 - JamieHun
  20. --*/
  21. #include "precomp.h"
  22. #pragma hdrstop
  23. int ParseInfContext::LoadSourceDisksFiles()
  24. /*++
  25. Routine Description:
  26. Determine all source media information (as of right now, we don't need
  27. target disk information)
  28. Build a per-file list of possible media/platform information
  29. MAINTAINANCE: Keep in step with SourceDisksFiles syntax and decorations
  30. Arguments:
  31. NONE
  32. Return Value:
  33. 0 on success
  34. --*/
  35. {
  36. static StringProdPair decorations[] = {
  37. //
  38. // listed from most specific to most generic
  39. //
  40. { TEXT("SourceDisksFiles.x86"), PLATFORM_MASK_NTX86 },
  41. { TEXT("SourceDisksFiles.ia64"), PLATFORM_MASK_NTIA64 },
  42. { TEXT("SourceDisksFiles.amd64"), PLATFORM_MASK_NTAMD64 },
  43. { TEXT("SourceDisksFiles"), PLATFORM_MASK_ALL_ARCHITECTS },
  44. { NULL, 0 }
  45. };
  46. INFCONTEXT context;
  47. int i;
  48. DWORD platforms = pGlobalScan->Version.PlatformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN);
  49. int res;
  50. for(i=0;decorations[i].String;i++) {
  51. DWORD plat = platforms & decorations[i].ProductMask;
  52. if(plat) {
  53. res = LoadSourceDisksFilesSection(plat,decorations[i].String);
  54. if(res != 0) {
  55. return res;
  56. }
  57. }
  58. }
  59. return 0;
  60. }
  61. int ParseInfContext::LoadSourceDisksFilesSection(DWORD platform,const SafeString & section)
  62. /*++
  63. Routine Description:
  64. Helper function for LoadSourceDisksFiles
  65. loading information for a specific (decorated) section
  66. Arguments:
  67. platform - specific platform or platforms that section is valid for
  68. section - section to load
  69. Return Value:
  70. 0 on success
  71. --*/
  72. {
  73. //
  74. // see if specified section exists
  75. // load section into TargetList of same name
  76. //
  77. INFCONTEXT context;
  78. if(!SetupFindFirstLine(InfHandle,section.c_str(),NULL,&context)) {
  79. return 0;
  80. }
  81. do {
  82. SafeString filename;
  83. SafeString name;
  84. if(!MyGetStringField(&context,0,filename) || filename.empty()) {
  85. pInfScan->Fail(MSG_BAD_FILENAME_ENTRY,section);
  86. continue;
  87. }
  88. SourceDisksFilesEntry entry;
  89. entry.Used = FALSE;
  90. entry.Platform = platform;
  91. if(!SetupGetIntField(&context,1,&entry.DiskId)) {
  92. pInfScan->Fail(MSG_BAD_FILENAME_DISK,section,filename);
  93. continue;
  94. }
  95. if(MyGetStringField(&context,2,name) && name.length()) {
  96. entry.SubDir = name;
  97. }
  98. if(!SetupGetIntField(&context,8,&entry.TargetDirectory)) {
  99. entry.TargetDirectory = 0;
  100. }
  101. if(!SetupGetIntField(&context,9,&entry.UpgradeDisposition)) {
  102. entry.UpgradeDisposition = 3;
  103. } else if((entry.UpgradeDisposition == 0) && MyGetStringField(&context,9,name) && name.empty()) {
  104. //
  105. // actually empty field
  106. //
  107. entry.UpgradeDisposition = 3;
  108. }
  109. if(!SetupGetIntField(&context,10,&entry.TextModeDisposition)) {
  110. entry.TextModeDisposition = 3;
  111. } else if((entry.TextModeDisposition == 0) && MyGetStringField(&context,10,name) && name.empty()) {
  112. //
  113. // actually empty field
  114. //
  115. entry.TextModeDisposition = 3;
  116. }
  117. if(MyGetStringField(&context,11,name) && name.length()) {
  118. entry.TargetName = name;
  119. }
  120. if((entry.UpgradeDisposition != 3) || (entry.TextModeDisposition != 3)) {
  121. if(entry.TargetDirectory) {
  122. LooksLikeLayoutInf = TRUE;
  123. } else {
  124. pInfScan->Fail(MSG_TEXTMODE_DISPOSITION_MISSING_DIR,section,filename);
  125. }
  126. }
  127. //
  128. // is this a completely new entry for this file?
  129. //
  130. StringToSourceDisksFilesList::iterator sdfl = SourceDisksFiles.find(filename);
  131. if(sdfl == SourceDisksFiles.end()) {
  132. //
  133. // never come across this name before (typical case)
  134. //
  135. SourceDisksFilesList blankList;
  136. sdfl = SourceDisksFiles.insert(sdfl,StringToSourceDisksFilesList::value_type(filename,blankList));
  137. SourceDisksFilesList & list = sdfl->second;
  138. list.push_back(entry);
  139. } else {
  140. //
  141. // there's already an entry for this filename
  142. // see if this is an alternate location/info
  143. //
  144. SourceDisksFilesList & list = sdfl->second;
  145. SourceDisksFilesList::iterator i;
  146. BOOL conflict = FALSE;
  147. BOOL duplicate = FALSE;
  148. for(i = list.begin(); i != list.end(); i++) {
  149. //
  150. // existing entries
  151. //
  152. SourceDisksFilesEntry & e = *i;
  153. //
  154. // test numerics first then strings
  155. //
  156. if(entry.DiskId == e.DiskId &&
  157. entry.TargetDirectory == e.TargetDirectory &&
  158. entry.TextModeDisposition == e.TextModeDisposition &&
  159. entry.UpgradeDisposition == e.UpgradeDisposition &&
  160. entry.SubDir == e.SubDir &&
  161. entry.TargetName == e.TargetName) {
  162. //
  163. // already listed
  164. //
  165. duplicate = TRUE;
  166. break;
  167. }
  168. //
  169. // the existing entry might be more specific than what we have
  170. // eg, specific ia64, generic everything else
  171. // so remove the flags from existing entry from mask
  172. //
  173. entry.Platform &= ~ e.Platform;
  174. if(pInfScan->Pedantic()) {
  175. conflict = TRUE;
  176. }
  177. }
  178. if (duplicate) {
  179. //
  180. // duplicate/compatible entry listed
  181. //
  182. i->Platform |= entry.Platform;
  183. } else {
  184. //
  185. // no duplicate or compatible
  186. //
  187. if (conflict) {
  188. //
  189. // different source listings for different platforms
  190. // might be an error
  191. //
  192. pInfScan->Fail(MSG_SOURCE_CONFLICT,section,filename);
  193. }
  194. list.push_back(entry);
  195. }
  196. }
  197. } while (SetupFindNextLine(&context,&context));
  198. return 0;
  199. }
  200. int ParseInfContext::QuerySourceFile(DWORD platforms,const SafeString & section,const SafeString & source,SourceDisksFilesList & Target)
  201. /*++
  202. Routine Description:
  203. See also InstallScan::QuerySourceFile
  204. Determine list of possible source entries for given source file
  205. This can be zero (bad layout)
  206. 1 (typical)
  207. >1 (multiple targets)
  208. WARNING! This shadows SetupAPI implementation always subject to change
  209. MAINTAINANCE: keep in step with SetupAPI
  210. Arguments:
  211. platforms - bitmap list of platforms we're interested in
  212. section - name of the copy section or install section (for error reporting only)
  213. source - name of source file
  214. Target - returned list of source media information
  215. Return Value:
  216. 0 on success
  217. --*/
  218. {
  219. //
  220. // return list of entries matching source file
  221. //
  222. StringToSourceDisksFilesList::iterator sdfl = SourceDisksFiles.find(source);
  223. if(sdfl == SourceDisksFiles.end()) {
  224. //
  225. // not found
  226. // don't fail here, caller will try a few more alternatives
  227. //
  228. return 0;
  229. }
  230. SourceDisksFilesList & list = sdfl->second;
  231. SourceDisksFilesList::iterator i;
  232. for(i = list.begin(); i != list.end(); i++) {
  233. //
  234. // existing entries
  235. //
  236. SourceDisksFilesEntry & e = *i;
  237. if ((e.Platform & platforms) == 0) {
  238. continue;
  239. }
  240. Target.push_back(e);
  241. }
  242. if(!Target.size()) {
  243. pInfScan->Fail(MSG_SOURCE_NOT_LISTED_PLATFORM,section,source);
  244. //
  245. // indicate we errored out
  246. //
  247. return -1;
  248. }
  249. return 0;
  250. }
  251. int ParseInfContext::LoadWinntDirectories(IntToString & Target)
  252. /*++
  253. Routine Description:
  254. Load the Layout.INF specific [WinntDirectories]
  255. to aid in textmode vs setupapi consistency
  256. WARNING! This relies heavily on current textmode implementation subject to change
  257. MAINTAINANCE: Keep in step with textmode
  258. Arguments:
  259. Target - initialized with <id> to <subdirectory> mapping
  260. Return Value:
  261. 0 on success
  262. --*/
  263. {
  264. if(pGlobalScan->IgnoreErrors && !pGlobalScan->TargetsToo) {
  265. //
  266. // don't bother if we're not interested in errors
  267. // (unless we want target information)
  268. //
  269. return 0;
  270. }
  271. INFCONTEXT context;
  272. if(!SetupFindFirstLine(InfHandle,TEXT("WinntDirectories"),NULL,&context)) {
  273. return 0;
  274. }
  275. do {
  276. int index;
  277. TCHAR path[MAX_PATH];
  278. if(SetupGetIntField(&context,0,&index) && index) {
  279. if(!SetupGetStringField(&context,1,path,MAX_PATH,NULL) || !path[0]) {
  280. continue;
  281. }
  282. _tcslwr(path);
  283. IntToString::iterator i = Target.find(index);
  284. if(i == Target.end()) {
  285. Target[index] = path;
  286. } else {
  287. if(i->second.compare(path)!=0) {
  288. //
  289. // mismatch
  290. //
  291. pInfScan->Fail(MSG_WINNT_DIRECTORY_CONFLICT,i->second,path);
  292. }
  293. }
  294. }
  295. } while (SetupFindNextLine(&context,&context));
  296. return 0;
  297. }
  298. int ParseInfContext::LoadDestinationDirs()
  299. /*++
  300. Routine Description:
  301. Load the [DestinationDirs]
  302. Also uses pGlobalScan->GlobalDirectories to remap certain ID's
  303. WARNING! This relies heavily on current SetupAPI and textmode implementations subject to change
  304. MAINTAINANCE: Keep in step with textmode vs SetupAPI directory ID's
  305. Arguments:
  306. NONE
  307. Return Value:
  308. 0 on success
  309. --*/
  310. {
  311. if(pGlobalScan->IgnoreErrors && !pGlobalScan->TargetsToo) {
  312. //
  313. // don't bother if we're not interested in errors
  314. // (unless we want target information)
  315. //
  316. return 0;
  317. }
  318. INFCONTEXT context;
  319. if(!SetupFindFirstLine(InfHandle,TEXT("DestinationDirs"),NULL,&context)) {
  320. return 0;
  321. }
  322. //
  323. //
  324. // MAINTAINANCE:
  325. // this table needs to correlate to LAYOUT.INX
  326. //
  327. // process [DestinationDirs] if there is one
  328. // <section> = dirid,subdir
  329. //
  330. // normalize following dirid's:
  331. // 10,subdir - as is
  332. // 11,subdir - 10,system32\subdir
  333. // 12,subdir - 10,system32\drivers\subdir
  334. // 17,subdir - 10,inf\subdir
  335. // 18,subdir -
  336. TCHAR section[LINE_LEN];
  337. int dirid = 0;
  338. TCHAR subdir[MAX_PATH];
  339. int global_equiv[] = {
  340. 0,0,0,0,0,0,0,0,0,0,0, // 0-10
  341. 2, // 11 - system32
  342. 4, // 12 - system32/drivers
  343. 0,0,0,0, // 13-16
  344. 20, // 17 - inf
  345. 21, // 18 - help
  346. 0, // 19
  347. 22, // 20 - fonts
  348. 0
  349. };
  350. do {
  351. int index;
  352. TCHAR path[MAX_PATH];
  353. if(!SetupGetStringField(&context,0,section,LINE_LEN,NULL) || !section[0]) {
  354. continue;
  355. }
  356. _tcslwr(section);
  357. if(!SetupGetIntField(&context,1,&dirid) || dirid == 0) {
  358. pInfScan->Fail(MSG_DIRID_NOT_SPECIFIED,section);
  359. dirid = 0;
  360. }
  361. if(!SetupGetStringField(&context,2,subdir,MAX_PATH,NULL)) {
  362. subdir[0] = TEXT('\0');
  363. }
  364. _tcslwr(subdir);
  365. TargetDirectoryEntry entry;
  366. entry.Used = false;
  367. entry.DirId = dirid;
  368. entry.SubDir = subdir;
  369. //
  370. // certain dirid have a global equiv, remap
  371. //
  372. if(dirid>0 && dirid < ASIZE(global_equiv)) {
  373. int equiv = global_equiv[dirid];
  374. if(equiv) {
  375. IntToString::iterator i = pGlobalScan->GlobalDirectories.find(equiv);
  376. if(i != pGlobalScan->GlobalDirectories.end()) {
  377. //
  378. // we have a mapping relative to dirID 10.
  379. //
  380. entry.DirId = 10;
  381. entry.SubDir = PathConcat(i->second,subdir);
  382. }
  383. }
  384. }
  385. //
  386. // make a note
  387. //
  388. DestinationDirectories[section] = entry;
  389. } while (SetupFindNextLine(&context,&context));
  390. //
  391. // now determine default
  392. //
  393. CopySectionToTargetDirectoryEntry::iterator tde = DestinationDirectories.find(TEXT("defaultdestdir"));
  394. if(tde != DestinationDirectories.end()) {
  395. DefaultTargetDirectory = tde;
  396. }
  397. return 0;
  398. }
  399. void ParseInfContext::PartialCleanup()
  400. /*++
  401. Routine Description:
  402. Cleanup information not required by results phase
  403. In particular, INF handle must ALWAYS be closed
  404. Arguments:
  405. NONE
  406. Return Value:
  407. NONE
  408. --*/
  409. {
  410. if(InfHandle != INVALID_HANDLE_VALUE) {
  411. SetupCloseInfFile(InfHandle);
  412. InfHandle = INVALID_HANDLE_VALUE;
  413. }
  414. SourceDisksFiles.clear();
  415. CompletedCopySections.clear();
  416. }