Home | History | Annotate | Download | only in pending
      1 /* tar.c - create/extract archives
      2  *
      3  * Copyright 2014 Ashwini Kumar <ak.ashwini81 (at) gmail.com>
      4  *
      5  * USTAR interchange format is of interest in
      6  * See http://http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
      7  * For writing to external program
      8  * http://www.gnu.org/software/tar/manual/html_node/Writing-to-an-External-Program.html
      9 
     10 USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc]", TOYFLAG_USR|TOYFLAG_BIN))
     11 
     12 config TAR
     13   bool "tar"
     14   default n
     15   help
     16     usage: tar -[cxtzhmvO] [-X FILE] [-T FILE] [-f TARFILE] [-C DIR]
     17 
     18     Create, extract, or list files from a tar file
     19 
     20     Operation:
     21     c Create
     22     f Name of TARFILE ('-' for stdin/out)
     23     h Follow symlinks
     24     m Don't restore mtime
     25     t List
     26     v Verbose
     27     x Extract
     28     z (De)compress using gzip
     29     C Change to DIR before operation
     30     O Extract to stdout
     31     exclude=FILE File to exclude
     32     X File with names to exclude
     33     T File with names to include
     34 */
     35 
     36 #define FOR_tar
     37 #include "toys.h"
     38 
     39 GLOBALS(
     40   char *fname;
     41   char *dir;
     42   struct arg_list *inc_file;
     43   struct arg_list *exc_file;
     44   char *tocmd;
     45   struct arg_list *exc;
     46 
     47   struct arg_list *inc, *pass;
     48   void *inodes, *handle;
     49 )
     50 
     51 struct tar_hdr {
     52   char name[100], mode[8], uid[8], gid[8],size[12], mtime[12], chksum[8],
     53        type, link[100], magic[8], uname[32], gname[32], major[8], minor[8],
     54        prefix[155], padd[12];
     55 };
     56 
     57 struct file_header {
     58   char *name, *link_target, *uname, *gname;
     59   off_t size;
     60   uid_t uid;
     61   gid_t gid;
     62   mode_t mode;
     63   time_t mtime;
     64   dev_t device;
     65 };
     66 
     67 struct archive_handler {
     68   int src_fd;
     69   struct file_header file_hdr;
     70   off_t offset;
     71   void (*extract_handler)(struct archive_handler*);
     72 };
     73 
     74 struct inode_list {
     75   struct inode_list *next;
     76   char *arg;
     77   ino_t ino;
     78   dev_t dev;
     79 };
     80 
     81 static void copy_in_out(int src, int dst, off_t size)
     82 {
     83   int i, rd, rem = size%512, cnt;
     84 
     85   cnt = size/512 + (rem?1:0);
     86 
     87   for (i = 0; i < cnt; i++) {
     88     rd = (i == cnt-1 && rem) ? rem : 512;
     89     xreadall(src, toybuf, rd);
     90     writeall(dst, toybuf, rd);
     91   }
     92 }
     93 
     94 //convert to octal
     95 static void itoo(char *str, int len, off_t val)
     96 {
     97   char *t, tmp[sizeof(off_t)*3+1];
     98   int cnt  = sprintf(tmp, "%0*llo", len, (unsigned long long)val);
     99 
    100   t = tmp + cnt - len;
    101   if (*t == '0') t++;
    102   memcpy(str, t, len);
    103 }
    104 
    105 static struct inode_list *seen_inode(void **list, struct stat *st, char *name)
    106 {
    107   if (!st) llist_traverse(*list, llist_free_arg);
    108   else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
    109     struct inode_list *new;
    110 
    111     for (new = *list; new; new = new->next)
    112       if(new->ino == st->st_ino && new->dev == st->st_dev)
    113         return new;
    114 
    115     new = xzalloc(sizeof(*new));
    116     new->ino = st->st_ino;
    117     new->dev = st->st_dev;
    118     new->arg = xstrdup(name);
    119     new->next = *list;
    120     *list = new;
    121   }
    122   return 0;
    123 }
    124 
    125 static void write_longname(struct archive_handler *tar, char *name, char type)
    126 {
    127   struct tar_hdr tmp;
    128   unsigned int sum = 0;
    129   int i, sz = strlen(name) +1;
    130   char buf[512] = {0,};
    131 
    132   memset(&tmp, 0, sizeof(tmp));
    133   strcpy(tmp.name, "././@LongLink");
    134   sprintf(tmp.mode, "%0*d", (int)sizeof(tmp.mode)-1, 0);
    135   sprintf(tmp.uid, "%0*d", (int)sizeof(tmp.uid)-1, 0);
    136   sprintf(tmp.gid, "%0*d", (int)sizeof(tmp.gid)-1, 0);
    137   sprintf(tmp.size, "%0*d", (int)sizeof(tmp.size)-1, 0);
    138   sprintf(tmp.mtime, "%0*d", (int)sizeof(tmp.mtime)-1, 0);
    139   itoo(tmp.size, sizeof(tmp.size), sz);
    140   tmp.type = type;
    141   memset(tmp.chksum, ' ', 8);
    142   strcpy(tmp.magic, "ustar  ");
    143   for (i= 0; i < 512; i++) sum += (unsigned int)((char*)&tmp)[i];
    144   itoo(tmp.chksum, sizeof(tmp.chksum)-1, sum);
    145 
    146   writeall(tar->src_fd, (void*) &tmp, sizeof(tmp));
    147   //write name to archive
    148   writeall(tar->src_fd, name, sz);
    149   if (sz%512) writeall(tar->src_fd, buf, (512-(sz%512)));
    150 }
    151 
    152 static int filter(struct arg_list *lst, char *name)
    153 {
    154   struct arg_list *cur;
    155 
    156   for (cur = lst; cur; cur = cur->next)
    157     if (!fnmatch(cur->arg, name, 1<<3)) return 1;
    158   return 0;
    159 }
    160 
    161 static void add_file(struct archive_handler *tar, char **nam, struct stat *st)
    162 {
    163   struct tar_hdr hdr;
    164   struct passwd *pw;
    165   struct group *gr;
    166   struct inode_list *node;
    167   int i, fd =-1;
    168   char *c, *p, *name = *nam, *lnk, *hname, buf[512] = {0,};
    169   unsigned int sum = 0;
    170   static int warn = 1;
    171 
    172   for (p = name; *p; p++)
    173     if ((p == name || p[-1] == '/') && *p != '/'
    174         && filter(TT.exc, p)) return;
    175 
    176   if (S_ISDIR(st->st_mode) && name[strlen(name)-1] != '/') {
    177     lnk = xmprintf("%s/",name);
    178     free(name);
    179     *nam = name = lnk;
    180   }
    181   hname = name;
    182   //remove leading '/' or relative path '../' component
    183   if (*hname == '/') hname++;
    184   if (!*hname) return;
    185   while ((c = strstr(hname, "../"))) hname = c + 3;
    186   if (warn && hname != name) {
    187     printf("removing leading '%.*s' "
    188         "from member names\n", (int)(hname-name), name);
    189     warn = 0;
    190   }
    191 
    192   memset(&hdr, 0, sizeof(hdr));
    193   strncpy(hdr.name, hname, sizeof(hdr.name));
    194   itoo(hdr.mode, sizeof(hdr.mode), st->st_mode &07777);
    195   itoo(hdr.uid, sizeof(hdr.uid), st->st_uid);
    196   itoo(hdr.gid, sizeof(hdr.gid), st->st_gid);
    197   itoo(hdr.size, sizeof(hdr.size), 0); //set size later
    198   itoo(hdr.mtime, sizeof(hdr.mtime), st->st_mtime);
    199   for (i=0; i<sizeof(hdr.chksum); i++) hdr.chksum[i] = ' ';
    200 
    201   if ((node = seen_inode(&TT.inodes, st, hname))) {
    202     //this is a hard link
    203     hdr.type = '1';
    204     if (strlen(node->arg) > sizeof(hdr.link))
    205       write_longname(tar, hname, 'K'); //write longname LINK
    206     xstrncpy(hdr.link, node->arg, sizeof(hdr.link));
    207   } else if (S_ISREG(st->st_mode)) {
    208     hdr.type = '0';
    209     if (st->st_size <= (off_t)0777777777777LL)
    210       itoo(hdr.size, sizeof(hdr.size), st->st_size);
    211     else {
    212       error_msg("can't store file '%s' of size '%lld'\n",
    213                 hname, (unsigned long long)st->st_size);
    214       return;
    215     }
    216   } else if (S_ISLNK(st->st_mode)) {
    217     hdr.type = '2'; //'K' long link
    218     if (!(lnk = xreadlink(name))) {
    219       perror_msg("readlink");
    220       return;
    221     }
    222     if (strlen(lnk) > sizeof(hdr.link))
    223       write_longname(tar, hname, 'K'); //write longname LINK
    224     xstrncpy(hdr.link, lnk, sizeof(hdr.link));
    225     free(lnk);
    226   }
    227   else if (S_ISDIR(st->st_mode)) hdr.type = '5';
    228   else if (S_ISFIFO(st->st_mode)) hdr.type = '6';
    229   else if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
    230     hdr.type = (S_ISCHR(st->st_mode))?'3':'4';
    231     itoo(hdr.major, sizeof(hdr.major), major(st->st_rdev));
    232     itoo(hdr.minor, sizeof(hdr.minor), minor(st->st_rdev));
    233   } else {
    234     error_msg("unknown file type '%o'", st->st_mode & S_IFMT);
    235     return;
    236   }
    237   if (strlen(hname) > sizeof(hdr.name))
    238           write_longname(tar, hname, 'L'); //write longname NAME
    239   strcpy(hdr.magic, "ustar  ");
    240   if ((pw = getpwuid(st->st_uid)))
    241     snprintf(hdr.uname, sizeof(hdr.uname), "%s", pw->pw_name);
    242   else snprintf(hdr.uname, sizeof(hdr.uname), "%d", st->st_uid);
    243 
    244   if ((gr = getgrgid(st->st_gid)))
    245     snprintf(hdr.gname, sizeof(hdr.gname), "%s", gr->gr_name);
    246   else snprintf(hdr.gname, sizeof(hdr.gname), "%d", st->st_gid);
    247 
    248   //calculate chksum.
    249   for (i= 0; i < 512; i++) sum += (unsigned int)((char*)&hdr)[i];
    250   itoo(hdr.chksum, sizeof(hdr.chksum)-1, sum);
    251   if (toys.optflags & FLAG_v) printf("%s\n",hname);
    252   writeall(tar->src_fd, (void*)&hdr, 512);
    253 
    254   //write actual data to archive
    255   if (hdr.type != '0') return; //nothing to write
    256   if ((fd = open(name, O_RDONLY)) < 0) {
    257     perror_msg("can't open '%s'", name);
    258     return;
    259   }
    260   copy_in_out(fd, tar->src_fd, st->st_size);
    261   if (st->st_size%512) writeall(tar->src_fd, buf, (512-(st->st_size%512)));
    262   close(fd);
    263 }
    264 
    265 static int add_to_tar(struct dirtree *node)
    266 {
    267   struct stat st;
    268   char *path;
    269   struct archive_handler *hdl = (struct archive_handler*)TT.handle;
    270 
    271   if (!fstat(hdl->src_fd, &st) && st.st_dev == node->st.st_dev
    272       && st.st_ino == node->st.st_ino) {
    273     error_msg("'%s' file is the archive; not dumped", TT.fname);
    274     return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
    275   }
    276 
    277   if (node->parent && !dirtree_notdotdot(node)) return 0;
    278   path = dirtree_path(node, 0);
    279   add_file(hdl, &path, &(node->st)); //path may be modified
    280   free(path);
    281   if (toys.optflags & FLAG_no_recursion) return 0;
    282   return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
    283 }
    284 
    285 static void compress_stream(struct archive_handler *tar_hdl)
    286 {
    287   int pipefd[2];
    288   pid_t cpid;
    289 
    290   xpipe(pipefd);
    291 
    292   signal(SIGPIPE, SIG_IGN);
    293   cpid = fork();
    294   if (cpid == -1) perror_exit("fork");
    295 
    296   if (!cpid) {    /* Child reads from pipe */
    297     char *argv[] = {"gzip", "-f", NULL};
    298     xclose(pipefd[1]); /* Close unused write*/
    299     dup2(pipefd[0], 0);
    300     dup2(tar_hdl->src_fd, 1); //write to tar fd
    301     xexec(argv);
    302   } else {
    303     xclose(pipefd[0]);          /* Close unused read end */
    304     dup2(pipefd[1], tar_hdl->src_fd); //write to pipe
    305   }
    306 }
    307 
    308 static void extract_to_stdout(struct archive_handler *tar)
    309 {
    310   struct file_header *file_hdr = &tar->file_hdr;
    311 
    312   copy_in_out(tar->src_fd, 0, file_hdr->size);
    313   tar->offset += file_hdr->size;
    314 }
    315 
    316 static void extract_to_command(struct archive_handler *tar)
    317 {
    318   int pipefd[2], status = 0;
    319   pid_t cpid;
    320   struct file_header *file_hdr = &tar->file_hdr;
    321 
    322   if (pipe(pipefd) == -1) error_exit("pipe");
    323   if (!S_ISREG(file_hdr->mode)) return; //only regular files are supported.
    324 
    325   cpid = fork();
    326   if (cpid == -1) perror_exit("fork");
    327 
    328   if (!cpid) {    // Child reads from pipe
    329     char buf[64], *argv[4] = {"sh", "-c", TT.tocmd, NULL};
    330 
    331     setenv("TAR_FILETYPE", "f", 1);
    332     sprintf(buf, "%0o", file_hdr->mode);
    333     setenv("TAR_MODE", buf, 1);
    334     sprintf(buf, "%ld", (long)file_hdr->size);
    335     setenv("TAR_SIZE", buf, 1);
    336     setenv("TAR_FILENAME", file_hdr->name, 1);
    337     setenv("TAR_UNAME", file_hdr->uname, 1);
    338     setenv("TAR_GNAME", file_hdr->gname, 1);
    339     sprintf(buf, "%0o", (int)file_hdr->mtime);
    340     setenv("TAR_MTIME", buf, 1);
    341     sprintf(buf, "%0o", file_hdr->uid);
    342     setenv("TAR_UID", buf, 1);
    343     sprintf(buf, "%0o", file_hdr->gid);
    344     setenv("TAR_GID", buf, 1);
    345 
    346     xclose(pipefd[1]); // Close unused write
    347     dup2(pipefd[0], 0);
    348     signal(SIGPIPE, SIG_DFL);
    349     xexec(argv);
    350   } else {
    351     xclose(pipefd[0]);  // Close unused read end
    352     copy_in_out(tar->src_fd, pipefd[1], file_hdr->size);
    353     tar->offset += file_hdr->size;
    354     xclose(pipefd[1]);
    355     waitpid(cpid, &status, 0);
    356     if (WIFSIGNALED(status))
    357       xprintf("tar : %d: child returned %d\n", cpid, WTERMSIG(status));
    358   }
    359 }
    360 
    361 static void extract_to_disk(struct archive_handler *tar)
    362 {
    363   int flags, dst_fd = -1;
    364   char *s;
    365   struct stat ex;
    366   struct file_header *file_hdr = &tar->file_hdr;
    367 
    368   if (file_hdr->name[strlen(file_hdr->name)-1] == '/')
    369     file_hdr->name[strlen(file_hdr->name)-1] = 0;
    370   //Regular file with preceding path
    371   if ((s = strrchr(file_hdr->name, '/'))) {
    372     if (mkpathat(AT_FDCWD, file_hdr->name, 00, 2) && errno !=EEXIST) {
    373       error_msg(":%s: not created", file_hdr->name);
    374       return;
    375     }
    376   }
    377 
    378   //remove old file, if exists
    379   if (!(toys.optflags & FLAG_k) && !S_ISDIR(file_hdr->mode)
    380       && !lstat( file_hdr->name, &ex)) {
    381     if (unlink(file_hdr->name)) {
    382       perror_msg("can't remove: %s",file_hdr->name);
    383     }
    384   }
    385 
    386   //hard link
    387   if (S_ISREG(file_hdr->mode) && file_hdr->link_target) {
    388     if (link(file_hdr->link_target, file_hdr->name))
    389       perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
    390     goto COPY;
    391   }
    392 
    393   switch (file_hdr->mode & S_IFMT) {
    394     case S_IFREG:
    395       flags = O_WRONLY|O_CREAT|O_EXCL;
    396       if (toys.optflags & FLAG_overwrite) flags = O_WRONLY|O_CREAT|O_TRUNC;
    397       dst_fd = open(file_hdr->name, flags, file_hdr->mode & 07777);
    398       if (dst_fd == -1) perror_msg("%s: can't open", file_hdr->name);
    399       break;
    400     case S_IFDIR:
    401       if ((mkdir(file_hdr->name, file_hdr->mode) == -1) && errno != EEXIST)
    402         perror_msg("%s: can't create", file_hdr->name);
    403       break;
    404     case S_IFLNK:
    405       if (symlink(file_hdr->link_target, file_hdr->name))
    406         perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
    407       break;
    408     case S_IFBLK:
    409     case S_IFCHR:
    410     case S_IFIFO:
    411       if (mknod(file_hdr->name, file_hdr->mode, file_hdr->device))
    412         perror_msg("can't create '%s'", file_hdr->name);
    413       break;
    414     default:
    415       printf("type not yet supported\n");
    416       break;
    417   }
    418 
    419   //copy file....
    420 COPY:
    421   copy_in_out(tar->src_fd, dst_fd, file_hdr->size);
    422   tar->offset += file_hdr->size;
    423   close(dst_fd);
    424 
    425   if (S_ISLNK(file_hdr->mode)) return;
    426   if (!(toys.optflags & FLAG_o)) {
    427     //set ownership..., --no-same-owner, --numeric-owner
    428     uid_t u = file_hdr->uid;
    429     gid_t g = file_hdr->gid;
    430 
    431     if (!(toys.optflags & FLAG_numeric_owner)) {
    432       struct group *gr = getgrnam(file_hdr->gname);
    433       struct passwd *pw = getpwnam(file_hdr->uname);
    434       if (pw) u = pw->pw_uid;
    435       if (gr) g = gr->gr_gid;
    436     }
    437     if (chown(file_hdr->name, u, g))
    438       perror_msg("chown %d:%d '%s'", u, g, file_hdr->name);;
    439   }
    440 
    441   if (toys.optflags & FLAG_p) // || !(toys.optflags & FLAG_no_same_permissions))
    442     chmod(file_hdr->name, file_hdr->mode);
    443 
    444   //apply mtime
    445   if (!(toys.optflags & FLAG_m)) {
    446     struct timeval times[2] = {{file_hdr->mtime, 0},{file_hdr->mtime, 0}};
    447     utimes(file_hdr->name, times);
    448   }
    449 }
    450 
    451 static void add_to_list(struct arg_list **llist, char *name)
    452 {
    453   struct arg_list **list = llist;
    454 
    455   while (*list) list=&((*list)->next);
    456   *list = xzalloc(sizeof(struct arg_list));
    457   (*list)->arg = name;
    458   if ((name[strlen(name)-1] == '/') && strlen(name) != 1)
    459     name[strlen(name)-1] = '\0';
    460 }
    461 
    462 static void add_from_file(struct arg_list **llist, struct arg_list *flist)
    463 {
    464   char *line = NULL;
    465 
    466   while (flist) {
    467     int fd = 0;
    468 
    469     if (strcmp((char *)flist->arg, "-"))
    470       fd = xopen((char *)flist->arg, O_RDONLY);
    471 
    472     while ((line = get_line(fd))) {
    473       add_to_list(llist, line);
    474     }
    475     if (fd) close(fd);
    476     flist = flist->next;
    477   }
    478 }
    479 
    480 static struct archive_handler *init_handler()
    481 {
    482   struct archive_handler *tar_hdl = xzalloc(sizeof(struct archive_handler));
    483   tar_hdl->extract_handler = extract_to_disk;
    484   return tar_hdl;
    485 }
    486 
    487 //convert octal to int
    488 static int otoi(char *str, int len)
    489 {
    490   long val;
    491   char *endp, inp[len+1]; //1 for NUL termination
    492 
    493   memcpy(inp, str, len);
    494   inp[len] = '\0'; //nul-termination made sure
    495   val = strtol(inp, &endp, 8);
    496   if (*endp && *endp != ' ') error_exit("invalid param");
    497   return (int)val;
    498 }
    499 
    500 static void extract_stream(struct archive_handler *tar_hdl)
    501 {
    502   int pipefd[2];
    503   pid_t cpid;
    504 
    505   if (pipe(pipefd) == -1) error_exit("pipe");
    506 
    507   cpid = fork();
    508   if (cpid == -1) perror_exit("fork");
    509 
    510   if (!cpid) {    /* Child reads from pipe */
    511     char *argv[] = {"gunzip", "-cf", "-", NULL};
    512     xclose(pipefd[0]); /* Close unused read*/
    513     dup2(tar_hdl->src_fd, 0);
    514     dup2(pipefd[1], 1); //write to pipe
    515     xexec(argv);
    516   } else {
    517     xclose(pipefd[1]);          /* Close unused read end */
    518     dup2(pipefd[0], tar_hdl->src_fd); //read from pipe
    519   }
    520 }
    521 
    522 static char *process_extended_hdr(struct archive_handler *tar, int size)
    523 {
    524   char *value = NULL, *p, *buf = xzalloc(size+1);
    525 
    526   if (readall(tar->src_fd, buf, size) != size) error_exit("short read");
    527   buf[size] = 0;
    528   tar->offset += size;
    529   p = buf;
    530 
    531   while (size) {
    532     char *key;
    533     int len, n;
    534 
    535     // extended records are of the format: "LEN NAME=VALUE\n"
    536     sscanf(p, "%d %n", &len, &n);
    537     key = p + n;
    538     p += len;
    539     size -= len;
    540     p[-1] = 0;
    541     if (size < 0) {
    542       error_msg("corrupted extended header");
    543       break;
    544     }
    545 
    546     len = strlen("path=");
    547     if (!strncmp(key, "path=", len)) {
    548       value = key + strlen("path=");
    549       break;
    550     }
    551   }
    552   if (value) value = xstrdup(value);
    553   free(buf);
    554   return value;
    555 }
    556 
    557 static void tar_skip(struct archive_handler *tar, int sz)
    558 {
    559   int x;
    560 
    561   while ((x = lskip(tar->src_fd, sz))) {
    562     tar->offset += sz - x;
    563     sz = x;
    564   }
    565   tar->offset += sz;
    566 }
    567 
    568 static void unpack_tar(struct archive_handler *tar_hdl)
    569 {
    570   struct tar_hdr tar;
    571   struct file_header *file_hdr;
    572   int i, j, maj, min, sz, e = 0;
    573   unsigned int cksum;
    574   unsigned char *gzMagic;
    575   char *longname = NULL, *longlink = NULL;
    576 
    577   while (1) {
    578     cksum = 0;
    579     if (tar_hdl->offset % 512) {
    580       sz = 512 - tar_hdl->offset % 512;
    581       tar_skip(tar_hdl, sz);
    582     }
    583     i = readall(tar_hdl->src_fd, &tar, 512);
    584     tar_hdl->offset += i;
    585     if (i != 512) {
    586       if (i >= 2) goto CHECK_MAGIC; //may be a small (<512 byte)zipped file
    587       error_exit("read error");
    588     }
    589 
    590     if (!tar.name[0]) {
    591       if (e) return; //end of tar 2 empty blocks
    592       e = 1;//empty jump to next block
    593       continue;
    594     }
    595     if (strncmp(tar.magic, "ustar", 5)) {
    596       //try detecting by reading magic
    597 CHECK_MAGIC:
    598       gzMagic = (unsigned char*)&tar;
    599       if ((gzMagic[0] == 0x1f) && (gzMagic[1] == 0x8b)
    600           && !lseek(tar_hdl->src_fd, -i, SEEK_CUR)) {
    601         tar_hdl->offset -= i;
    602         extract_stream(tar_hdl);
    603         continue;
    604       }
    605       error_exit("invalid tar format");
    606     }
    607 
    608     for (j = 0; j<148; j++) cksum += (unsigned int)((char*)&tar)[j];
    609     for (j = 156; j<500; j++) cksum += (unsigned int)((char*)&tar)[j];
    610     //cksum field itself treated as ' '
    611     for ( j= 0; j<8; j++) cksum += (unsigned int)' ';
    612 
    613     if (cksum != otoi(tar.chksum, sizeof(tar.chksum))) error_exit("wrong cksum");
    614 
    615     file_hdr = &tar_hdl->file_hdr;
    616     memset(file_hdr, 0, sizeof(struct file_header));
    617     file_hdr->mode = otoi(tar.mode, sizeof(tar.mode));
    618     file_hdr->uid = otoi(tar.uid, sizeof(tar.uid));
    619     file_hdr->gid = otoi(tar.gid, sizeof(tar.gid));
    620     file_hdr->size = otoi(tar.size, sizeof(tar.size));
    621     file_hdr->mtime = otoi(tar.mtime, sizeof(tar.mtime));
    622     file_hdr->uname = xstrdup(tar.uname);
    623     file_hdr->gname = xstrdup(tar.gname);
    624     maj = otoi(tar.major, sizeof(tar.major));
    625     min = otoi(tar.minor, sizeof(tar.minor));
    626     file_hdr->device = makedev(maj, min);
    627 
    628     if (tar.type <= '7') {
    629       if (tar.link[0]) {
    630         sz = sizeof(tar.link);
    631         file_hdr->link_target = xmalloc(sz + 1);
    632         memcpy(file_hdr->link_target, tar.link, sz);
    633         file_hdr->link_target[sz] = '\0';
    634       }
    635 
    636       file_hdr->name = xzalloc(256);// pathname supported size
    637       if (tar.prefix[0]) {
    638         memcpy(file_hdr->name, tar.prefix, sizeof(tar.prefix));
    639         sz = strlen(file_hdr->name);
    640         if (file_hdr->name[sz-1] != '/') file_hdr->name[sz] = '/';
    641       }
    642       sz = strlen(file_hdr->name);
    643       memcpy(file_hdr->name + sz, tar.name, sizeof(tar.name));
    644       if (file_hdr->name[255]) error_exit("filename too long");
    645     }
    646 
    647     switch (tar.type) {
    648       //    case '\0':
    649       case '0':
    650       case '7':
    651       case '1': //Hard Link
    652         file_hdr->mode |= S_IFREG;
    653         break;
    654       case '2':
    655         file_hdr->mode |= S_IFLNK;
    656         break;
    657       case '3':
    658         file_hdr->mode |= S_IFCHR;
    659         break;
    660       case '4':
    661         file_hdr->mode |= S_IFBLK;
    662         break;
    663       case '5':
    664         file_hdr->mode |= S_IFDIR;
    665         break;
    666       case '6':
    667         file_hdr->mode |= S_IFIFO;
    668         break;
    669       case 'K':
    670         longlink = xzalloc(file_hdr->size +1);
    671         xread(tar_hdl->src_fd, longlink, file_hdr->size);
    672         tar_hdl->offset += file_hdr->size;
    673         continue;
    674       case 'L':
    675         free(longname);
    676         longname = xzalloc(file_hdr->size +1);
    677         xread(tar_hdl->src_fd, longname, file_hdr->size);
    678         tar_hdl->offset += file_hdr->size;
    679         continue;
    680       case 'D':
    681       case 'M':
    682       case 'N':
    683       case 'S':
    684       case 'V':
    685       case 'g':  // pax global header
    686         tar_skip(tar_hdl, file_hdr->size);
    687         continue;
    688       case 'x':  // pax extended header
    689         free(longname);
    690         longname = process_extended_hdr(tar_hdl, file_hdr->size);
    691         continue;
    692       default: break;
    693     }
    694 
    695     if (longname) {
    696       free(file_hdr->name);
    697       file_hdr->name = longname;
    698       longname = NULL;
    699     }
    700     if (longlink) {
    701       free(file_hdr->link_target);
    702       file_hdr->link_target = longlink;
    703       longlink = NULL;
    704     }
    705 
    706     if ((file_hdr->mode & S_IFREG) &&
    707         file_hdr->name[strlen(file_hdr->name)-1] == '/') {
    708       file_hdr->name[strlen(file_hdr->name)-1] = '\0';
    709       file_hdr->mode &= ~S_IFREG;
    710       file_hdr->mode |= S_IFDIR;
    711     }
    712 
    713     if ((file_hdr->link_target && *(file_hdr->link_target))
    714         || S_ISLNK(file_hdr->mode) || S_ISDIR(file_hdr->mode))
    715       file_hdr->size = 0;
    716 
    717     if (filter(TT.exc, file_hdr->name) ||
    718         (TT.inc && !filter(TT.inc, file_hdr->name))) goto SKIP;
    719     add_to_list(&TT.pass, xstrdup(file_hdr->name));
    720 
    721     if (toys.optflags & FLAG_t) {
    722       if (toys.optflags & FLAG_v) {
    723         char perm[11];
    724         struct tm *lc = localtime((const time_t*)&(file_hdr->mtime));
    725 
    726         mode_to_string(file_hdr->mode, perm);
    727         printf("%s %s/%s %9ld %d-%02d-%02d %02d:%02d:%02d ",perm,file_hdr->uname,
    728             file_hdr->gname, (long)file_hdr->size, 1900+lc->tm_year,
    729             1+lc->tm_mon, lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec);
    730       }
    731       printf("%s",file_hdr->name);
    732       if (file_hdr->link_target) printf(" -> %s",file_hdr->link_target);
    733       xputc('\n');
    734 SKIP:
    735       tar_skip(tar_hdl, file_hdr->size);
    736     } else {
    737       if (toys.optflags & FLAG_v) printf("%s\n",file_hdr->name);
    738       tar_hdl->extract_handler(tar_hdl);
    739     }
    740     free(file_hdr->name);
    741     free(file_hdr->link_target);
    742     free(file_hdr->uname);
    743     free(file_hdr->gname);
    744   }
    745 }
    746 
    747 void tar_main(void)
    748 {
    749   struct archive_handler *tar_hdl;
    750   int fd = 0;
    751   struct arg_list *tmp;
    752   char **args = toys.optargs;
    753 
    754   if (!geteuid()) toys.optflags |= FLAG_p;
    755 
    756   for (tmp = TT.exc; tmp; tmp = tmp->next)
    757     tmp->arg = xstrdup(tmp->arg); //freeing at the end fails otherwise
    758 
    759   while(*args) add_to_list(&TT.inc, xstrdup(*args++));
    760   if (toys.optflags & FLAG_X) add_from_file(&TT.exc, TT.exc_file);
    761   if (toys.optflags & FLAG_T) add_from_file(&TT.inc, TT.inc_file);
    762 
    763   if (toys.optflags & FLAG_c) {
    764     if (!TT.inc) error_exit("empty archive");
    765     fd = 1;
    766   }
    767   if ((toys.optflags & FLAG_f) && strcmp(TT.fname, "-"))
    768     fd = xcreate(TT.fname, fd*(O_WRONLY|O_CREAT|O_TRUNC), 0666);
    769   if (toys.optflags & FLAG_C) xchdir(TT.dir);
    770 
    771   tar_hdl = init_handler();
    772   tar_hdl->src_fd = fd;
    773 
    774   if ((toys.optflags & FLAG_x) || (toys.optflags & FLAG_t)) {
    775     if (toys.optflags & FLAG_O) tar_hdl->extract_handler = extract_to_stdout;
    776     if (toys.optflags & FLAG_to_command) {
    777       signal(SIGPIPE, SIG_IGN); //will be using pipe between child & parent
    778       tar_hdl->extract_handler = extract_to_command;
    779     }
    780     if (toys.optflags & FLAG_z) extract_stream(tar_hdl);
    781     unpack_tar(tar_hdl);
    782     for (tmp = TT.inc; tmp; tmp = tmp->next)
    783       if (!filter(TT.exc, tmp->arg) && !filter(TT.pass, tmp->arg))
    784         error_msg("'%s' not in archive", tmp->arg);
    785   } else if (toys.optflags & FLAG_c) {
    786     //create the tar here.
    787     if (toys.optflags & FLAG_z) compress_stream(tar_hdl);
    788     for (tmp = TT.inc; tmp; tmp = tmp->next) {
    789       TT.handle = tar_hdl;
    790       //recurse thru dir and add files to archive
    791       dirtree_handle_callback(dirtree_start(tmp->arg, toys.optflags & FLAG_h),
    792         add_to_tar);
    793     }
    794     memset(toybuf, 0, 1024);
    795     writeall(tar_hdl->src_fd, toybuf, 1024);
    796     seen_inode(&TT.inodes, 0, 0);
    797   }
    798 
    799   if (CFG_TOYBOX_FREE) {
    800     close(tar_hdl->src_fd);
    801     free(tar_hdl);
    802     llist_traverse(TT.exc, llist_free_arg);
    803     llist_traverse(TT.inc, llist_free_arg);
    804     llist_traverse(TT.pass, llist_free_arg);
    805   }
    806 }
    807