OSDN Git Service

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