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