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.

506 lines
12 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. For Internal use only!
  4. Module Name:
  5. INFSCAN
  6. globals.cpp
  7. Abstract:
  8. Global functions (ie, not part of any class)
  9. History:
  10. Created July 2001 - JamieHun
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <initguid.h>
  15. #include <new.h>
  16. int
  17. __cdecl
  18. my_new_handler(size_t)
  19. {
  20. throw std::bad_alloc();
  21. return 0;
  22. }
  23. int
  24. __cdecl
  25. main(int argc,char *argv[])
  26. /*++
  27. Routine Description:
  28. Main point of entry
  29. Defer to GlobalScan::ParseArgs and GlobalScan::Scan
  30. Arguments:
  31. argc - # of arguments passed on command line
  32. argv - arguments passed on command line
  33. Return Value:
  34. 0 on success
  35. 1 no files
  36. 2 bad usage
  37. 3 fatal error (out of memory)
  38. stdout -- scan errors
  39. stderr -- trace/fatal errors
  40. --*/
  41. {
  42. int res;
  43. _PNH _old_new_handler = _set_new_handler(my_new_handler);
  44. int _old_new_mode = _set_new_mode(1);
  45. try {
  46. GlobalScan scanner;
  47. res = scanner.ParseArgs(argc,argv);
  48. if(res != 0) {
  49. return res;
  50. }
  51. res = scanner.Scan();
  52. } catch(bad_alloc &) {
  53. res = 3;
  54. }
  55. if(res == 3) {
  56. fprintf(stderr,"Out of memory!\n");
  57. }
  58. _set_new_mode(_old_new_mode);
  59. _set_new_handler(_old_new_handler);
  60. return res;
  61. }
  62. void FormatToStream(FILE * stream,DWORD fmt,DWORD flags,...)
  63. /*++
  64. Routine Description:
  65. Format text to stream using a particular msg-id fmt
  66. Used for displaying localizable messages
  67. Arguments:
  68. stream - file stream to output to, stdout or stderr
  69. fmt - message id
  70. ... - parameters %1...
  71. Return Value:
  72. none
  73. --*/
  74. {
  75. va_list arglist;
  76. LPTSTR locbuffer = NULL;
  77. DWORD count;
  78. va_start(arglist, flags);
  79. count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ALLOCATE_BUFFER|flags,
  80. NULL,
  81. fmt,
  82. 0, // LANGID
  83. (LPTSTR) &locbuffer,
  84. 0, // minimum size of buffer
  85. (flags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
  86. ? reinterpret_cast<va_list*>(va_arg(arglist,DWORD_PTR*))
  87. : &arglist);
  88. if(locbuffer) {
  89. if(count) {
  90. int c;
  91. int back = 0;
  92. while(((c = *CharPrev(locbuffer,locbuffer+count)) == TEXT('\r')) ||
  93. (c == TEXT('\n'))) {
  94. count--;
  95. back++;
  96. }
  97. if(back) {
  98. locbuffer[count++] = TEXT('\n');
  99. locbuffer[count] = TEXT('\0');
  100. }
  101. _fputts(locbuffer,stream);
  102. }
  103. LocalFree(locbuffer);
  104. }
  105. }
  106. PTSTR CopyString(PCTSTR arg, int extra)
  107. /*++
  108. Routine Description:
  109. Copy a string into a newly allocated buffer
  110. Arguments:
  111. arg - string to copy
  112. extra - extra characters to allow for
  113. Return Value:
  114. TCHAR[] buffer, delete with "delete []"
  115. --*/
  116. {
  117. int max = _tcslen(arg)+1;
  118. PTSTR chr = new TCHAR[max+extra]; // may throw bad_alloc
  119. memcpy(chr,arg,max*sizeof(TCHAR));
  120. return chr;
  121. }
  122. #ifdef UNICODE
  123. PTSTR CopyString(PCSTR arg, int extra)
  124. /*++
  125. Routine Description:
  126. Copy a string into a newly allocated buffer
  127. Converting from ANSI to UNICODE
  128. Arguments:
  129. arg - string to copy
  130. extra - extra characters to allow for
  131. Return Value:
  132. TCHAR[] buffer, delete with "delete []"
  133. --*/
  134. {
  135. int max = strlen(arg)+1;
  136. PTSTR chr = new TCHAR[max+extra]; // may throw bad_alloc
  137. if(!MultiByteToWideChar(CP_ACP,0,arg,max,chr,max)) {
  138. delete [] chr;
  139. return NULL;
  140. }
  141. return chr;
  142. }
  143. #else
  144. PTSTR CopyString(PCWSTR arg, int extra)
  145. /*++
  146. Routine Description:
  147. Copy a string into a newly allocated buffer
  148. Converting from UNICODE to ANSI
  149. Arguments:
  150. arg - string to copy
  151. extra - extra characters to allow for
  152. Return Value:
  153. TCHAR[] buffer, delete with "delete []"
  154. --*/
  155. {
  156. #error CopyString(PCWSTR arg,int extra)
  157. }
  158. #endif
  159. int GetFullPathName(const SafeString & given,SafeString & target)
  160. /*++
  161. Routine Description:
  162. Obtain full pathname
  163. Arguments:
  164. given - path to convert
  165. target - full pathname on success, same as given on error
  166. Return Value:
  167. 0 on success, !=0 on failure
  168. --*/
  169. {
  170. DWORD len = GetFullPathName(given.c_str(),0,NULL,NULL);
  171. if(len == 0) {
  172. if(&target != &given) {
  173. target = given;
  174. }
  175. return -1;
  176. }
  177. PTSTR chr = new TCHAR[len];
  178. if(!chr) {
  179. if(&target != &given) {
  180. target = given;
  181. }
  182. return -1;
  183. }
  184. DWORD alen = GetFullPathName(given.c_str(),len,chr,NULL);
  185. if((alen == 0) || (alen>len)) {
  186. if(&target != &given) {
  187. target = given;
  188. }
  189. delete [] chr;
  190. return -1;
  191. }
  192. target = chr;
  193. delete [] chr;
  194. return 0;
  195. }
  196. SafeString PathConcat(const SafeString & path,const SafeString & tail)
  197. /*++
  198. Routine Description:
  199. Combine path and tail, returning newly combined string
  200. inserts/removes path seperator if needed
  201. Arguments:
  202. path - first part
  203. tail - last part
  204. Return Value:
  205. appended path
  206. --*/
  207. {
  208. if(!path.length()) {
  209. return tail;
  210. }
  211. if(!tail.length()) {
  212. return path;
  213. }
  214. PCTSTR path_p = path.c_str();
  215. int path_l = path.length();
  216. int c = *CharPrev(path_p,path_p+path_l);
  217. bool addslash = false;
  218. bool takeslash = false;
  219. if((c != TEXT('\\')) && (c != TEXT('/'))) {
  220. addslash = true;
  221. }
  222. c = tail[0];
  223. if((c == TEXT('\\')) || (c == TEXT('/'))) {
  224. if(addslash) {
  225. return path+tail;
  226. } else {
  227. return path+tail.substr(1);
  228. }
  229. } else {
  230. if(addslash) {
  231. return path+SafeString(TEXT("\\"))+tail;
  232. } else {
  233. return path+tail;
  234. }
  235. }
  236. }
  237. VOID
  238. Usage(VOID)
  239. /*++
  240. Routine Description:
  241. Help information
  242. Arguments:
  243. Return Value:
  244. --*/
  245. {
  246. _tprintf(TEXT("Usage: INFSCAN [/B <textfile>] [/C <output>] [/D] [/E <output>] [/F <filter>] [/G] [/I] {/N <infname>} {/O <dir>} [/P] [Q <output>] [/R] [/S <output>] [/T <count>] [/V <version>] [/W <textfile>] [/X <textfile>] [/Y] [/Z] [SourcePath]\n\n"));
  247. _tprintf(TEXT("Options:\n\n"));
  248. _tprintf(TEXT("/B <textfile> (build special) Filter /E based on a list of \"unchanged\" files\n"));
  249. _tprintf(TEXT(" variation /B1 - based on copied files only\n"));
  250. _tprintf(TEXT(" variation /B2 - based on INF files only\n"));
  251. _tprintf(TEXT("/C <output> Create INF filter/report based on errors\n"));
  252. _tprintf(TEXT("/D Determine non-driver installation sections\n"));
  253. _tprintf(TEXT("/E <output> Create a DeviceToInf filter INF\n"));
  254. _tprintf(TEXT("/F <filter> Filter based on INF: FilterInfPath\n"));
  255. _tprintf(TEXT("/G Generate Pnfs first (see also /Z)\n"));
  256. _tprintf(TEXT("/I Ignore errors (for when generating file list)\n"));
  257. _tprintf(TEXT("/N <infname> Specify single INF name (/N may be used multiple times)\n"));
  258. _tprintf(TEXT("/O <dir> Specify an override directory (/O may be used multiple times and parsed in order)\n"));
  259. _tprintf(TEXT("/P Pedantic mode (show potential problems too)\n"));
  260. _tprintf(TEXT("/Q <output> Source+Target copied files list (filtered by layout.inf) see also /S\n"));
  261. _tprintf(TEXT("/R Trace (list all INF's)\n"));
  262. _tprintf(TEXT("/S <output> Source copied files list (filtered by layout.inf) see also /Q\n"));
  263. _tprintf(TEXT("/T <count> Specify number of threads to use\n"));
  264. _tprintf(TEXT("/V <version> Version (eg NTx86.5.1)\n"));
  265. _tprintf(TEXT("/W <textfile> List of files to include (alternative to /N)\n"));
  266. _tprintf(TEXT("/X <textfile> List of files to exclude (same format as /W) overrides later includes\n"));
  267. _tprintf(TEXT("/Y Don't check per-inf [SourceDisksFiles*]\n"));
  268. _tprintf(TEXT("/Z Generate Pnfs and quit (see also /G)\n"));
  269. _tprintf(TEXT("/? or /H Display brief usage message\n"));
  270. }
  271. bool MyGetStringField(PINFCONTEXT Context,DWORD FieldIndex,SafeString & result,bool downcase)
  272. /*++
  273. Routine Description:
  274. Get a string field from an INF
  275. downcase it if flag indicates it needs to be (typical case)
  276. Arguments:
  277. Context - from SetupFindFirstLine/SetupFindNextLine etc
  278. FieldIndex - 0 for key, 1-n for parameter
  279. result - string obtained
  280. downcase - true (typical) to return result as lower-case
  281. Return Value:
  282. TRUE if success (result modified), FALSE otherwise (result left untouched)
  283. --*/
  284. {
  285. TCHAR Buf[MAX_INF_STRING_LENGTH];
  286. if(SetupGetStringField(Context,FieldIndex,Buf,MAX_INF_STRING_LENGTH,NULL)) {
  287. if(downcase) {
  288. _tcslwr(Buf);
  289. }
  290. result = Buf;
  291. return true;
  292. } else {
  293. //
  294. // leave result as is, allowing default capability
  295. //
  296. return false;
  297. }
  298. }
  299. SafeString QuoteIt(const SafeString & val)
  300. /*++
  301. Routine Description:
  302. Quote a string in such a way that it will be correctly parsed by SetupAPI
  303. Arguments:
  304. val - unquoted string
  305. Return Value:
  306. quoted string
  307. --*/
  308. {
  309. if(val.empty()) {
  310. //
  311. // don't quote empty string
  312. //
  313. return val;
  314. }
  315. basic_ostringstream<TCHAR> result;
  316. result << TEXT("\"");
  317. LPCTSTR p = val.c_str();
  318. LPCTSTR q;
  319. while((q = wcsstr(p,TEXT("%\""))) != NULL) {
  320. TCHAR c = *q;
  321. q++; // include the special char
  322. result << SafeString(p,q-p) << c; // write what we have so far, double up the special char
  323. p = q;
  324. }
  325. result << p << TEXT("\"");
  326. return result.str();
  327. }
  328. int GeneratePnf(const SafeString & pnf)
  329. /*++
  330. Routine Description:
  331. Generate a single PNF
  332. Arguments:
  333. none
  334. Return Value:
  335. 0 on success
  336. --*/
  337. {
  338. HINF hInf;
  339. hInf = SetupOpenInfFile(pnf.c_str(),
  340. NULL,
  341. INF_STYLE_WIN4 | INF_STYLE_CACHE_ENABLE,
  342. NULL
  343. );
  344. if(hInf != INVALID_HANDLE_VALUE) {
  345. SetupCloseInfFile(hInf);
  346. }
  347. return 0;
  348. }
  349. void Write(HANDLE hFile,const SafeStringW & str)
  350. /*++
  351. Routine Description:
  352. Write a string to specified file, converting UNICODE to ANSI
  353. Arguments:
  354. NONE
  355. Return Value:
  356. 0 on success
  357. --*/
  358. {
  359. int len = WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),NULL,0,NULL,NULL);
  360. if(!len) {
  361. return;
  362. }
  363. LPSTR buf = new CHAR[len];
  364. if(!buf) {
  365. return;
  366. }
  367. int nlen = WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),buf,len,NULL,NULL);
  368. if(!nlen) {
  369. delete [] buf;
  370. return;
  371. }
  372. DWORD written;
  373. BOOL f = WriteFile(hFile,buf,len,&written,NULL);
  374. delete [] buf;
  375. }
  376. void Write(HANDLE hFile,const SafeStringA & str)
  377. /*++
  378. Routine Description:
  379. Write a string to specified file as-is
  380. Arguments:
  381. NONE
  382. Return Value:
  383. 0 on success
  384. --*/
  385. {
  386. DWORD written;
  387. BOOL f = WriteFile(hFile,str.c_str(),str.length(),&written,NULL);
  388. }