home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 2 / MECOMP-CD-II.iso / amiga / tools / packer / detarv1.3 / detar.c next >
Encoding:
C/C++ Source or Header  |  1997-10-27  |  10.4 KB  |  502 lines

  1. /*
  2. **      $VER: DeTar.c 1.3 (27.10.97)
  3. **
  4. **      DeTar main module
  5. **
  6. **      written in 1995-97 by Andreas R. Kleinert, based on code by Steve Sampson
  7. **      Public Domain. (See DeTar.doc)
  8. */
  9.  
  10. /* ------------------------------------------------------------------------------ */
  11.  
  12. /*
  13.  *      detar.c
  14.  *
  15.  *      Version 1.1
  16.  *
  17.  *      Fixed bug in convert() wich produced errors on files without
  18.  *      a slash '/' in them.
  19.  *
  20.  *      Unix Tape Archive (TAR) Extractor for MSDOS
  21.  *
  22.  *      Public Domain January 1988, Steve Sampson
  23.  *      Based on the public domain TAR program by John Gilmore
  24.  *
  25.  *      Compiled with ECO-C88 V3.21
  26.  *
  27.  */
  28.  
  29. /* Includes */
  30.  
  31. #define __USE_SYSBASE
  32.  
  33. #include <exec/types.h>
  34.  
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <stdlib.h>
  38. #include <ctype.h>
  39. #include <time.h>
  40.  
  41. #include <proto/exec.h>
  42. #include <proto/dos.h>
  43.  
  44. #include "detar.h"
  45.  
  46. /* Defines */
  47.  
  48. #define isodigit(c)     ( ((c) >= '0') && ((c) <= '7') )
  49.  
  50. /* Globals */
  51.  
  52. FILE    *fdi,
  53.         *fdo;
  54.  
  55. union   record  *head;          /* the archive file header */
  56. struct  stat    hstat;          /* the decoded stat info   */
  57. struct  {
  58.         long    year;
  59.         long    month;
  60.         long    day;
  61.         long    hour;
  62.         long    min;
  63.         long    sec;
  64. } tm;
  65.  
  66. long    ugswidth = 11;
  67. long     dir_only = 0;
  68.  
  69. char    tempname[102];
  70.  
  71. char version [] = "\0$VER: detar 1.3 (27.10.97)";
  72.  
  73.  
  74. /* Forward References, Prototypes */
  75.  
  76. void dir_tar(void);
  77. void de_tar(void);
  78. void decode_header(union record *header, struct stat *st, long *stdp);
  79. void demode(unsigned mode, char *string);
  80. long from_oct(long digs, char *where);
  81.  
  82.  
  83. /* Main Program */
  84.  
  85. void main(long argc, char **argv)
  86. {
  87.  char   *p;
  88.  
  89.  /* The operator can ask for directory only or de-tar only. */
  90.  
  91.  argv++;
  92.  
  93.  if (argc == 3 && **argv == 'd')
  94.   {
  95.    dir_only++;
  96.    argc--;
  97.    argv++;
  98.   }
  99.  
  100.  if (argc != 2)
  101.   {
  102.    fprintf(stderr, &version[7]);
  103.  
  104.    fprintf(stderr, "\nAmiga Port by Andreas R. Kleinert in 1995-97. Public Domain."
  105.                    "\nPublic Domain January 1988, Steve Sampson"
  106.                    "\nBased on the public domain TAR program by John Gilmore");
  107.  
  108.    fprintf(stderr, "\nUsage: detar [d] filename[.tar]");
  109.    fprintf(stderr, "\nWhere d means directory only\n");
  110.  
  111.    exit(1);
  112.   }
  113.  
  114.  for (p = *argv; *p; p++) *p = (char)toupper(*p);
  115.  
  116.  /* parse the many possibilities, this stuff not needed with MSC */
  117.  
  118.  if ((p = strrchr(*argv, '.')) == (char *)NULL) goto add;
  119.   else if (strcmp(p, ".TAR") == NULL) strcpy(tempname, *argv);
  120.   else if (*(p+1) == '/' || *(p+1) == '\\')
  121.    {
  122. add: strcpy(tempname, *argv);
  123.      strcat(tempname, ".TAR");
  124.    }else
  125.    {
  126.      fprintf(stderr, "File '%s' not a TAR archive\n", *argv);
  127.  
  128.      exit(1);
  129.    }
  130.  
  131.  if ((fdi = fopen(tempname, "rb")) == (FILE *)NULL)
  132.   {
  133.    fprintf(stderr, "Tar File '%s' Not Found\n", tempname);
  134.    exit(1);
  135.   }
  136.  
  137.  head = (union record *)malloc(512);
  138.  
  139.  if (dir_only) dir_tar();
  140.   else         de_tar();
  141.  
  142.  free(head);
  143.  
  144.  exit(0);
  145. }
  146.  
  147.  
  148. /*
  149.  *      Produce a directory of the files contained on the TAR
  150.  */
  151.  
  152. void dir_tar(void)
  153. {
  154.  char   modes[11], *timestamp;
  155.  char   uform[11], gform[11];
  156.  char   *user, *group, size[24];
  157.  long   n, pad, header_std;
  158.  time_t timeval;
  159.  
  160.  for (;;)
  161.   {
  162.    if ((n = fread((char *)head, 1, 512, fdi)) == EOF)
  163.     {
  164.      fclose(fdi);
  165.      return;
  166.     }
  167.  
  168.    decode_header(head, &hstat, &header_std);
  169.  
  170.    /* File type and modes */
  171.  
  172.    modes[0] = '?';
  173.  
  174.    switch (head->header.linkflag)
  175.     {
  176.      case LF_NORMAL:
  177.      case LF_OLDNORMAL:
  178.      case LF_LINK:
  179.       {
  180.        modes[0] = '-';
  181.        if ('/' == head->header.name[strlen(head->header.name)-1])
  182.        modes[0] = 'd';
  183.        break;
  184.       }
  185.      case LF_DIR:
  186.       {
  187.        modes[0] = 'd';
  188.        break;
  189.       }
  190.      case LF_SYMLINK:
  191.       {
  192.        modes[0] = 'l';
  193.        break;
  194.       }
  195.      case LF_BLK:
  196.       {
  197.        modes[0] = 'b';
  198.        break;
  199.       }
  200.      case LF_CHR:
  201.       {
  202.        modes[0] = 'c';
  203.        break;
  204.       }
  205.      case LF_FIFO:
  206.       {
  207.        modes[0] = 'f';
  208.        break;
  209.       }
  210.      case LF_CONTIG:
  211.       {
  212.        modes[0] = '=';
  213.        break;
  214.       }
  215.     }
  216.  
  217.    demode(hstat.st_mode, modes+1);
  218.  
  219.    /* Timestamp */
  220.  
  221.    timeval = hstat.st_mtime;
  222.    timestamp = ctime(&timeval);
  223.    timestamp[16] = '\0';
  224.    timestamp[24] = '\0';
  225.  
  226.    /* User and group names */
  227.  
  228.    if (*head->header.uname && header_std)
  229.     {
  230.      user  = head->header.uname;
  231.     }else
  232.     {
  233.      user = uform;
  234.      sprintf(uform, "%ld", (long)hstat.st_uid);
  235.     }
  236.  
  237.    if (*head->header.gname && header_std)
  238.     {
  239.      group = head->header.gname;
  240.     }else
  241.     {
  242.      group = gform;
  243.      sprintf(gform, "%ld", (long)hstat.st_gid);
  244.     }
  245.  
  246.    /* Format the file size or major/minor device numbers */
  247.  
  248.    switch (head->header.linkflag)
  249.     {
  250.      case LF_CHR:
  251.      case LF_BLK:
  252.       {
  253.        sprintf(size, "%ld, %ld",
  254.        (long)from_oct(8, head->header.devmajor),
  255.        (long)from_oct(8, head->header.devminor));
  256.        break;
  257.       }
  258.      default:
  259.       {
  260.        sprintf(size, "%ld", hstat.st_size);
  261.  
  262.        break;
  263.       }
  264.     }
  265.  
  266.  
  267.    /* Figure out padding and print the whole line. */
  268.  
  269.    pad = strlen(user) + strlen(group) + strlen(size) + 1;
  270.  
  271.    if (pad > ugswidth) ugswidth = pad;
  272.  
  273.     printf("%s %s/%s %*s%s %s %s %.*s",
  274.         modes,
  275.         user,
  276.         group,
  277.         ugswidth - pad,
  278.         "",
  279.         size,
  280.         timestamp+4, timestamp+20,
  281.         sizeof(head->header.name),
  282.         head->header.name);
  283.  
  284.     switch (head->header.linkflag)
  285.      {
  286.       case LF_SYMLINK:
  287.        {
  288.         printf(" -> %s\n", head->header.linkname);
  289.         break;
  290.        }
  291.       case LF_LINK:
  292.        {
  293.         printf(" link to %s\n", head->header.linkname);
  294.         break;
  295.        }
  296.  
  297.       default:
  298.        {
  299.         printf(" unknown file type '%c'\n", head->header.linkflag);
  300.         break;
  301.        }
  302.  
  303.       case LF_OLDNORMAL:
  304.       case LF_NORMAL:
  305.       case LF_CHR:
  306.       case LF_BLK:
  307.       case LF_DIR:
  308.       case LF_FIFO:
  309.       case LF_CONTIG:
  310.        {
  311.         putc('\n', stdout);
  312.         break;
  313.        }
  314.     }
  315.  
  316.    /* Seek to next file */
  317.  
  318.    fseek(fdi, hstat.st_size, 1);
  319.  
  320.    /* File starts on 512 byte boundary */
  321.  
  322.    fseek(fdi, 512L - (hstat.st_size % 512L), 1);
  323.   }
  324. }
  325.  
  326.  
  327. /*
  328.  *      Extract the files from the TAR archive
  329.  *
  330.  */
  331.  
  332. void de_tar(void)
  333. {
  334.         ULONG   size, filesize;
  335.         long    header_std, c;
  336.         char    *workfile;
  337.  
  338.         for (;!feof(fdi);)
  339.          {
  340.           if ( fread((char *)head, 1, 512, fdi) == EOF) break;
  341.  
  342.                 decode_header(head, &hstat, &header_std);
  343.                 workfile = head->header.name;
  344.                 size = filesize = hstat.st_size;
  345.  
  346.                 if(    workfile[strlen(workfile)-1] == '/'
  347.                     || workfile[strlen(workfile)-1] == ':' )
  348.                  {
  349.                   ULONG lock;
  350.  
  351.                   printf("Creating: %s ...", workfile);
  352.  
  353.                   workfile[strlen(workfile)-1] = (char) 0;
  354.  
  355.                   lock = CreateDir(workfile);
  356.                   if(lock)
  357.                    {
  358.                     printf(" OK\n");
  359.                     UnLock(lock);
  360.                    }else printf(" Failed\n");
  361.  
  362.                   fseek(fdi, filesize, 1);
  363.  
  364.                   continue;
  365.                  }
  366.  
  367.                 printf("Extracting: %s\n", workfile);
  368.  
  369.                 fdo = fopen(workfile, "w");
  370.  
  371.                 while ((c = getc(fdi)) != EOF)  {
  372.  
  373.                         /*
  374.                          *      Convert Linefeed to MSDOS
  375.                          *      Carriage Return, Linefeed pair
  376.                          *
  377.                          */
  378.  
  379.                         if (c == 0x0A)
  380.                                 putc('\n', fdo);
  381.                         else
  382.                                 putc(c, fdo);
  383.  
  384.                         if (--size == 0L)  {
  385.  
  386.                            /*
  387.                             *   Get to next 512 byte boundary
  388.                             */
  389.  
  390.                            fseek(fdi, 512L - (filesize % 512L), 1);
  391.                            break;
  392.                         }
  393.                 }
  394.  
  395.                 fclose(fdo);
  396.         }
  397.  
  398.  fclose(fdi);
  399. }
  400.  
  401.  
  402. /*
  403.  *      Break down the header info into stat info
  404.  *
  405.  *      Set "*stdp" to != 0 or == 0 depending whether
  406.  *      header record is "Unix Standard" or "old" tar format.
  407.  *
  408.  */
  409.  
  410. void decode_header(union record *header, struct stat *st, long *stdp)
  411. {
  412.         st->st_mode  = (long)from_oct( 8, header->header.mode);
  413.         st->st_mtime = from_oct(12, header->header.mtime);
  414.         st->st_size  = from_oct(12, header->header.size);
  415.  
  416.         if (0 == strcmp(header->header.magic, TMAGIC)) {
  417.  
  418.                 /* Unix Standard tar archive */
  419.  
  420.                 *stdp = 1;
  421.                 st->st_dev = 0;
  422.  
  423.         } else {
  424.  
  425.                 /* Old fashioned tar archive */
  426.  
  427.                 *stdp = 0;
  428.                 st->st_uid = (long)from_oct(8, header->header.uid);
  429.                 st->st_gid = (long)from_oct(8, header->header.gid);
  430.                 st->st_dev = 0;
  431.         }
  432. }
  433.  
  434.  
  435. /*
  436.  *      Decode the mode string from a stat entry into a 9-char string
  437.  */
  438.  
  439. void demode(unsigned mode, char *string)
  440. {
  441.         register unsigned mask;
  442.         register char     *rwx = "rwxrwxrwx";
  443.  
  444.         for (mask = 0400; mask != 0; mask >>= 1) {
  445.                 if (mode & mask)
  446.                         *string++ = *rwx++;
  447.                 else {
  448.                         *string++ = '-';
  449.                         rwx++;
  450.                 }
  451.         }
  452.  
  453.         if (mode & S_ISUID)
  454.                 if (string[-7] == 'x')
  455.                         string[-7] = 's';
  456.                 else
  457.                         string[-7] = 'S';
  458.  
  459.         if (mode & S_ISGID)
  460.                 if (string[-4] == 'x')
  461.                         string[-4] = 's';
  462.                 else
  463.                         string[-4] = 'S';
  464.  
  465.         if (mode & S_ISVTX)
  466.                 if (string[-1] == 'x')
  467.                         string[-1] = 't';
  468.                 else
  469.                         string[-1] = 'T';
  470.  
  471.         *string = '\0';
  472. }
  473.  
  474.  
  475. /*
  476.  *      Quick and dirty octal conversion.
  477.  *
  478.  *      Result is -1 if the field is invalid (all blank, or nonoctal).
  479.  */
  480.  
  481. long from_oct(long digs, char *where)
  482. {
  483.         register long   value;
  484.  
  485.         while (isspace(*where)) {               /* Skip spaces */
  486.                 where++;
  487.                 if (--digs <= 0)
  488.                         return -1;              /* All blank field */
  489.         }
  490.  
  491.         value = 0;
  492.         while (digs > 0 && isodigit(*where)) {  /* Scan til nonoctal */
  493.                 value = (value << 3) | (*where++ - '0');
  494.                 --digs;
  495.         }
  496.  
  497.         if (digs > 0 && *where && !isspace(*where))
  498.                 return -1;                      /* Ended on non-space/nul */
  499.  
  500.         return value;
  501. }
  502.