home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / PPCDeTarWOS.lha / PPCDeTar.c < prev    next >
C/C++ Source or Header  |  1998-02-18  |  11KB  |  521 lines

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