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.

552 lines
18 KiB

  1. /**************************************************************************************\
  2. * Chksum.c
  3. * Purpose: Print to stdout checksum of all files in current directory, and optionally
  4. * recurse from current directory.
  5. *
  6. * Created 02-15-95. DonBr
  7. *
  8. \**************************************************************************************/
  9. #include <windows.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <search.h>
  13. #include <errno.h>
  14. #include <string.h>
  15. #include <io.h>
  16. #include <imagehlp.h>
  17. #include <direct.h>
  18. #include <ctype.h>
  19. // type definitions
  20. #define exename "chksum"
  21. #define MAX_EXCLUDE (30)
  22. #define LISTSIZE 12000 // max allowable number of files and dirs in a flat directory
  23. typedef struct List {
  24. char Name[MAX_PATH]; // file or directory name
  25. unsigned long Attributes;
  26. unsigned long Size;
  27. } List, *pList;
  28. // Function prototypes
  29. VOID CheckRel();
  30. VOID CheckSum(List *rgpList, TCHAR *x); //, TCHAR *szDirectory);
  31. int __cdecl CompFileAndDir( const void *elem1 , const void *elem2);
  32. int __cdecl CompName( const void *elem1 , const void *elem2);
  33. int MyGetFullPathName( IN const CHAR *InPath, IN OUT CHAR *FullPath);
  34. VOID CreateOutputPath(char *CurrentDir, char *NewDir);
  35. VOID ParseArgs(int *pargc, char **argv);
  36. VOID Usage();
  37. // Variable declarations
  38. BOOL fRecurse = FALSE;
  39. BOOL fPathOverride = FALSE;
  40. BOOL fFileOut = FALSE;
  41. BOOL fExclude = FALSE;
  42. BOOL fFileIn = FALSE;
  43. int DirNum = 1,DirNameSize = 0, ProcessedFiles=0, endchar=0, ExclCounter=0;
  44. int grc=0; // global return code
  45. char szRootDir[MAX_PATH];
  46. char szRootDir2[MAX_PATH];
  47. char *szFileOut;
  48. char szFileOutFullPath[MAX_PATH];
  49. char *szExclude[MAX_EXCLUDE];
  50. char *szFileIn;
  51. CHAR szDirectory[MAX_PATH] = {"."}; // default to current directory
  52. FILE* fout;
  53. FILE* fin;
  54. // Begin main program
  55. VOID __cdecl
  56. main(
  57. INT argc,
  58. LPSTR argv[]
  59. )
  60. {
  61. TCHAR CWD[MAX_PATH];
  62. HANDLE logfh;
  63. ParseArgs(&argc, argv);
  64. // Create File if fFileOut==TRUE
  65. if (fFileOut) {
  66. fout = fopen(szFileOut, "w");
  67. if (fout == NULL) {
  68. fprintf(stderr, "Output file %s could not be created.\n", szFileOut);
  69. exit(1);
  70. }
  71. }
  72. /*
  73. // Open File if fFileIn==TRUE
  74. if (fFileIn) {
  75. fin = fopen(szFileIn, "r"); // open check file
  76. if (fin == NULL) {
  77. fprintf(stderr, "Check file %s could not be opened.\n", szFileIn);
  78. exit(1);
  79. }
  80. }
  81. */
  82. // set root path
  83. if (fPathOverride) {
  84. // attempt to change directories
  85. if (_chdir(szRootDir) == -1){
  86. fprintf(stderr, "Path not found: %s\n", szRootDir);
  87. Usage();
  88. }
  89. }else{
  90. GetCurrentDirectory(MAX_PATH, szRootDir);
  91. }
  92. fprintf(fout==NULL? stdout : fout , "Processing %s\n", szRootDir);
  93. CheckRel(); // primary worker routine
  94. fprintf(stdout, "%d files processed in %d directories\n", ProcessedFiles, DirNum);
  95. if (fFileOut) {
  96. fclose(fout);
  97. }
  98. exit(grc);
  99. }
  100. /**************************************************************************************\
  101. * Checkrel
  102. * Purpose: Create an array of List structures containing file data for the current
  103. * directory, sort the array alphabetically placing Files first and
  104. * directories last, and finally process the array contents. Another instance
  105. * of checkrel is started for directories, and checksum is called for files.
  106. \**************************************************************************************/
  107. VOID CheckRel()
  108. {
  109. HANDLE fh;
  110. TCHAR CurrentDir[MAX_PATH] = {"\0"};
  111. TCHAR NewDir[MAX_PATH] = {"\0"};
  112. WIN32_FIND_DATA *pfdata;
  113. BOOL fFilesInDir=FALSE;
  114. BOOL fDirsFound=FALSE;
  115. int iArrayMember=0, cNumDir=0, i=0, Length=0;
  116. pList *rgpList = NULL; // a pointer to an array of pointers to List structures
  117. CHAR cFileNameFullPath[MAX_PATH];
  118. pfdata = (WIN32_FIND_DATA*)malloc(sizeof(WIN32_FIND_DATA));
  119. if (!pfdata) {
  120. fprintf(stderr, "Not enough memory.\n");
  121. grc++;
  122. return;
  123. }
  124. // Find the first file
  125. fh = FindFirstFile("*.*", pfdata);
  126. if (fh == INVALID_HANDLE_VALUE) {
  127. fprintf(fout==NULL? stdout : fout , "\t No files found\n");
  128. free(pfdata);
  129. grc++;
  130. return;
  131. }
  132. // Allocate an array of pointers to List structures
  133. rgpList = (pList *) malloc(LISTSIZE * sizeof(pList));
  134. if (!rgpList) {
  135. fprintf(stderr, "Not enough memory allocating rgpList[].\n");
  136. free(pfdata);
  137. FindClose(fh); // close the file handle
  138. grc++;
  139. return;
  140. }
  141. //
  142. // DoWhile loop to find all files and directories in current directory
  143. // and copy pertinent data to individual List structures.
  144. //
  145. do { // while (FindNextFile(fh, pfdata))
  146. if (strcmp(pfdata->cFileName, ".") && strcmp(pfdata->cFileName, "..")) { // skip . and ..
  147. //
  148. // If excluding files and current file matches any excluded file
  149. // (case insensitively), then don't process current file
  150. //
  151. if (fExclude) {
  152. for (i=0; i < ExclCounter; i++) {
  153. if (!_strcmpi(pfdata->cFileName, szExclude[i])) {
  154. goto excludefound;
  155. }
  156. }
  157. }
  158. //
  159. // If current file matches output file name, then don't process current file
  160. //
  161. if ((fFileOut) && (!strcmp(szFileOut, pfdata->cFileName)) ) {
  162. // File names match. If full paths match, ignore the output file.
  163. MyGetFullPathName(pfdata->cFileName, cFileNameFullPath);
  164. if ( !_strcmpi( szFileOutFullPath, cFileNameFullPath) ) {
  165. goto excludefound;
  166. }
  167. }
  168. rgpList[iArrayMember] = (pList)malloc(sizeof(List)); // allocate the memory
  169. if (!rgpList[iArrayMember]) {
  170. fputs("Not enough memory.\n", stderr);
  171. free(pfdata);
  172. FindClose(fh); // close the file handle
  173. for (i=0; i<iArrayMember; i++) free(rgpList[i]);
  174. free(rgpList);
  175. grc++;
  176. return;
  177. }
  178. strcpy(rgpList[iArrayMember]->Name, pfdata->cFileName);
  179. _strlwr(rgpList[iArrayMember]->Name); // all lowercase for strcmp in CompName
  180. memcpy(&(rgpList[iArrayMember]->Attributes), &pfdata->dwFileAttributes, 4);
  181. memcpy(&(rgpList[iArrayMember]->Size), &pfdata->nFileSizeLow, 4);
  182. if (!(rgpList[iArrayMember]->Attributes & FILE_ATTRIBUTE_DIRECTORY)) { //If file
  183. fFilesInDir=TRUE;
  184. } else {
  185. if (rgpList[iArrayMember]->Attributes & FILE_ATTRIBUTE_DIRECTORY) { //If directory
  186. fDirsFound=TRUE;
  187. }
  188. if (fRecurse) { // if recursive increment directory counter
  189. cNumDir++;
  190. }
  191. }
  192. iArrayMember++;
  193. if (iArrayMember >= LISTSIZE) {
  194. GetCurrentDirectory(MAX_PATH, CurrentDir);
  195. fprintf(stderr, "More than %d files in %s. \nRebuild chksum.exe or eliminate some files from the root of this directory.\n", LISTSIZE, CurrentDir);
  196. free(pfdata);
  197. FindClose(fh); // close the file handle
  198. for (i=0; i<iArrayMember; i++) free(rgpList[i]);
  199. free(rgpList);
  200. grc++;
  201. return;
  202. }
  203. excludefound: ;
  204. }
  205. } while (FindNextFile(fh, pfdata));
  206. if (pfdata) free(pfdata);
  207. if (fh) FindClose(fh); // close the file handle
  208. //
  209. // if no directories or files found with exception of . and ..
  210. //
  211. if ( (iArrayMember==0) || (!fFilesInDir) ){
  212. GetCurrentDirectory(MAX_PATH, CurrentDir);
  213. CreateOutputPath(CurrentDir, NewDir);
  214. // fprintf(fout==NULL? stdout : fout , "%s - No files\n", NewDir);
  215. }
  216. // Sort Array arranging FILE entries at top
  217. qsort( (void *)rgpList, iArrayMember, sizeof(List *), CompFileAndDir);
  218. // Sort Array alphabetizing only FILE names
  219. qsort( (void *)rgpList, iArrayMember-cNumDir, sizeof(List *), CompName);
  220. // Sort Array alphabetizing only DIRectory names
  221. qsort( (void *)&rgpList[iArrayMember-cNumDir], cNumDir, sizeof(List *), CompName);
  222. //
  223. // Process newly sorted structures.
  224. // Checksum files or start another instance of checkrel() for directories
  225. //
  226. for (i=0; i < iArrayMember; ++i) {
  227. if (rgpList[i]->Attributes & FILE_ATTRIBUTE_DIRECTORY) { // if Dir
  228. if (fRecurse) { // if recursive
  229. if (_chdir(rgpList[i]->Name) == -1){ // cd into subdir and check for error
  230. fprintf(stderr, "Unable to change directory: %s (error %d)\n", rgpList[i]->Name, GetLastError());
  231. grc++;
  232. } else {
  233. DirNum++; // directory counter
  234. CheckRel(); // start another iteration of checkrel function in new directory
  235. _chdir(".."); // get back to previous directory when above iteration returns
  236. } // end if _chdir
  237. } // end if recurse
  238. } else { // else if not Directory
  239. GetCurrentDirectory(MAX_PATH, CurrentDir);
  240. CreateOutputPath(CurrentDir, NewDir);
  241. CheckSum(rgpList[i], NewDir);
  242. }
  243. } // end for i < iArrayMember
  244. // Clean up the array and it's elements
  245. for (i=0; i<iArrayMember; i++) free(rgpList[i]);
  246. free(rgpList);
  247. } // end CheckRel
  248. /*************************************************************************************\
  249. * CheckSum
  250. * Purpose: uses MapFileAndCheckSum to determine file checksum and outputs data.
  251. \*************************************************************************************/
  252. VOID CheckSum(List *rgpList, TCHAR *x) {//TCHAR *szDirectory) {
  253. ULONG HeaderSum, CheckSum=0, status;
  254. if (rgpList->Size != 0) { //High != 0 || rgpList->nFileSizeLow != 0) {
  255. status = MapFileAndCheckSum(rgpList->Name, &HeaderSum, &CheckSum);
  256. if (status != CHECKSUM_SUCCESS) {
  257. fprintf(fout==NULL? stdout : fout , "\nCannot open or map file: %s (error %d)\n", rgpList->Name, GetLastError());
  258. grc++;
  259. return;
  260. }
  261. }
  262. fprintf(fout==NULL? stdout : fout , "%s\\%s %lx\n", x, rgpList->Name, CheckSum);//szDirectory, rgpList->Name, CheckSum);
  263. ProcessedFiles++;
  264. } //CheckSum
  265. /********************************************************************************************\
  266. * CompFileAndDir
  267. * Purpose: a comparision routine passed to QSort. It compares elem1 and elem2
  268. * based upon their attribute, i.e., is it a file or directory.
  269. \********************************************************************************************/
  270. int __cdecl
  271. CompFileAndDir( const void *elem1 , const void *elem2 )
  272. {
  273. pList p1, p2;
  274. // qsort passes a void universal pointer, use a typecast (List**)
  275. // so the compiler recognizes the data as a List structure.
  276. // Typecast pointer-to-pointer-to-List and dereference ONCE
  277. // leaving a pList. I don't dereference the remaining pointer
  278. // in the p1 and p2 definitions to avoid copying the structure.
  279. p1 = (*(List**)elem1);
  280. p2 = (*(List**)elem2);
  281. if ( (p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && (p2->Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  282. return 0;
  283. } //both dirs
  284. if (!(p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && !(p2->Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  285. return 0;
  286. } //both files
  287. if ( (p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && !(p2->Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  288. return 1;
  289. } // elem1 is dir and elem2 is file
  290. if (!(p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && (p2->Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  291. return -1;
  292. } // elem1 is file and elem2 is dir
  293. return 0; // if none of above
  294. }
  295. /********************************************************************************************\
  296. * CompName is another compare routine passed to QSort that compares the two Name strings *
  297. \********************************************************************************************/
  298. int __cdecl
  299. CompName( const void *elem1 , const void *elem2 )
  300. {
  301. return strcmp( (*(List**)elem1)->Name, (*(List**)elem2)->Name );
  302. }
  303. /**********************************************************************************************\
  304. * CreateOutputPath just formats NewDir, the path prepended to filename during checksum output *
  305. \**********************************************************************************************/
  306. VOID CreateOutputPath(char *CurrentDir, char *NewDir)
  307. {
  308. strcpy(NewDir, ".");
  309. // if rootdir ends in '\' and currentdir and szrootdir2 don't match
  310. // handles case where /p path override arg ends in a '\' char like "/p g:\"
  311. // files listed at the root don't need the extra '\' placed in NewDir, but
  312. // directories at the root DO need ".\" prepended to their name
  313. _strlwr(CurrentDir);
  314. //fprintf(stdout, "szrootdir: %s, szrootdir2: %s, currentdir: %s\n", szRootDir, szRootDir2, CurrentDir);
  315. if ( (szRootDir[strlen(szRootDir)-1] == '\\') && // if arg path ends in "\"
  316. (strcmp(CurrentDir, szRootDir2)) && // if they don't match
  317. (CurrentDir[strlen(CurrentDir)-1] != '\\') //&& // if currentdir doesn't end with "\"
  318. //(szRootDir2[strlen(szRootDir2)-1] != ':') ){ // if arg path ends with ":"
  319. ){
  320. strcat(NewDir, "\\");
  321. }
  322. if ( (CurrentDir[strlen(CurrentDir)-2] !=':') && (CurrentDir[strlen(CurrentDir)-1] !='\\') ){
  323. strcat(NewDir, &CurrentDir[(strlen(szRootDir))] );
  324. }
  325. }
  326. VOID
  327. ParseArgs(int *pargc, char **argv) {
  328. CHAR cswitch, c, *p;
  329. int argnum = 1;
  330. while ( argnum < *pargc ) {
  331. _strlwr(argv[argnum]);
  332. cswitch = *argv[argnum];
  333. if (cswitch == '/' || cswitch == '-') {
  334. c = *(argv[argnum]+1);
  335. switch (c) {
  336. case '?':
  337. Usage();
  338. case 'r':
  339. fRecurse = TRUE;
  340. break;
  341. case 'p':
  342. if ( ((argnum+1) < *pargc) && (*(argv[argnum]+2) == '\0') && (*(argv[argnum+1]) != '\0') ) {
  343. ++argnum; // increment to next arg string
  344. strcpy(szRootDir, argv[argnum]);
  345. if (szRootDir == NULL) {
  346. fprintf(stderr, "out of memory for root dir.\n");
  347. exit(1);
  348. }
  349. fPathOverride = TRUE;
  350. // Find the full path to the root
  351. if ( !MyGetFullPathName(argv[argnum], szRootDir) ) {
  352. fprintf(stderr, "Cannot get full path for root dir %s\n", szRootDir);
  353. exit(1);
  354. }
  355. _strlwr(szRootDir);
  356. strcpy(szRootDir2, szRootDir);
  357. // if path given ends in a "\", remove it...
  358. if (szRootDir2[strlen(szRootDir2)-1] == 92) szRootDir2[strlen(szRootDir2)-1] = '\0';
  359. break;
  360. } else {
  361. Usage();
  362. }
  363. case 'o':
  364. if ( ((argnum+1) < *pargc) && (*(argv[argnum]+2) == '\0') && (*(argv[argnum+1]) != '\0') ) {
  365. ++argnum;
  366. szFileOut = _strdup(argv[argnum]);
  367. if (szFileOut == NULL) {
  368. fprintf(stderr, "Out of memory for output file.\n");
  369. exit(1);
  370. }
  371. fFileOut = TRUE;
  372. // Find the full path to the output file
  373. if ( !MyGetFullPathName(szFileOut, szFileOutFullPath) ) {
  374. fprintf(stderr, "Cannot get full path for output file %s\n", szFileOut);
  375. exit(1);
  376. }
  377. _strlwr(szFileOutFullPath); // lower case full path to output file
  378. _strlwr(szFileOut); // lower case path to output file
  379. break;
  380. } else {
  381. Usage();
  382. }
  383. case 'x': // check number of args given
  384. if ( ((argnum+1) < *pargc) && (*(argv[argnum]+2) == '\0') && (*(argv[argnum+1]) != '\0') ) {
  385. ++argnum;
  386. szExclude[ExclCounter] = _strdup(argv[argnum]);
  387. if (szExclude[ExclCounter] == NULL) {
  388. fprintf(stderr, "Out of memory for exclude name.\n");
  389. exit(1);
  390. }
  391. fExclude = TRUE;
  392. _strlwr(szExclude[ExclCounter]);
  393. ExclCounter++;
  394. break;
  395. } else {
  396. Usage();
  397. }
  398. /*
  399. case 'i':
  400. if ( (*(argv[argnum]+2) == '\0') && (*(argv[argnum+1]) != '\0') ) {
  401. ++argnum;
  402. szFileIn = strdup(argv[argnum]);
  403. if (szFileIn == NULL) {
  404. fprintf(stderr, "Out of memory for input file.\n");
  405. exit(1);
  406. }
  407. fFileIn = TRUE;
  408. break;
  409. } else {
  410. Usage();
  411. }
  412. */
  413. default:
  414. fprintf(stderr, "\nInvalid argument: %s\n", argv[argnum]);
  415. Usage();
  416. } //switch
  417. } else {
  418. Usage();
  419. } // if
  420. ++argnum;
  421. } // while
  422. } // parseargs
  423. LPSTR pszUsage =
  424. "Generates a listing of each file processed and its check sum.\n\n"
  425. "Usage: %s [/?] display this message\n"
  426. " [/r] recursive file check\n"
  427. " [/p pathname] root path override\n"
  428. " [/o filename] output file name\n"
  429. " [/x name] exclude file or directory\n\n"
  430. "Notes: If no /p path is given, the current directory is processed.\n"
  431. " Exclude multiple files or directories with multiple /x arguments\n"
  432. " e.g. - /x file1 /x file2\n\n"
  433. "Example: %s /r /p c:\\winnt351 /o %s.chk /x symbols /x dump\n"
  434. "";
  435. VOID
  436. Usage()
  437. {
  438. fprintf(stderr, pszUsage, exename, exename, exename);
  439. exit(1);
  440. }
  441. int MyGetFullPathName( IN const CHAR *InPath, IN OUT CHAR *FullPath)
  442. {
  443. int len;
  444. LPSTR FilePart;
  445. len = GetFullPathName(InPath, MAX_PATH, FullPath, &FilePart);
  446. return ( (len>0 && len<MAX_PATH) ? len : 0 );
  447. }