home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c019 / 1.ddi / AR001 / AR.C next >
Encoding:
C/C++ Source or Header  |  1990-04-23  |  10.5 KB  |  419 lines

  1. /***********************************************************
  2.     ar.c -- archiver in ANSI C
  3.     Apr 22 1990 H.Okumura
  4. ***********************************************************/
  5.  
  6. static char *usage =
  7.     "ar -- archiver\n"
  8.     "Usage: ar command archive [file ...]\n"
  9.     "Commands:\n"
  10.     "   a: Add files to archive (replace if present)\n"
  11.     "   x: Extract files from archive\n"
  12.     "   r: Replace files in archive\n"
  13.     "   d: Delete files from archive\n"
  14.     "   p: Print files on standard output\n"
  15.     "   l: List contents of archive\n"
  16.     "If no files are named, all files in archive are processed,\n"
  17.     "   except for commands 'a' and 'd'.\n"
  18.     "You may copy and distribute this program freely.\n";
  19.  
  20. /***********************************************************
  21. Structure of archive block (low order byte first):
  22.  2    basic header size (from 'method' thru 'filename' below)
  23.         = 18 + strlen(filename) (= 0 if end of archive)
  24.  2    method (0 = stored, 1 = compressed)
  25.  1    file type (0: binary, 1: text(not supported yet))
  26.  1    sec + (timeinfo << 6), where timeinfo = 0 (local),
  27.         1 (local, not DST), 2 (local, DST),
  28.         3 (UTC, not supported yet).
  29.  2    (day << 11) + (hour << 6) + min
  30.  2    ((year - 1900) << 4) + month
  31.  4    compressed size
  32.  4    original size
  33.  2    original file's CRC
  34.  ?    filename (not null-terminated)
  35.  2    basic header CRC
  36.  2    1st extended header size (0 if none)
  37.  ?    1st extended header
  38.  2    1st extended header's CRC
  39.  ...
  40.  ?    compressed file
  41. ***********************************************************/
  42.  
  43. #include "ar.h"
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <ctype.h>
  47. #include <time.h>
  48.  
  49. #define BYTESIZE  8
  50. #define FNAME_MAX  1024
  51. #define HEADERSIZE_MAX  (FNAME_MAX + 18)
  52. #define BUFFERSIZE  4096
  53.  
  54. int unpackable;  /* global, set in io.c */
  55. ulong compsize, origsize;  /* global */
  56. uchar buffer[BUFFERSIZE];
  57.  
  58. static uchar header[HEADERSIZE_MAX + 1];
  59. static ushort headersize, method;
  60. static uchar file_type, flag_sec;
  61. static ushort day_hour_min, year_mon;
  62. #define filename ((char *)&header[18])
  63. static ushort file_crc, header_crc;
  64.  
  65. static ushort namelen;
  66. static char *temp_name;
  67.  
  68. static uint ratio(ulong a, ulong b)  /* [(1000a + [b/2]) / b] */
  69. {
  70.     int i;
  71.  
  72.     for (i = 0; i < 3; i++)
  73.         if (a <= ULONG_MAX / 10) a *= 10;  else b /= 10;
  74.     if ((ulong)(a + (b >> 1)) < a) {  a >>= 1;  b >>= 1;  }
  75.     if (b == 0) return 0;
  76.     return (uint)((a + (b >> 1)) / b);
  77. }
  78.  
  79. static void putword(ushort x, FILE *f)
  80. {
  81.     fputc(x & 0xFF, f);
  82.     fputc(x >> BYTESIZE, f);
  83. }
  84.  
  85. ushort getword(FILE *f)
  86. {
  87.     ushort x;
  88.  
  89.     x = fgetc(f);
  90.     return x + ((uint)fgetc(f) << BYTESIZE);
  91. }
  92.  
  93. static void put_to_header(int i, ushort x)
  94. {
  95.     header[i]     = (uchar)(x & 0xFF);
  96.     header[i + 1] = (uchar)(x >> BYTESIZE);
  97. }
  98.  
  99. ushort headerword(int i)
  100. {
  101.     return header[i] + ((ushort)header[i + 1] << BYTESIZE);
  102. }
  103.  
  104. static int read_header(void)
  105. {
  106.     ushort extheadersize;
  107.  
  108.     headersize = getword(arcfile);
  109.     if (headersize == 0) return 0;  /* end of archive */
  110.     if (headersize > HEADERSIZE_MAX) error("Bad header");
  111.     crc = 0xFFFFU;
  112.     fread_crc(header, headersize, arcfile);
  113.     header_crc = getword(arcfile);
  114.     if ((crc ^ 0xFFFFU) != header_crc) error("Header CRC error");
  115.     method = headerword(0);
  116.     file_type = header[2];
  117.     flag_sec = header[3];
  118.     day_hour_min = headerword(4);
  119.     year_mon = headerword(6);
  120.     compsize = headerword(8)  + ((ulong)headerword(10) << (2 * BYTESIZE));
  121.     origsize = headerword(12) + ((ulong)headerword(14) << (2 * BYTESIZE));
  122.     file_crc = headerword(16);
  123.     namelen = headersize - 18;
  124.     filename[namelen] = '\0';
  125.     while ((extheadersize = getword(arcfile)) != 0)
  126.         fseek(arcfile, extheadersize + 2, SEEK_CUR);
  127.     return 1;  /* success */
  128. }
  129.  
  130. static void set_header(void)
  131. {
  132.     time_t t;
  133.     struct tm *tp;
  134.  
  135.     t = time(NULL);  tp = localtime(&t);
  136.     flag_sec = tp->tm_sec;
  137.     if      (tp->tm_isdst == 0) flag_sec +=  64;
  138.     else if (tp->tm_isdst >  0) flag_sec += 128;
  139.     /* tp = gmtime(&t); --> flag_sec +=  64 + 128; */
  140.     day_hour_min =
  141.         (tp->tm_mday << 11) + (tp->tm_hour << 6) + tp->tm_min;
  142.     year_mon = (tp->tm_year << 4) + tp->tm_mon;
  143.     file_type = 0;  /* binary */
  144.  
  145.     put_to_header( 0, method);
  146.     header[2] = file_type;  header[3] = flag_sec;
  147.     put_to_header( 4, day_hour_min);
  148.     put_to_header( 6, year_mon);
  149.     put_to_header( 8, (ushort)compsize & 0xFFFFU);
  150.     put_to_header(10, (ushort)(compsize >> 16));
  151.     put_to_header(12, (ushort)origsize & 0xFFFFU);
  152.     put_to_header(14, (ushort)(origsize >> 16));
  153.     put_to_header(16, file_crc);
  154. }
  155.  
  156. static void write_header(void)
  157. {
  158.     putword(headersize, outfile);
  159.     crc = 0xFFFFU;
  160.     fwrite_crc(header, headersize, outfile);
  161.     putword(crc ^ 0xFFFFU, outfile);
  162.     putword(0, outfile);  /* no ext header */
  163. }
  164.  
  165. static void skip(void)
  166. {
  167.     fseek(arcfile, compsize, SEEK_CUR);
  168. }
  169.  
  170. static void copy(void)
  171. {
  172.     uint n;
  173.  
  174.     write_header();
  175.     while (compsize != 0) {
  176.         n = (uint)((compsize > BUFFERSIZE) ? BUFFERSIZE : compsize);
  177.         if (fread ((char *)buffer, 1, n, arcfile) != n)
  178.             error("Can't read");
  179.         if (fwrite((char *)buffer, 1, n, outfile) != n)
  180.             error("Can't write");
  181.         compsize -= n;
  182.     }
  183. }
  184.  
  185. static void store(void)
  186. {
  187.     uint n;
  188.  
  189.     origsize = 0;
  190.     crc = 0xFFFFU;
  191.     while ((n = fread((char *)buffer, 1, BUFFERSIZE, infile)) != 0) {
  192.         fwrite_crc(buffer, n, outfile);  origsize += n;
  193.     }
  194.     compsize = origsize;
  195. }
  196.  
  197. static int add(int replace_flag)
  198. {
  199.     long headerpos, arcpos;
  200.     uint r;
  201.  
  202.     if ((infile = fopen(filename, "rb")) == NULL) {
  203.         fprintf(stderr, "Can't open %s\n", filename);
  204.         return 0;  /* failure */
  205.     }
  206.     if (replace_flag) {
  207.         printf("Replacing %s ", filename);  skip();
  208.     } else
  209.         printf("Adding %s ", filename);
  210.     headerpos = ftell(outfile);
  211.     namelen = strlen(filename);
  212.     headersize = 18 + namelen;
  213.     method = 1;
  214.     write_header();  /* temporarily */
  215.     arcpos = ftell(outfile);
  216.     origsize = compsize = 0;  unpackable = 0;
  217.     crc = 0xFFFFU;  encode();
  218.     if (unpackable) {
  219.         method = 0;  /* store */
  220.         rewind(infile);
  221.         fseek(outfile, arcpos, SEEK_SET);
  222.         store();
  223.     }
  224.     file_crc = crc ^ 0xFFFFU;
  225.     fclose(infile);
  226.     set_header();
  227.     fseek(outfile, headerpos, SEEK_SET);
  228.     write_header();
  229.     fseek(outfile, 0L, SEEK_END);
  230.     r = ratio(compsize, origsize);
  231.     printf(" %d.%d%%\n", r / 10, r % 10);
  232.     return 1;  /* success */
  233. }
  234.  
  235. static void unstore(void)
  236. {
  237.     uint n;
  238.  
  239.     crc = 0xFFFFU;
  240.     while (compsize != 0) {
  241.         n = (uint)((compsize > BUFFERSIZE) ? BUFFERSIZE : compsize);
  242.         if (fread((char *)buffer, 1, n, arcfile) != n)
  243.             error("Can't read");
  244.         fwrite_crc(buffer, n, outfile);
  245.         if (outfile != stdout) putc('.', stderr);
  246.         compsize -= n;
  247.     }
  248. }
  249.  
  250. int get_line(char *s, int n)
  251. {
  252.     int i, c;
  253.  
  254.     i = 0;
  255.     while ((c = getchar()) != EOF && c != '\n')
  256.         if (i < n) s[i++] = (char)c;
  257.     s[i] = '\0';
  258.     return i;
  259. }
  260.  
  261. static void extract(int to_file)
  262. {
  263.     if (to_file) {
  264.         while ((outfile = fopen(filename, "wb")) == NULL) {
  265.             fprintf(stderr, "Can't open %s\nnew filename: ", filename);
  266.             if (get_line(filename, FNAME_MAX) == 0) {
  267.                 fprintf(stderr, "Not extracted\n");
  268.                 skip();  return;
  269.             }
  270.             namelen = strlen(filename);
  271.         }
  272.         printf("Extracting %s ", filename);
  273.     } else {
  274.         outfile = stdout;
  275.         printf("===== %s =====\n", filename);
  276.     }
  277.     crc = 0xFFFFU;
  278.     if      (method == 1) decode();
  279.     else if (method == 0) unstore();
  280.     else {
  281.         fprintf(stderr, "Unknown method: %u\n", method);
  282.         skip();
  283.     }
  284.     if (to_file) fclose(outfile);  else outfile = NULL;
  285.     printf("\n");
  286.     if ((crc ^ 0xFFFFU) != file_crc)
  287.         fprintf(stderr, "CRC error\n");
  288. }
  289.  
  290. static void list_start(void)
  291. {
  292.     printf("Filename     Mode  Original Compressed Ratio"
  293.            "  Archived date/time  CRC Method\n");
  294. }
  295.  
  296. static void list(void)
  297. {
  298.     uint r;
  299.     char dst[4] = { ' ', 'N', 'D', 'U' };
  300.         /* Local(no DST info), Local(not DST), Local(DST), UTC */
  301.     char mode[2] = { 'B', 'T' };  /* Binary, Text */
  302.  
  303.     printf("%-14s", filename);
  304.     if (namelen > 14) printf("\n              ");
  305.     r = ratio(compsize, origsize);
  306.     printf(" %c %10lu %10lu %u.%3u %4u-%02u-%02u %02u:%02u:%02u%c %04X %5u\n",
  307.         mode[file_type & 1], origsize, compsize, r / 1000, r % 1000,
  308.         (year_mon >> 4) + 1900, (year_mon & 15) + 1,
  309.         day_hour_min >> 11, (day_hour_min >> 6) & 31, day_hour_min & 31,
  310.         flag_sec & 63, dst[flag_sec >> 6],
  311.         file_crc, method);
  312. }
  313.  
  314. static int match(char *s1, char *s2)
  315. {
  316.     for ( ; ; ) {
  317.         while (*s2 == '*' || *s2 == '?') {
  318.             if (*s2++ == '*')
  319.                 while (*s1 && *s1 != *s2) s1++;
  320.             else if (*s1 == 0)
  321.                 return 0;
  322.             else s1++;
  323.         }
  324.         if (*s1 != *s2) return 0;
  325.         if (*s1 == 0  ) return 1;
  326.         s1++;  s2++;
  327.     }
  328. }
  329.  
  330. static int search(int argc, char *argv[])
  331. {
  332.     int i;
  333.  
  334.     if (argc == 3) return 1;
  335.     for (i = 3; i < argc; i++)
  336.         if (match(filename, argv[i])) return 1;
  337.     return 0;
  338. }
  339.  
  340. static void exitfunc(void)
  341. {
  342.     fclose(outfile);  remove(temp_name);
  343. }
  344.  
  345. int main(int argc, char *argv[])
  346. {
  347.     int i, j, cmd, count, nfiles, found, done;
  348.  
  349.     cmd = toupper(argv[1][0]);
  350.     if (argv[1][1] || strchr("AXRDPL", cmd) == NULL)
  351.         error("Invalid command: %s", argv[1]);
  352.     if (argc < 3 + (strchr("AD", cmd) != NULL)) error(usage);
  353.     count = 0;
  354.     for (i = 3; i < argc; i++)
  355.         if (strpbrk(argv[i], "*?")) count++;
  356.     if (cmd == 'A' && count != 0)
  357.         error("Wildcards not allowed for command 'a'");
  358.     if (count == 0) nfiles = argc - 3;  else nfiles = -1;
  359.     arcfile = fopen(argv[2], "rb");
  360.     if (arcfile == NULL && cmd != 'A')
  361.         error("Can't open %s", argv[2]);
  362.     temp_name = NULL;
  363.     if (strchr("ARD", cmd)) {
  364.         temp_name = tmpnam(NULL);
  365.         outfile = fopen(temp_name, "wb");
  366.         if (outfile == NULL)
  367.             error("Can't open temporary file");
  368.         atexit(exitfunc);
  369.     }
  370.     make_crctable();  count = done = 0;
  371.     if (cmd == 'A') {
  372.         for (i = 3; i < argc; i++) {
  373.             for (j = 3; j < i; j++)
  374.                 if (strcmp(argv[j], argv[i]) == 0) break;
  375.             if (j == i) {
  376.                 strcpy(filename, argv[i]);
  377.                 if (add(0)) count++;  else argv[i][0] = 0;
  378.             } else nfiles--;
  379.         }
  380.         if (count == 0 || arcfile == NULL) done = 1;
  381.     }
  382.     while (! done && read_header()) {
  383.         found = search(argc, argv);
  384.         switch (cmd) {
  385.         case 'R':
  386.             if (found) {
  387.                 if (add(1)) count++;  else copy();
  388.             } else copy();
  389.             break;
  390.         case 'A':  case 'D':
  391.             if (found) {
  392.                 count += (cmd == 'D');  skip();
  393.             } else copy();
  394.             break;
  395.         case 'X':  case 'P':
  396.             if (found) {
  397.                 extract(cmd == 'X');
  398.                 if (++count == nfiles) done = 1;
  399.             } else skip();
  400.             break;
  401.         case 'L':
  402.             if (found) {
  403.                 if (count == 0) list_start();
  404.                 list();
  405.                 if (++count == nfiles) done = 1;
  406.             }
  407.             skip();  break;
  408.         }
  409.     }
  410.     if (temp_name != NULL && count != 0) {
  411.         putword(0, outfile);  /* end of archive */
  412.         if (ferror(outfile) || fclose(outfile) == EOF)
  413.             error("Can't write");
  414.         remove(argv[2]);  rename(temp_name, argv[2]);
  415.     }
  416.     printf("  %d files\n", count);
  417.     return EXIT_SUCCESS;
  418. }
  419.