home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / trojanpr / file_crc.arc / COMPARE.C next >
Encoding:
C/C++ Source or Header  |  1988-11-19  |  31.7 KB  |  1,121 lines

  1. /*
  2.    PROGRAM TO COMPARE THE CRC'S OF THE FILE LISTS IN
  3.      CHECK$$$.NEW AND CHECK$$$.CRC                      
  4.  
  5. Written by Ted H. Emigh -- emigh@ncsugn.uucp or NEMIGH@TUCC.BITNET
  6. Modifications by Jim Van Zandt  <jrv@mitre-bedford.arpa>...
  7.     Translated from Pascal to C.
  8.     Explicitly checking for too many directories or too many files.
  9.     Reading time and date of CRC check from old and new files.
  10.     Optionally writing changes to hidden, system, or read-only files to screen.
  11.     Writing deleted files out to FILES$$$.DEL.
  12.     Customizing parameters at run time.
  13.  
  14. */
  15.  
  16. #include    <string.h>
  17. #include    <stdio.h>
  18.  
  19. #define DESMET                    /* DeSmet C compiler */
  20. #define CUSTOMIZABLE            /* enable run time customizing */
  21.  
  22. /* the first three of these #defines should match the ones in FILECRC */
  23. #define COMPARE_PROGRAM_NAME "COMPARE.EXE"
  24. #define CHECK_NEW "CHECK$$$.NEW"
  25. #define CHECK_CRC "CHECK$$$.CRC"
  26.  
  27. #define CHECK_OLD "CHECK$$$.OLD"
  28.  
  29. #define FILES_NEW "FILES$$$.NEW"
  30. #define FILES_DEL "FILES$$$.DEL"
  31. #define FILES_MOD "FILES$$$.MOD"
  32. #define FILES_UPD "FILES$$$.UPD"
  33.  
  34. #define FLAG1 "O4x7890aiudhvo8jh*&"      /* 19 character strings to mark the */
  35. #define FLAG2 "0aijnvpo987G/&^%&_)"      /* parameter block in the .EXE file */
  36.  
  37. #define MAX_FILES 1500
  38. #define MAX_DIRECTORIES 200
  39.  
  40. long lseek();
  41.  
  42. #define     VERSION_NUMBER        "2.10"
  43.  
  44. #define     VERSION_DATE        "19 November 1988"
  45.  
  46.  
  47. #define RR(a) if(debugging) printf a
  48.                             /* evaluates TRUE (nonzero) for equal strings */
  49. #define streq(a, b) (strcmp((a),(b)) == 0)
  50.  
  51. /*                    These are the customizable parameters                    */
  52. typedef struct
  53.     {char flag1[20];
  54.     char compare_program[80];
  55.     char new_crc_file[80];
  56.     char cur_crc_file[80];
  57.     char old_crc_file[80];
  58.     char flag2[20];
  59.     } PARMS;
  60.  
  61. PARMS signature = 
  62.     {FLAG1, 
  63.     COMPARE_PROGRAM_NAME, 
  64.     CHECK_NEW,
  65.     CHECK_CRC,
  66.     CHECK_OLD,
  67.     FLAG2
  68.     };
  69.  
  70.  
  71.  
  72. typedef char (months[12])[4];
  73. months month = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
  74.                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  75.  
  76.  
  77. typedef struct {
  78.     char directory[65];
  79.     int filenum;
  80.     } directory_record;
  81. directory_record directories[MAX_DIRECTORIES];
  82.  
  83. typedef struct {
  84.     char name[13];
  85.     int time_of_day;
  86.     int date;
  87.     long file_size;
  88.     unsigned char attribute;
  89.     int crc;
  90.     char surviving;
  91.     } file_rec;
  92. file_rec fileinfo[MAX_FILES];
  93.  
  94. /**********
  95. show_dir(dirnum) int dirnum;
  96. {    printf("directory %2d starting at file %3d is %s\n",
  97.         dirnum,
  98.         directories[dirnum].filenum,
  99.         directories[dirnum].directory);
  100. }
  101.  
  102. show_fil(filnum) int filnum;
  103. {    char *get_time();
  104.     printf("file %2d  %12s  %s  %02x  %10ld  %04x  %d\n",
  105.         filnum,
  106.         fileinfo[filnum].name,
  107.         get_time(fileinfo[filnum].time_of_day, fileinfo[filnum].date),
  108.         fileinfo[filnum].attribute,
  109.         fileinfo[filnum].file_size,
  110.         fileinfo[filnum].crc,
  111.         fileinfo[filnum].surviving);
  112. }
  113. ***********/
  114.  
  115. int timeofday, filedate; /* file creation time and date read from new file */
  116.  
  117. int directory_number;     /* 
  118.                             directories[directory_number] is the first
  119.                             one with no directory name.  However, after
  120.                             the old entries are all read,
  121.                             directories[directory_number].filenum is
  122.                             set to old_file.
  123.                         */
  124.  
  125.           /*  Number of files in each category  */
  126. int file_number;
  127. int old_file;         /* fileinfo[old_file] is the first one with no entry */
  128. int new_file; 
  129. int del_file; 
  130. int ok_file; 
  131. int update_file; 
  132. int mod_file; 
  133.  
  134. int old_time, old_date, new_time, new_date; /* creation times of CRC files */
  135.  
  136. char *cur_filename; 
  137. char *new_filename; 
  138.  
  139. FILE *infile;                 /* file for reading file lists */
  140. FILE *newfile;                 /* file for writing names of new files created */
  141. FILE *delfile;                 /* file for writing names of deleted files */
  142. FILE *modfile;                 /* file for writing names of modified files */
  143. FILE *updatefile;            /* file for writing names of updated files */
  144. FILE *tempfile;                /* used in renaming files */
  145. int crc_value; 
  146. char filename[13]; 
  147. char name_of_file[256]; 
  148. char crc_string[256]; 
  149. char instring[256]; 
  150. unsigned char attribute; 
  151. long filesize; 
  152. int new; 
  153. int new_dir; 
  154. int number_directories; 
  155. int direct_count; 
  156. int conservative = 0;    /* nonzero if changes to hidden, system, or read-only 
  157.                             files are to be displayed on the screen */
  158. int customizing = 0;    /* nonzero if user wants to change file names */
  159. int debugging = 0;        /* nonzero to enable trace output */
  160. char this_directory[65]; 
  161. char current_directory[65]; 
  162.  
  163.  
  164. /*
  165.   This function returns a string up to the first space from infile
  166. */
  167.  
  168. char *get_string()
  169. {
  170. int inchar; 
  171. static char buf[256]; 
  172. char *s;
  173.  
  174.     /*  Ignore any leading blanks  */
  175.     do {inchar = fgetc(infile);} while (inchar == ' ');
  176.     s = buf;
  177.     buf[0] = 0;
  178.     /*  Now, add on to string until a blank is found  */
  179.     do
  180.         {*s++ = inchar;
  181.         inchar = fgetc(infile);
  182.         }
  183.     while (inchar != ' ' && inchar != -1);
  184.     *s = 0;
  185.  
  186.     return(buf);
  187. }
  188.  
  189.  
  190. /*
  191.     returns zero if nonwhite characters remain in the file
  192. */
  193. eof(fp) FILE *fp;
  194. {    int c;
  195.     while(isspace(c = fgetc(fp))) {}
  196.     if(c == -1) return 1;
  197.     ungetc(c, fp);
  198.     return 0;
  199. }
  200.  
  201.  
  202. /*
  203.   Procedure to read in the old list of files and set up the list of
  204.   directories (variable directories), and the list of files along with
  205.   the various data (variable fileinfo).
  206.   On return, 
  207.   old_file has the number of files in the list and
  208.   number_directories has the number of directories.
  209.  
  210.   The variables directories and fileinfo have the following information:
  211.   directories  directory : Name of the directory (up to 64 characters)
  212.                FileNum   : Number of the name in fileinfo that contains
  213.                            the information for the first file in this
  214.                            directory.
  215.  
  216.   fileinfo     name        : Name of the file
  217.                time_of_day : Time of day in DOS format
  218.                date        : Date in DOS format
  219.                file_size   : File size
  220.                attribute   : Attribute of the file
  221.                crc         : CRC of the file
  222.  
  223. */
  224.  
  225. /* // */
  226. void read_old_file()
  227. {
  228.     fscanf(infile, "%d %d", &old_time, &old_date);
  229.     /*  Set to read Old List of Files  */
  230.     old_file = 0;                /*  Number of files in the list  */
  231.     number_directories = 0;        /*  Number of directories in the list  */
  232.     while (!eof(infile))
  233.         {
  234.         if(old_file == MAX_FILES) 
  235.             {printf("more than %d files in old CRC list - remainder ignored\n", 
  236.                 MAX_FILES);
  237.             break;
  238.             }
  239.         strcpy(this_directory, get_string());    /*  Get the directory name  */
  240.         strcpy(fileinfo[old_file].name, get_string() );
  241.                                                 /*  Get the file name  */
  242.         if (strcmp(this_directory, current_directory))
  243.             {if(number_directories == MAX_DIRECTORIES - 1) 
  244.                 {printf("more than %d directories in old CRC list - \
  245. remainder ignored\n", 
  246.                     MAX_DIRECTORIES);
  247.                 break;
  248.                 }
  249.         
  250.             strcpy(current_directory, this_directory);
  251.             strcpy(directories[number_directories].directory, this_directory);
  252.             directories[number_directories].filenum = old_file;
  253.             number_directories++;
  254.             }
  255.         fscanf(infile, "%d %d %d %ld %x\n", 
  256.             &(fileinfo[old_file].attribute), 
  257.             &(fileinfo[old_file].time_of_day), 
  258.             &(fileinfo[old_file].date), 
  259.             &(fileinfo[old_file].file_size), 
  260.             &(fileinfo[old_file].crc));
  261.         fileinfo[old_file].surviving = 0;
  262.         old_file++;        /*  Another file  */
  263.         }
  264.     directories[number_directories].filenum = old_file;
  265.     RR(("old file has %d directories and %d files\n", number_directories, old_file));
  266. }
  267.  
  268.  
  269. /*
  270.   This function returns the time and date of file creation.
  271.   date1 is the time of day in DOS directory format
  272.   date2 is the date of creation in DOS directory format
  273.  
  274.   get_time is a string with the time and date (e.g., 14:31:42  8 AUG 1986)
  275. */
  276.  
  277. char* get_time(date1, date2)
  278. int date1; 
  279. int date2; 
  280. {
  281. int hour, minute, second; 
  282. int year, n_month, day; 
  283. static char time[65]; 
  284.  
  285.     if (date2 != 0)
  286.         {
  287.         hour = (date1 >> 11);
  288.         minute = ((date1 >> 5)) & 63;
  289.         second = (date1 & 31) * 2;
  290.         year = (date2 >> 9);
  291.         n_month = ((date2 >> 5)) & 15;
  292.         day = date2 & 31;
  293.         sprintf(time, "%2d:%02d:%02d  %2d %s %4d", 
  294.             hour, minute, second, day, month[n_month - 1], year + 1980);
  295.         }
  296.     else 
  297.         strcpy(time, "                     ");
  298. return(time);
  299. }
  300.  
  301.  
  302. /*
  303.   Procedure to write the attribute, size and CRC for a file from
  304.   the old list
  305.  
  306.   file_number is the number of the file name
  307.  
  308. */
  309.  
  310. void write_old_file(file_number)
  311. int file_number; 
  312. {
  313.     printf("  Attribute = %2d, Size = %10ld", 
  314.         fileinfo[file_number].attribute, 
  315.         fileinfo[file_number].file_size); 
  316.     printf(", CRC = %04x\n", fileinfo[file_number].crc);
  317. }
  318.  
  319.  
  320. /*
  321.   Procedure to write the attribute, size and CRC for a file from
  322.   the new list
  323.  
  324. */
  325.  
  326. void write_new_file()
  327. {
  328.     fprintf(stdout , "  Attribute = %2d, Size = %10ld", attribute, filesize); 
  329.     fprintf(stdout , ", CRC = %04x\n", crc_value); 
  330. }
  331.  
  332.  
  333. /*
  334.   Procedure to find the directory from the old list that matches the
  335.   directory name from the new list
  336.  
  337.   If the directory name is the same as the current directory, then
  338.   number and newdir are unchanged.
  339.  
  340.   If the directory name is not the same, and it exists on the old list, 
  341.   number will be the number of the old directory, and newdir is FALSE.
  342.   The current directory will be updated.
  343.  
  344.   If the directory name is not the same, and it does not exist on the
  345.   old list, newdir is FALSE.  Number is number of directories + 1, but
  346.   is never used.
  347.  
  348. */
  349.  
  350. void find_directory(number, newdir)
  351. int *number; 
  352. int *newdir; 
  353. {
  354.     /*  If the directory is the same, then the status of number and newdir  */
  355.     /*  will not change                        */
  356.    if ((strcmp(this_directory, current_directory) != 0))
  357.         {
  358.         /*  search from the beginning  --  nothing fancy  */
  359.         *number = 0;
  360.         do
  361.             {
  362.             *number = *number + 1;
  363.             }
  364.         while (!(((*number > number_directories) 
  365.             || (streq(this_directory, directories[*number - 1].directory)))));
  366.         *newdir = (*number > number_directories);
  367.         strcpy(current_directory, this_directory);
  368.         }
  369. }
  370.  
  371.  
  372. /*
  373.   Procedure to find the file name.  The directory name has been
  374.   found prior to this time, so the starting point in the search
  375.   has been found.  The search will continue until the first file
  376.    name in the next directory.
  377.  
  378. */
  379.  
  380. void find_file(number, new, number_begin, number_end)
  381. int *number; 
  382. int *new; 
  383. int number_begin; 
  384. int number_end; 
  385. {
  386.  
  387. /* 
  388.     check fileinfo[i] for i in the range [number_begin ... number_end)
  389.     or            [directories[dn - 1].filenum ... directories[dn].filenum)
  390. */
  391.     *new = 1;
  392.     *number = number_begin - 1;
  393.     do
  394.         {
  395.         *number = *number + 1;
  396.         }
  397.     while (*number < number_end && 
  398.         (*new = strcmp(filename, fileinfo[*number].name)));
  399. }
  400.  
  401. /*
  402.     Write the full pathname of a file, advancing to the 
  403.     next line if the path is longer than 27 characters.
  404. */
  405. write_path(ofile, dir, name) FILE *ofile; char *dir, *name;
  406. {    char path[60];
  407.     sprintf(path, "%s\\%s", dir, name);
  408.     if(strlen(path) > 28) 
  409.         fprintf(ofile, "%s\n                              ", path);
  410.     else
  411.         fprintf(ofile, "%-30s", path);
  412. }
  413.  
  414. /*
  415.   This procedure processes the new files.  new_file is the counter
  416.   for the number of new files.  The file name and information is
  417.   written to the file assigned to newfile.
  418. */
  419.  
  420. void file_new()
  421. {
  422.     new_file = new_file + 1;
  423.     write_path(newfile, this_directory, filename);
  424.     fprintf(newfile, 
  425.         "%s    %2d   %10ld   %04x\n", 
  426.         get_time(timeofday, filedate),
  427.         attribute, filesize, crc_value);
  428. }
  429.  
  430. /*
  431.   This procedure processes the deleted files.  del_file is the counter
  432.   for the number of deleted files.  The file name and information is
  433.   written to the file assigned to delfile.
  434. */
  435.  
  436. void file_del(dirnum, filnum) int dirnum, filnum;
  437. {
  438.     RR(("  file #%d = %s was deleted\n", filnum, fileinfo[filnum].name));
  439.     del_file = del_file + 1;
  440.     write_path(delfile, directories[dirnum].directory, fileinfo[filnum].name);
  441.     fprintf(delfile, "%s", 
  442.                 get_time(fileinfo[filnum].time_of_day, fileinfo[filnum].date));
  443.     fprintf(delfile, "    %2d   %10ld   %04x\n", 
  444.         fileinfo[filnum].attribute, 
  445.         fileinfo[filnum].file_size, 
  446.         fileinfo[filnum].crc);
  447. }
  448.  
  449. /*
  450.   This procedure processes the updated files.  Update_file is the counter
  451.   for the number of updated files.
  452.  
  453.   format of file...
  454.  
  455. Path                              Time         Date  Attr       Length    CRC
  456. I:\CHECK$$$.CRC               9:37:08  30 Aug 1988    32         1377   850C
  457.                        new:   9:37:08  30 Aug 1988    32         1377   850C
  458.                                                   ----22---1234567890---4444
  459. */
  460.  
  461. void file_updated()
  462. {    char old_attr;
  463.  
  464.     update_file = update_file + 1;
  465.     old_attr = fileinfo[file_number].attribute;
  466.     write_path(updatefile, this_directory, filename);
  467.     RR(("  file %s updated\n", filename));
  468.     fprintf(updatefile, "%s", 
  469.         get_time(fileinfo[file_number].time_of_day, 
  470.             fileinfo[file_number].date));
  471.     fprintf(updatefile, "    %2d   %10ld   %04x\n", 
  472.         old_attr, 
  473.         fileinfo[file_number].file_size, 
  474.         fileinfo[file_number].crc);
  475.     fprintf(updatefile, "                        new:  %s", 
  476.         get_time(timeofday, filedate));
  477.     fprintf(updatefile, "    %2d   %10ld   %04x\n", 
  478.         attribute, filesize, crc_value);
  479.     if(conservative && (old_attr & 0x07) )
  480.         {    /* system, hidden, or read-only attribute was set (note: 
  481.                 we're checking the attribute in the OLD crc file)  */
  482.         printf("change to ");
  483.         if(old_attr & 0x01) printf("read-only ");
  484.         if(old_attr & 0x02) printf("hidden ");
  485.         if(old_attr & 0x04) printf("system ");
  486.         printf("file %s\\%s\n", this_directory, filename);
  487.         printf("Old file: %s", 
  488.             get_time(fileinfo[file_number].time_of_day, 
  489.             fileinfo[file_number].date));
  490.         write_old_file(file_number);
  491.         printf("New file: %s", get_time(timeofday, filedate));
  492.         write_new_file( );
  493.         }
  494. }
  495.  
  496.  
  497. /*
  498.   This procedure processes the files that have not been changed, modified
  499.   or deleted.  OK_file is the counter for the number of such files.
  500. */
  501.  
  502. void file_ok()
  503. {
  504.     RR(("  file %s unchanged\n", filename));
  505.     ok_file = ok_file + 1;
  506. }
  507.  
  508.  
  509. /*
  510.   This procedure processes the files that have been modified without
  511.   changing the directory entry date or time.  Mod_file is the counter for
  512.   the number of such files.  In normal operations, this should not happen, 
  513.   so for such files, the name and date information is shown on the console
  514.   and sent to the file assigned to modfile.
  515. */
  516.  
  517. void bad_crc()
  518. {
  519.  
  520.     mod_file = mod_file + 1;
  521.     printf("CRCs or file lengths do not match!  File: %s\\%s\n", 
  522.         this_directory, filename);
  523.     printf("Old file: %s", 
  524.         get_time(fileinfo[file_number].time_of_day, 
  525.             fileinfo[file_number].date));
  526.     write_old_file(file_number);
  527.     printf("New file: %s", get_time(timeofday, filedate));
  528.     write_new_file( );
  529.  
  530.     write_path(modfile, this_directory, filename);
  531.     fprintf(modfile, "%s    %2d   %10ld   %04x\n", 
  532.         get_time(fileinfo[file_number].time_of_day, 
  533.             fileinfo[file_number].date), 
  534.         fileinfo[file_number].attribute, 
  535.         fileinfo[file_number].file_size, 
  536.         fileinfo[file_number].crc);
  537.     fprintf(modfile, 
  538.         "                        new:  %s    %2d   %10ld   %04x\n", 
  539.         get_time(timeofday, filedate),
  540.         attribute, filesize, crc_value);
  541. }
  542.  
  543.  
  544. /*
  545.   Procedure to read the list of new files, and compare them to the
  546.   old files.  The various comparison types are processed according to
  547.   the preceeding routines.
  548. */
  549.  
  550. void read_new_file()
  551. {
  552.     strcpy(current_directory, "");
  553.     new_dir = FALSE;
  554.     fscanf(infile, "%d %d", &new_time, &new_date);
  555.  
  556.     fprintf(newfile, "new files created on this disk\n");
  557.     fprintf(newfile, "between  %s  ", get_time(old_time, old_date));
  558.     fprintf(newfile, "and  %s\n", get_time(new_time, new_date));
  559.     fprintf(newfile, "\nPath                              Time         ");
  560.     fprintf(newfile, "Date  Attr       Length    CRC\n");
  561.  
  562.     fprintf(delfile, "files deleted on this disk\n");
  563.     fprintf(delfile, "between  %s  ", get_time(old_time, old_date));
  564.     fprintf(delfile, "and  %s\n", get_time(new_time, new_date));
  565.     fprintf(delfile, "\nPath                              Time         ");
  566.     fprintf(delfile, "Date  Attr       Length    CRC\n");
  567.  
  568.     fprintf(modfile, "files that were modified without updating ");
  569.     fprintf(modfile, "the creation time/date\n");
  570.     fprintf(modfile, "between  %s  ", get_time(old_time, old_date));
  571.     fprintf(modfile, "and  %s\n", get_time(new_time, new_date));
  572.     fprintf(modfile, "\nPath                              Time         ");
  573.     fprintf(modfile, "Date  Attr       Length    CRC\n");
  574.  
  575.     fprintf(updatefile, "files that were updated on this disk\n");
  576.     fprintf(updatefile, "between  %s  ", get_time(old_time, old_date));
  577.     fprintf(updatefile, "and  %s\n", get_time(new_time, new_date));
  578.     fprintf(updatefile, "\nPath                              Time         ");
  579.     fprintf(updatefile, "Date  Attr       Length    CRC\n");
  580.  
  581.     while (!eof(infile))
  582.         {
  583.         strcpy(this_directory, get_string( ));
  584.         /*  First is the directory name  */
  585.  
  586.         strcpy(filename, get_string( ));
  587.         RR(("directory \"%s\", file \"%s\"\n", this_directory, filename));
  588.         /*  Next is the file name  */
  589.  
  590.         fscanf(infile, "%d %d %d %ld %x\n", 
  591.             &attribute, 
  592.             &timeofday, 
  593.             &filedate, 
  594.             &filesize, 
  595.             &crc_value);
  596.         /*  Then the file parameters  */
  597.  
  598.         /*  Find the entry in the list of old files with the same name  */
  599.         find_directory(&directory_number, &new_dir);
  600.          if (!new_dir)
  601.             find_file(&file_number, &new, 
  602.                 directories[directory_number - 1].filenum, 
  603.                 directories[directory_number].filenum);
  604. /************
  605. if(debugging)
  606. {printf("checking directory %12s, file %12s:  files [%2d,%2d) new_dir=%d  new=%d\n", 
  607. this_directory, filename, 
  608. directories[directory_number - 1].filenum, 
  609. directories[directory_number].filenum, 
  610. new_dir, new);
  611. }
  612. ************/
  613.         if (new_dir || new)
  614.             /*  New directory means new file  */
  615.             file_new( );
  616.         else 
  617.             /*  Existing file, compare the two  */
  618.             {
  619.             RR(("  file #%d = %s survived\n", file_number, filename));
  620.             fileinfo[file_number].surviving = 1;
  621.             if ((fileinfo[file_number].time_of_day != timeofday) || 
  622.                 (fileinfo[file_number].date != filedate) ||
  623.                 (fileinfo[file_number].attribute != attribute) )
  624.                 file_updated( );
  625.             else 
  626.                 if (fileinfo[file_number].crc != crc_value ||
  627.                     fileinfo[file_number].file_size != filesize)
  628.                     bad_crc( );
  629.                 else 
  630.                     file_ok( );
  631.             }
  632.         }
  633. }
  634.  
  635.  
  636. help()
  637. {
  638.     printf("\nusage:  compare  [options]\n");
  639.     printf("options\n");
  640.     printf("   -c    conservative checking: report changes to \"hidden\", \n");
  641.     printf("         \"system\", or \"read-only\" files to screen\n");
  642. #ifdef CUSTOMIZABLE
  643.     printf("   -u    user customizing - reset file names\n");
  644. #endif /* CUSTOMIZABLE */
  645.     exit();
  646. }
  647.  
  648.  
  649. main(argc, argv) int argc; char *argv[];
  650. {
  651.     int dirnum, filnum, ac, i;
  652.     char *s, c, **av;
  653.  
  654.                                 /*  Compare  */
  655.     printf("CRC file integrity comparison program\n");
  656.     printf("Version %s, %s\n", VERSION_NUMBER, VERSION_DATE);
  657.     printf("Written by Ted H. Emigh -- ");
  658.     printf("emigh@ncsugn.uucp or NEMIGH@TUCC.BITNET\n");
  659.     printf("Modified by James R. Van Zandt -- jrv@mitre-bedford.arpa\n");
  660.  
  661.     ac = argc;
  662.     av = argv;
  663.     argc = 1;
  664.     while(--ac)
  665.         {s = *++av;
  666.         if(*s == '?') help();
  667.         if(*s == '-')
  668.             {while(c = *++s)
  669.                 {if(c == '?') help();
  670.                 else if(c == 'c') {conservative = 1;}
  671.                 else if(c == 'd') {debugging = 1;}
  672.  
  673. #ifdef CUSTOMIZABLE
  674.                 else if(c == 'u') {customizing = 1;}
  675. #endif
  676.  
  677.                 else printf("invalid command line switch %c ignored\n", c);
  678.                 }
  679.             }
  680.         else
  681.             argv[argc++] = s;
  682.         }
  683.  
  684. #ifdef CUSTOMIZABLE
  685.     if(customizing) rewrite_object_file();
  686. #endif
  687.  
  688.     number_directories = 1;
  689.     strcpy(current_directory, "");
  690.     strcpy(directories[0].directory, current_directory);
  691.     directories[0].filenum = 0;
  692.     /*  Reset the counters for the various comparisons  */
  693.     new_file = 0;
  694.     ok_file = 0;
  695.     update_file = 0;
  696.     mod_file = 0;
  697.     /*  Set up the input and output files  */
  698.     switch ((int)(argc - 1)) {
  699.         case 0:
  700.             {
  701.             /*  No command line parameters, use default names  */
  702.             cur_filename = signature.cur_crc_file;
  703.             new_filename = signature.new_crc_file;
  704.             }
  705.             break;
  706.         case 1:
  707.             {
  708.             /*  File name with listing of new files has been given  */
  709.             cur_filename = signature.cur_crc_file;
  710.             new_filename = argv[1];
  711.             }
  712.             break;
  713.         default:
  714.             {
  715.             /*  Both file names have been given  */
  716.             cur_filename = argv[2];
  717.             new_filename = argv[1];
  718.             }
  719.             break;
  720.     }
  721.     /*  Set up the various input and output files  */
  722.     infile = fopen(cur_filename, "r");
  723.     if(!infile)
  724.         {fprintf(stderr, "can't open %s\n", cur_filename);
  725.         exit(1);
  726.         }
  727.     newfile = creat(FILES_NEW);
  728.     delfile = creat(FILES_DEL);
  729.     modfile = creat(FILES_MOD);
  730.     updatefile = creat(FILES_UPD);
  731.     
  732.     
  733.     printf("\nReading old CRC list from %s...\n", cur_filename);
  734.     read_old_file( );
  735.     fclose(infile);
  736.     
  737.     infile = fopen(new_filename, "r");
  738.     if(!infile)
  739.         {fprintf(stderr, "can't open %s\n", new_filename);
  740.         fclose(newfile);
  741.         fclose(delfile);
  742.         fclose(modfile);
  743.         fclose(updatefile);
  744.         unlink(FILES_NEW);
  745.         unlink(FILES_DEL);
  746.         unlink(FILES_MOD);
  747.         unlink(FILES_UPD);
  748.         exit(1);
  749.         }
  750.     
  751. /**************
  752.     if(debugging)
  753.     {printf("number_directories=%d, old_file=%d\n", 
  754.                                                 number_directories, old_file);
  755.     for (dirnum = 0; dirnum < 5 && dirnum <= number_directories; dirnum++) 
  756.         show_dir(dirnum);
  757.     for (filnum = 0; 
  758.         filnum < directories[number_directories].filenum; 
  759.         filnum++) 
  760.         show_fil(filnum);
  761.     }
  762. **************/
  763.  
  764.     printf("Reading new CRC list from %s and comparing...\n\n", new_filename);
  765.     read_new_file( );
  766.     fclose(infile);
  767.  
  768.     for (dirnum = 0; dirnum < number_directories; dirnum++)
  769.         {
  770. /**************
  771.         if(debugging)
  772.         {printf("directory %d, checking for deleted files in range [%d,%d)\n", 
  773.                                             dirnum,
  774.                                             directories[dirnum].filenum, 
  775.                                             directories[dirnum + 1].filenum);
  776.         }
  777. ***************/
  778.         for (filnum = directories[dirnum].filenum;
  779.                 filnum < directories[dirnum + 1].filenum;
  780.                 filnum++)
  781.             {if(fileinfo[filnum].surviving == 0)
  782.                 file_del(dirnum, filnum);
  783.             }
  784.         }
  785.  
  786. /*    Close the output files */
  787.     fclose(newfile);
  788.     fclose(delfile);
  789.     fclose(modfile);
  790.     fclose(updatefile);
  791.  
  792. /*
  793.     Print the summary numbers for this check, 
  794.     and erase the output files if they are empty  
  795. */
  796.     printf("\n");
  797.     printf("%6d  files in the last CRC check\n",           old_file);
  798.     printf("\n");
  799.  
  800.     printf(  "%6d  files were deleted",                      del_file);
  801.     if(del_file) printf(            "       (see %s)", FILES_DEL);
  802.     else unlink(FILES_DEL);
  803.  
  804.     printf("\n\n");
  805.     printf("%6d  files are the same as last time\n",       ok_file);
  806.  
  807.     printf(  "%6d  new files",                               new_file);
  808.     if(new_file) printf(   "                (see %s)", FILES_NEW);
  809.     else unlink(FILES_NEW);
  810.  
  811.     printf("\n%6d  updated files",                         update_file);
  812.     if(update_file) printf(    "            (see %s)", FILES_UPD);
  813.     else unlink(FILES_UPD);
  814.  
  815.     printf("\n%6d  invalidly modified files",              mod_file);
  816.     if(mod_file) printf(                  " (see %s)", FILES_MOD);
  817.     else unlink(FILES_MOD);
  818.  
  819.     printf("\n%6d  files in this CRC check\n",
  820.                                 ok_file + new_file + update_file + mod_file);
  821.     printf("\n\n");
  822.  
  823. /*  No command line parameters  --  Rename the files with the file lists  */
  824.     if (argc == 1)
  825.         {
  826.         unlink(signature.old_crc_file);
  827.         rename(signature.cur_crc_file, signature.old_crc_file);
  828.         rename(signature.new_crc_file, signature.cur_crc_file);
  829.         printf("Old CRC file is now %s\n", signature.old_crc_file);
  830.         printf("New CRC file is now %s\n", signature.cur_crc_file);
  831.         printf("\n");
  832.         }
  833. }
  834.  
  835. #ifdef CUSTOMIZABLE
  836.  
  837. /*
  838.     customize parameters as instructed by the user
  839.  
  840. */
  841.  
  842. char *buffer;
  843. int buffer_length;
  844.  
  845. customize(pp) PARMS *pp;
  846. {    long ll, atol();
  847.     int i;
  848.     char time_string[9], *point, *index();
  849.  
  850.     printf("\nFile names may include drive letters and/or path names.\n");
  851.  
  852.     while(1)
  853.         {printf("    new name for this program (default %12s): ", 
  854.                                                         pp->compare_program);
  855.         fgets(buffer, 100, stdin);
  856.         buffer[strlen(buffer) - 1] = 0;        /* zap the \n */
  857.         strupr(buffer);
  858.         if(buffer[0] == 0)
  859.             break;
  860.         point = index(buffer, '.');
  861.         if(strlen(buffer) < sizeof(pp->compare_program) && 
  862.                                         point && streq(point, ".EXE")) 
  863.             {strcpy(pp->compare_program, buffer);    
  864.             break;
  865.             }
  866.         }
  867.  
  868.     while(1)
  869.         {while(1)
  870.             {printf("        name for new CRC file (default %12s): ", 
  871.                                                         pp->new_crc_file);
  872.             fgets(buffer, 100, stdin);
  873.             buffer[strlen(buffer) - 1] = 0;        /* zap the \n */
  874.             if(buffer[0] == 0) break;
  875.             strupr(buffer);
  876.             if(strlen(buffer) >= sizeof(pp->new_crc_file)) continue;
  877.             strcpy(pp->new_crc_file, buffer);    
  878.             break;
  879.             }
  880.         while(1)
  881.             {printf("    name for current CRC file (default %12s): ", 
  882.                                                         pp->cur_crc_file);
  883.             fgets(buffer, 100, stdin);
  884.             buffer[strlen(buffer) - 1] = 0;        /* zap the \n */
  885.             if(buffer[0] == 0) break;
  886.             strupr(buffer);
  887.             if(strlen(buffer) >= sizeof(pp->cur_crc_file)) continue;
  888.             strcpy(pp->cur_crc_file, buffer);    
  889.             break;
  890.             }
  891.         while(1)
  892.             {printf("        name for old CRC file (default %12s): ", 
  893.                                                         pp->old_crc_file);
  894.             fgets(buffer, 100, stdin);
  895.             buffer[strlen(buffer) - 1] = 0;        /* zap the \n */
  896.             strupr(buffer);
  897.             if(strlen(buffer) >= sizeof(pp->old_crc_file)) continue;
  898.             if(buffer[0]) strcpy(pp->old_crc_file, buffer);    
  899.             break;
  900.             }
  901.         if(strcmp(pp->old_crc_file, pp->new_crc_file) &&
  902.                     strcmp(pp->new_crc_file, pp->cur_crc_file) &&
  903.                     strcmp(pp->old_crc_file, pp->cur_crc_file)) break;
  904.         printf("new, current, and old CRC file names must be different.\n");
  905.         }
  906.  
  907.     printf("\nThe customizable values are now...\n");
  908.     printf("\t\t compare program: %s\n", pp->compare_program);
  909.     printf("\t\t    new CRC file: %s\n", pp->new_crc_file);
  910.     printf("\t\tcurrent CRC file: %s\n", pp->cur_crc_file);
  911.     printf("\t\t    old CRC file: %s\n", pp->old_crc_file);
  912.     printf("\nrecord these values? ");
  913.     if(tolower(getchar()) != 'y') exit();
  914.     printf("\n");
  915.  
  916.     times(time_string);                    /* reseed the random number */
  917.     srand(*(int *)(time_string + 7));    /* generator with the time of day */
  918.  
  919.     for (i = 0; i < 7; i++)                /* change the search strings */
  920.         {
  921.         pp->flag1[ rand()%sizeof(pp->flag1) - 1 ] ^= (rand()&0x0f);
  922.         pp->flag2[ rand()%sizeof(pp->flag2) - 1 ] ^= (rand()&0x0f);
  923.         }
  924. }    
  925.  
  926. /*    convert all characters in a string to upper case */    
  927. strupr(s) char *s;
  928. {    while(*s)
  929.         {*s = toupper(*s);
  930.         s++;
  931.         }
  932. }
  933.  
  934.  
  935. /*
  936.     based on a parameter update program in DeSmet Gazette, Dec 86
  937.         by King Computer Services, Inc.
  938.     modified for DeSmet environment by Pacific Data Works
  939.     modified to search the path by J. R. Van Zandt
  940. */
  941. /* rewrite_object_file - change customizable parameters in file */
  942. rewrite_object_file()
  943. {    long lseek(), findinst(), fpos, c;
  944.     FILE *exefile;        /* file to be modified */
  945.     int        j;
  946.     char *pname();
  947.     PARMS file_parms;
  948.  
  949.     buffer = fileinfo;
  950.     buffer_length = sizeof(fileinfo);
  951.  
  952.     printf("\nCOMPARE user customization...\n");
  953.  
  954.     if(!pname(name_of_file, sizeof(name_of_file) - 1))
  955.         strcpy(name_of_file, signature.compare_program);
  956.  
  957.                                          /* open for binary update */
  958.     while((exefile = open(name_of_file,2)) == ERR)
  959.         {printf("file %s not found\n", name_of_file);
  960.         printf("path for this program (<return> to abort): ");
  961.         fgets(name_of_file, sizeof(name_of_file) - 1, stdin);
  962.         name_of_file[strlen(name_of_file) - 1] = 0;        /* zap the \n */
  963.         if(name_of_file[0] == 0) exit(1);
  964.         strupr(name_of_file);
  965.         }
  966.     printf("%s opened for updating\n", name_of_file);
  967.  
  968.     fpos = findinst(exefile, &signature, signature.flag2, 
  969.         buffer, buffer_length);
  970.  
  971.     lseek(exefile, fpos, 0);
  972.     fread(&file_parms, 1, sizeof(signature), exefile);
  973.  
  974.     lseek(exefile, fpos + 1, 0);
  975.     if(findinst(exefile, &signature, signature.flag2, 
  976.         buffer, buffer_length))
  977.         {/* 
  978.             We've found a second copy of the flag strings which
  979.             surround the parameter block.  This probably means the
  980.             compiler left an extra copy of the flag strings in some
  981.             buffer, then included the buffer in the compiled code.  To
  982.             work around the problem, make some change to the source
  983.             code like adding a big string, then recompile.  Changing
  984.             the flag strings might be a good idea, too - just in case
  985.             they match a piece of object code somewhere!
  986.         */
  987.         fprintf(stderr, 
  988.             "more than one parameter block in .EXE file - \
  989. don't know which to use!");
  990.         exit(1);   
  991.         }
  992.  
  993.     customize(&signature);
  994.  
  995.     lseek(exefile, fpos, 0);
  996.     fwrite(&signature, 1, sizeof(signature), exefile);
  997.     printf("recorded\n");
  998.  
  999.     fclose(exefile);
  1000.     exit(0);
  1001. }
  1002.  
  1003. /*
  1004.     pname - get pathname of currently running program (else returns 0)
  1005. */
  1006. char *pname(buf, max_chars) char *buf; int max_chars;
  1007. {    unsigned length, seg,   off;
  1008. /*           [bp-2]  [bp-4] [bp-6]  */
  1009.  
  1010. #ifdef DESMET
  1011. #pragma ex+                    /* enable #asm directive */
  1012.  
  1013. #asm
  1014.     mov    ax,3000h    ; check if DOS 3.0 or later
  1015.     int    21H        ; (force al = 0 in case of DOS 1)
  1016.     cmp    al,3
  1017.     jb    argv7        ; DOS 1 or 2, return null parameter
  1018.     mov    ax,cs
  1019.     sub    ax,10h        ; calculate PSP segment (for DeSmet compiler)
  1020.     mov    es,ax
  1021.     mov    es,es:[2ch]    ; get environment segment from PSP
  1022.     mov    ax,es
  1023.     mov    [bp-4],ax    ; seg  =  environment segment
  1024.     xor    di,di        ; find the program name by
  1025.     xor    al,al        ; first skipping over all the
  1026.     mov    cx,-1        ; environment variables...
  1027.     cld
  1028. argv9:    repne    scasb        ; scan for double null (can't use
  1029.     scasb            ; scasw since might be odd addr.)
  1030.     jne    argv9        ; loop if it was a single null
  1031.     add    di,2        ; skip count word in environment
  1032.     mov    [bp-6],di    ; off = program name offset
  1033.     mov    cx,-1        ; now find its length...
  1034.     repne    scasb        ; scan for another null byte
  1035.     not    cx        ; convert cx to length
  1036.     dec    cx
  1037.     jmp    argvx
  1038. ;    REP MOVSB        ; es:di++ = ds:si++, while(cx--)
  1039.  
  1040. argv7:    xor    cx,cx
  1041. argvx:    mov    [bp-2],cx    ; length = program name length
  1042. #endasm
  1043.  
  1044. #else
  1045.     return 0;
  1046. #endif /* DESMET */
  1047.  
  1048.     if(length == 0) 
  1049.         return 0;
  1050.     if(length > max_chars) length = max_chars;
  1051.     _lmove(length, off, seg, buf, _showds());
  1052.     return buf;
  1053. }
  1054.     
  1055. /*
  1056.     This is the generic routine to find a flag string in an .exe file
  1057.     to be used as a pointer to the beginning of installable parameters. 
  1058.     Returns a long containing the position of the flag, or zero if the
  1059.     flag is not found.  File pointer points to the beginning of the
  1060.     struct.  Buffer, which must be long enough, contains the structure
  1061.     starting at the flag.
  1062.  
  1063.     Method...
  1064.     1. Read bytes into a buffer at least as long as the struct.
  1065.     2. Search the buffer for a match on both flags.
  1066.     3. If no match, move data at end of buffer to beginning of buffer,
  1067.        read in another batch from file.
  1068.     4. Go to 2 until match found.
  1069.     5. When match found, move matched code to head of buffer.
  1070.     6. lseek to the file position found and return the fpos.
  1071. */
  1072. long findinst(filen, flag1, flag2, buffer, buflen)
  1073. FILE *filen;
  1074. char *flag1, *flag2, *buffer;
  1075. unsigned buflen;
  1076. {    long f_pos;
  1077.     int nomatch, len;
  1078.     int structlen;
  1079.     int i, istop, j, k;
  1080.  
  1081.     nomatch = 1;        /* initialize status to "no match" */
  1082.     structlen = flag2 - flag1 + strlen(flag2) + 1;
  1083.  
  1084.     f_pos = fseek(filen, 0L, 1);
  1085.     len = 0;
  1086.     while(nomatch)
  1087.         {len += read(filen, &buffer[len], buflen - len - 1);
  1088.         if(len < structlen)    /* if we couldn't read enough bytes */
  1089.             return(0L);
  1090.  
  1091.         i = 0;    /* step through buffer char by char */
  1092.         istop = len - structlen + 1;
  1093.  
  1094.         while(((buffer[i] != *flag1)||
  1095.                 (nomatch = strcmp(&buffer[i], flag1))||
  1096.                 (nomatch = strcmp(&buffer[i + flag2 - flag1], flag2))) &&
  1097.             (i < istop))
  1098.             i++;        /* searching for the flags */
  1099.         if (nomatch)
  1100.             {/*    
  1101.                 if not found, move the tail end of the data to the head
  1102.                 of the buffer, set the number of bytes in the buffer,
  1103.                 reset file pointer, and return for another read
  1104.             */
  1105.             f_pos += i;
  1106.             for (j = 0; i < len;  ) buffer[j++] = buffer[i++];
  1107.             len = j;
  1108.             }
  1109.         else
  1110.             {f_pos += i;    /* update filepointer with the pos of match */
  1111.                             /* move structure to head of buffer */
  1112.             for (j = 0; j < structlen;  ) buffer[j++] = buffer[i++];
  1113.  
  1114.             }
  1115.         }
  1116.     lseek(filen, f_pos, 0);    /* set file pointer to beginning of structure */
  1117.     return (f_pos);
  1118. }
  1119.  
  1120. #endif /* CUSTOMIZABLE */
  1121.