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.

652 lines
21 KiB

  1. #include "symutil.h"
  2. typedef struct _FILE_INFO {
  3. DWORD TimeDateStamp;
  4. DWORD CheckSum;
  5. TCHAR szName[MAX_PATH];
  6. } FILE_INFO, *PFILE_INFO;
  7. typedef struct _COMMAND_ARGS {
  8. LPTSTR szDir; // Directory where source files exist
  9. LPTSTR szFileName; // File name(s) to copy
  10. FILE * hSymCDLog; // SymbolsCD log file
  11. BOOL Recurse; // Recurse in subdirectories
  12. LPTSTR szSymPath; // Directory where symbols exist
  13. LPTSTR szExcludeFileName; // File name with list of files to exclude
  14. // from symbol checking
  15. LPTSTR szListFileName; // File containing a list of files to check
  16. DWORD Split; // TRUE - check for split images
  17. // FALSE - check for non-split images
  18. BOOL Verbose; // Print info for every file checked,
  19. // not just the ones that fail
  20. LPTSTR szErrorFilterList; // Don't print errors for these files
  21. LPTSTR szCDIncludeList; // Full path to symbols that should get
  22. // written to the list that is used for creating
  23. // the symbol CD. Originally used for
  24. // international incremental builds
  25. } COM_ARGS, *PCOM_ARGS;
  26. typedef struct _FILE_COUNTS {
  27. DWORD NumPassedFiles;
  28. DWORD NumIgnoredFiles;
  29. DWORD NumFailedFiles;
  30. } FILE_COUNTS, *PFILE_COUNTS;
  31. // Prototypes
  32. PCOM_ARGS
  33. GetCommandLineArgs(
  34. int argc,
  35. char **argv
  36. );
  37. VOID
  38. Usage (
  39. VOID
  40. );
  41. DWORD
  42. CheckDirectory(
  43. LPTSTR szDir,
  44. LPTSTR szFName,
  45. LPTSTR szSymPath,
  46. FILE* hSymCDLog,
  47. PEXCLUDE_LIST pExcludeList,
  48. PFILE_COUNTS pFileCounts,
  49. DWORD Split
  50. );
  51. DWORD
  52. CheckAllDirectories(
  53. LPTSTR szDir,
  54. LPTSTR szFName,
  55. LPTSTR szSymPath,
  56. FILE* hSymCDLog,
  57. PEXCLUDE_LIST pExcludeList,
  58. PFILE_COUNTS pFileCounts,
  59. DWORD Split
  60. );
  61. BOOL
  62. CorrectPath(
  63. LPTSTR szFileName,
  64. LPTSTR szPathName,
  65. LPTSTR szCorrectPath
  66. );
  67. // Global variables
  68. BOOL Verbose = 0;
  69. BOOL Retail = TRUE;
  70. int
  71. _cdecl
  72. main( int argc, char **argv)
  73. {
  74. PCOM_ARGS pArgs;
  75. DWORD NumBadFiles=0;
  76. DWORD NumExcludeFiles=0;
  77. DWORD i;
  78. PEXCLUDE_LIST pExcludeList = NULL;
  79. FILE_COUNTS FileCounts;
  80. SYM_ERR SymErr;
  81. TCHAR ErrMsg[MAX_SYM_ERR];
  82. HFILE hListFile;
  83. P_LIST FileList;
  84. pArgs = GetCommandLineArgs(argc, argv);
  85. Verbose = (BOOL)pArgs->Verbose;
  86. memset( &SymErr, 0, sizeof(SymErr) );
  87. memset( &FileCounts, 0, sizeof(FILE_COUNTS) );
  88. if ( pArgs->szExcludeFileName != NULL ) {
  89. pExcludeList = GetExcludeList(pArgs->szExcludeFileName);
  90. }
  91. if ( pArgs->szErrorFilterList != NULL ) {
  92. pErrorFilterList = GetExcludeList(pArgs->szErrorFilterList);
  93. }
  94. if ( pArgs->szCDIncludeList != NULL ) {
  95. pCDIncludeList = GetList( pArgs->szCDIncludeList );
  96. }
  97. // This is the section for creating the symbols CD.
  98. if ( pArgs->szListFileName != NULL ) {
  99. FileList = GetList(pArgs->szListFileName);
  100. if ( FileList == NULL ) {
  101. printf(" Cannot open the file list %s\n", pArgs->szListFileName);
  102. exit(1);
  103. }
  104. if ( FileList->dNumFiles == 0 ) goto finish;
  105. // Do the first one, so we don't have to check for it inside the loop
  106. if ( CorrectPath(FileList->List[0].FName, FileList->List[0].Path, pArgs->szDir) ) {
  107. NumBadFiles += CheckDirectory(
  108. pArgs->szDir,
  109. FileList->List[0].FName,
  110. pArgs->szSymPath,
  111. pArgs->hSymCDLog,
  112. pExcludeList,
  113. &FileCounts,
  114. pArgs->Split
  115. );
  116. }
  117. for ( i=1; i< FileList->dNumFiles; i++) {
  118. // There may be some duplicates in the list ... skip them
  119. // Also, only check the files that are in the path given on the command line
  120. if ( (_tcsicmp(FileList->List[i].Path, FileList->List[i-1].Path) != 0) &&
  121. CorrectPath(FileList->List[i].FName, FileList->List[i].Path, pArgs->szDir) ) {
  122. NumBadFiles += CheckDirectory(
  123. pArgs->szDir,
  124. FileList->List[i].FName,
  125. pArgs->szSymPath,
  126. pArgs->hSymCDLog,
  127. pExcludeList,
  128. &FileCounts,
  129. pArgs->Split
  130. );
  131. }
  132. }
  133. }
  134. else {
  135. if ( !pArgs->Recurse ) {
  136. NumBadFiles += CheckDirectory(
  137. pArgs->szDir,
  138. pArgs->szFileName,
  139. pArgs->szSymPath,
  140. pArgs->hSymCDLog,
  141. pExcludeList,
  142. &FileCounts,
  143. pArgs->Split
  144. );
  145. } else {
  146. NumBadFiles += CheckAllDirectories(
  147. pArgs->szDir,
  148. pArgs->szFileName,
  149. pArgs->szSymPath,
  150. pArgs->hSymCDLog,
  151. pExcludeList,
  152. &FileCounts,
  153. pArgs->Split
  154. );
  155. }
  156. // CheckDirectory just returns the number of failed and passed. If
  157. // no files failed or passed, then report that we couldn't find the
  158. // file.
  159. if ( (FileCounts.NumFailedFiles + FileCounts.NumPassedFiles) == 0 ) {
  160. _tcscpy( SymErr.szFileName, pArgs->szFileName );
  161. SymErr.Verbose=pArgs->Verbose;
  162. if (InExcludeList(SymErr.szFileName, pExcludeList) ) {
  163. LogError(ErrMsg, &SymErr, IMAGE_PASSED );
  164. FileCounts.NumPassedFiles=1;
  165. } else {
  166. LogError(ErrMsg, &SymErr, FILE_NOT_FOUND);
  167. FileCounts.NumFailedFiles=1;
  168. }
  169. if ( _tcscmp(ErrMsg, "") != 0 ) {
  170. printf("SYMCHK: %s",ErrMsg);
  171. }
  172. }
  173. }
  174. finish:
  175. if (pArgs->hSymCDLog) fclose(pArgs->hSymCDLog);
  176. free(pArgs->szDir);
  177. free(pArgs->szFileName);
  178. free(pArgs);
  179. printf("\nSYMCHK: FAILED files = %d\n",FileCounts.NumFailedFiles);
  180. printf("SYMCHK: PASSED + IGNORED files = %d\n",FileCounts.NumPassedFiles);
  181. if ( FileCounts.NumFailedFiles > 0 ) {
  182. return(1);
  183. } else {
  184. return(0);
  185. }
  186. }
  187. DWORD
  188. CheckAllDirectories(
  189. LPTSTR szDir,
  190. LPTSTR szFName,
  191. LPTSTR szSymPath,
  192. FILE* hSymCDLog,
  193. PEXCLUDE_LIST pExcludeList,
  194. PFILE_COUNTS pFileCounts,
  195. DWORD Split
  196. )
  197. {
  198. HANDLE hFindFile;
  199. TCHAR szCurPath[_MAX_PATH];
  200. BOOL Found = FALSE;
  201. DWORD NumBadFiles=0;
  202. WIN32_FIND_DATA FindFileData;
  203. LPTSTR szF = NULL;
  204. LPTSTR szE = NULL;
  205. FILE_COUNTS FileCounts;
  206. NumBadFiles += CheckDirectory(szDir,
  207. szFName,
  208. szSymPath,
  209. hSymCDLog,
  210. pExcludeList,
  211. pFileCounts,
  212. Split
  213. );
  214. // Look for all the subdirectories
  215. _tcscpy(szCurPath, szDir);
  216. _tcscat(szCurPath, _T("\\*.*") );
  217. Found = TRUE;
  218. hFindFile = FindFirstFile((LPCTSTR)szCurPath, &FindFileData);
  219. if ( hFindFile == INVALID_HANDLE_VALUE) {
  220. Found = FALSE;
  221. }
  222. while ( Found ) {
  223. if ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  224. if ( !_tcscmp(FindFileData.cFileName, _T(".")) ||
  225. !_tcscmp(FindFileData.cFileName, _T("..")) ||
  226. !_tcsicmp(FindFileData.cFileName, _T("symbols")) ) {
  227. // Don't process these directories
  228. } else {
  229. // Get the current path that we are searching in
  230. _tcscpy(szCurPath, szDir);
  231. _tcscat(szCurPath, _T("\\"));
  232. _tcscat(szCurPath, FindFileData.cFileName);
  233. NumBadFiles += CheckAllDirectories(
  234. szCurPath,
  235. szFName,
  236. szSymPath,
  237. hSymCDLog,
  238. pExcludeList,
  239. pFileCounts,
  240. Split
  241. );
  242. }
  243. }
  244. Found = FindNextFile(hFindFile, &FindFileData);
  245. }
  246. FindClose(hFindFile);
  247. return(NumBadFiles);
  248. }
  249. DWORD
  250. CheckDirectory(
  251. LPTSTR szDir,
  252. LPTSTR szFName,
  253. LPTSTR szSymPath,
  254. FILE * hSymCDLog,
  255. PEXCLUDE_LIST pExcludeList,
  256. PFILE_COUNTS pFileCounts,
  257. DWORD Split
  258. )
  259. {
  260. HANDLE hFindFile;
  261. TCHAR szFileName[_MAX_PATH];
  262. TCHAR szCurPath[_MAX_PATH];
  263. TCHAR szCurFileName[_MAX_PATH];
  264. BOOL Found;
  265. DWORD NumBadFiles=0;
  266. DWORD NumGoodFiles=0;
  267. WIN32_FIND_DATA FindFileData;
  268. SYM_ERR SymErr;
  269. TCHAR ErrMsg[MAX_SYM_ERR];
  270. memset( &SymErr, 0, sizeof(SymErr) );
  271. // Create the file name
  272. _tcscpy(szFileName, szDir);
  273. _tcscat(szFileName, _T("\\") );
  274. _tcscat(szFileName, szFName);
  275. // Get the current path that we are searching in
  276. _tcscpy(szCurPath, szDir);
  277. Found = TRUE;
  278. hFindFile = FindFirstFile((LPCTSTR)szFileName, &FindFileData);
  279. if ( hFindFile == INVALID_HANDLE_VALUE ) {
  280. Found = FALSE;
  281. }
  282. while ( Found ) {
  283. // Found a file, not a directory
  284. if ( !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
  285. _tcscpy(szCurFileName, szCurPath);
  286. _tcscat(szCurFileName,_T("\\") );
  287. _tcscat(szCurFileName, FindFileData.cFileName );
  288. // Its not in the exclude list, go ahead and test it
  289. if (!InExcludeList(FindFileData.cFileName,pExcludeList ) ) {
  290. if ( !CheckSymbols( ErrMsg,
  291. szSymPath,
  292. szCurFileName,
  293. hSymCDLog,
  294. Split,
  295. Verbose,
  296. NULL ) ) {
  297. pFileCounts->NumFailedFiles++;
  298. NumBadFiles++;
  299. } else {
  300. pFileCounts->NumPassedFiles++;
  301. }
  302. }
  303. // It is in the exclude list, add it to NumPassed Files
  304. else {
  305. pFileCounts->NumPassedFiles++;
  306. _tcscpy(SymErr.szFileName, szCurFileName);
  307. SymErr.Verbose = Verbose;
  308. LogError(ErrMsg, &SymErr, IMAGE_PASSED);
  309. }
  310. if ( _tcscmp(ErrMsg,"") != 0 ) {
  311. printf("SYMCHK: %s", ErrMsg);
  312. }
  313. }
  314. Found = FindNextFile(hFindFile, &FindFileData);
  315. }
  316. FindClose(hFindFile);
  317. return(NumBadFiles);
  318. }
  319. VOID
  320. Usage (
  321. VOID
  322. )
  323. {
  324. puts("\n"
  325. "Usage: symchk [switches] file /s sympath \n\n"
  326. " file Name of file(s) or directory to check.\n"
  327. " Can include wildcards.\n\n"
  328. " [/b] For NT4 Service Packs -- don't complain if\n"
  329. " there is no CodeView data\n"
  330. " [/e file] File containing a list of files to exclude.\n"
  331. " This file can have one name per line. Comment\n"
  332. " lines begin with a ; . \n\n"
  333. " [/p] Check that private information is removed.\n"
  334. " [/c dest] Create an inf for the symbols CD\n\n"
  335. " [/r] Recurse into subdirectories. This uses the\n"
  336. " Windows 2000 build model and assumes that the\n"
  337. " first subdirectory to traverse into is the retail\n"
  338. " directory. Example sympath: \"E:\\binaries\\symbols\" .\n"
  339. " All subdirectories except \"symbols\" will be checked.\n\n"
  340. " /s sympath symbol path delimited by ; . Checks sympath\n"
  341. " and sympath\\ext for each string in the path, \n"
  342. " where ext is the extension of the executable.\n\n"
  343. " [/t] Fail if a DBG file is involved. Fails if the image points\n"
  344. " to a dbg file or if it contains data that can be stripped\n"
  345. " into a dbg file. Default is to fail if data can be stripped\n"
  346. " into a dbg file, but don't fail if the image points to a\n"
  347. " dbg file.\n\n"
  348. " [/u] Fail if image points to a dbg file. Don't fail if image\n"
  349. " contains data that can be split into a dbg file.\n\n"
  350. " [/v] Give verbose information\n"
  351. " [/x] Used with /c. Perform symbol checking on these files and\n"
  352. " add the correct symbols to the symbol CD's inf, but\n"
  353. " don't write error messages for the ones that are wrong.\n\n"
  354. );
  355. exit(1);
  356. // The purpose of /x is to not log errors for symbols in symbad.txt. However, symchk
  357. // should check all of the files in symbad.txt when it is creating the list of file
  358. // in case some of them actually have correct symbols and symbad hasn't been updated yet.
  359. }
  360. PCOM_ARGS
  361. GetCommandLineArgs(
  362. int argc,
  363. char **argv
  364. )
  365. {
  366. PCOM_ARGS pArgs;
  367. int i,cur,length;
  368. TCHAR c;
  369. BOOL NeedSecond = FALSE;
  370. BOOL Exclude = FALSE;
  371. LPTSTR szFileArg = NULL;
  372. TCHAR szDrive[_MAX_DRIVE + 1];
  373. TCHAR szDir[_MAX_DIR + 1];
  374. TCHAR szFileName[_MAX_FNAME + 1];
  375. TCHAR szExt[_MAX_EXT + 1];
  376. TCHAR szNameExt[_MAX_FNAME + _MAX_EXT + 1];
  377. LPTSTR szSymCDLog = NULL;
  378. LPTSTR szSymbolsCDFile = NULL;
  379. HANDLE fHandle;
  380. WIN32_FIND_DATA FindFileData;
  381. if (argc == 1) Usage();
  382. if (!(pArgs = (PCOM_ARGS)malloc(sizeof(COM_ARGS))))
  383. {
  384. printf("No memory");
  385. exit(1);
  386. }
  387. memset( pArgs, 0, sizeof(COM_ARGS) );
  388. pArgs->Split = 0;
  389. pArgs->szListFileName = NULL;
  390. pArgs->szCDIncludeList = NULL;
  391. CheckPrivate = FALSE;
  392. for (i=1; i<argc; i++) {
  393. if (!NeedSecond) {
  394. if ( (argv[i][0] == '/') || (argv[i][0] == '-') ) {
  395. length = _tcslen(argv[i]) -1;
  396. for (cur=1; cur <= length; cur++) {
  397. c = argv[i][cur];
  398. switch (c) {
  399. case 'c': NeedSecond = TRUE;
  400. break;
  401. case 'b': CheckCodeView=FALSE;
  402. NeedSecond = FALSE;
  403. break;
  404. case 'e': Exclude = TRUE;
  405. NeedSecond = TRUE;
  406. if ( length > cur) Usage();
  407. break;
  408. case 'l': NeedSecond = TRUE;
  409. break;
  410. case 'p': NeedSecond = FALSE;
  411. CheckPrivate = TRUE;
  412. break;
  413. case 'r': pArgs->Recurse = TRUE;
  414. Recurse = TRUE;
  415. break;
  416. case 's': NeedSecond = TRUE;
  417. if ( length > cur) Usage();
  418. break;
  419. case 't':
  420. pArgs->Split |= ERROR_IF_NOT_SPLIT;
  421. pArgs->Split |= ERROR_IF_SPLIT;
  422. break;
  423. case 'u': pArgs->Split |= ERROR_IF_SPLIT;
  424. break;
  425. case 'v': pArgs->Verbose = TRUE;
  426. break;
  427. case 'x': NeedSecond = TRUE;
  428. break;
  429. case 'y': NeedSecond = TRUE;
  430. break;
  431. default: Usage();
  432. }
  433. }
  434. } else {
  435. if (szFileArg != NULL) Usage();
  436. szFileArg = argv[i];
  437. }
  438. } else {
  439. NeedSecond = FALSE;
  440. switch (c) {
  441. case 'c': szSymbolsCDFile = argv[i];
  442. break;
  443. case 'e': pArgs->szExcludeFileName = argv[i];
  444. break;
  445. case 'l': pArgs->szListFileName = argv[i];
  446. break;
  447. case 's': pArgs->szSymPath = argv[i];
  448. break;
  449. case 'x': pArgs->szErrorFilterList = argv[i];
  450. break;
  451. case 'y': pArgs->szCDIncludeList = argv[i];
  452. break;
  453. default: Usage();
  454. }
  455. }
  456. }
  457. if ( pArgs->Split == 0 ) {
  458. // This has always been the default behavior
  459. pArgs->Split = ERROR_IF_NOT_SPLIT;
  460. }
  461. if ( szFileArg == NULL ) Usage();
  462. // make the Symbol Copy log for the Support Tools CD
  463. if ( szSymbolsCDFile != NULL ) {
  464. if ( (pArgs->hSymCDLog = fopen(szSymbolsCDFile, "a+")) == NULL ) {
  465. printf("Cannot open %s for appending\n",szSymbolsCDFile);
  466. exit(1);
  467. }
  468. }
  469. // Get the filenames so they are correct
  470. _tsplitpath( szFileArg, szDrive, szDir, szFileName, szExt );
  471. // Get current directory if they didn't enter a directory
  472. if ( !_tcscmp(szDrive, "") && !_tcscmp(szDir,"") ) {
  473. GetCurrentDirectory(_MAX_DIR, szDir);
  474. }
  475. // If szFileName and szExt are "" then put *.* in them
  476. if ( !_tcscmp(szFileName,"") && !_tcscmp(szExt,"") ) {
  477. _tcscpy(szFileName,"*");
  478. }
  479. // User may have entered a directory with an implies * for the
  480. // file name.
  481. fHandle = FindFirstFile( szFileArg, &FindFileData );
  482. _tcscpy(szNameExt, szFileName);
  483. _tcscat(szNameExt, szExt);
  484. // If its a directory and the name of the directory matches
  485. // the filename.ext from the command line parameter, then the user
  486. // entered a directory, so add * to the end.
  487. if ( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  488. (_tcscmp( szNameExt, FindFileData.cFileName )== 0) ) {
  489. // Move the filename to be the dir
  490. _tcscat( szDir, "\\");
  491. _tcscat( szDir, szFileName);
  492. // Put the file name as *
  493. _tcscpy(szFileName, "*");
  494. }
  495. pArgs->szDir=(LPTSTR) malloc( sizeof(TCHAR)* _MAX_PATH + 1 );
  496. _tmakepath( pArgs->szDir, szDrive, szDir, NULL, NULL);
  497. pArgs->szFileName = (LPTSTR) malloc( sizeof(TCHAR) * _MAX_PATH + 1 );
  498. _tmakepath(pArgs->szFileName, NULL, NULL, szFileName, szExt);
  499. // Check that everything has been entered
  500. if (NeedSecond ||
  501. (pArgs->szFileName == NULL) ||
  502. (pArgs->szDir == NULL) ||
  503. (pArgs->szSymPath == NULL) )
  504. {
  505. Usage();
  506. }
  507. return (pArgs);
  508. }
  509. BOOL
  510. CorrectPath(
  511. LPTSTR szFileName,
  512. LPTSTR szPathName,
  513. LPTSTR szCorrectPath
  514. )
  515. {
  516. // To return TRUE, szPathName should equal szCorrectPath + \ + szFileName
  517. // The only hitch is that there could be extraneous \'s
  518. TCHAR CorrectPathx[_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1];
  519. TCHAR PathNamex[_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1];
  520. LONG length, index, i;
  521. // Get rid of any extra \'s
  522. length = _tcslen(szPathName);
  523. PathNamex[0] = szPathName[0];
  524. index = 1;
  525. for (i=1; i<=length; i++) {
  526. if ( (szPathName[i-1] != '\\') || (szPathName[i] != '\\') ) {
  527. PathNamex[index] = szPathName[i];
  528. index++;
  529. }
  530. }
  531. length = _tcslen(szCorrectPath);
  532. CorrectPathx[0] = szCorrectPath[0];
  533. index = 1;
  534. for (i=1; i<=length; i++) {
  535. if ( (szCorrectPath[i-1] != '\\') || (szCorrectPath[i] != '\\') ) {
  536. CorrectPathx[index] = szCorrectPath[i];
  537. index++;
  538. }
  539. }
  540. // Make sure that the correct path doesn't end in a '\'
  541. length = _tcslen(CorrectPathx);
  542. if ( CorrectPathx[length-1] == '\\' ) CorrectPathx[length-1] = '\0';
  543. _tcscat(CorrectPathx,"\\");
  544. _tcscat(CorrectPathx,szFileName);
  545. if ( _tcsicmp(CorrectPathx, szPathName) == 0) return TRUE;
  546. else return FALSE;
  547. }