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 
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 
copy_in_out(int src,int dst,off_t size)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
itoo(char * str,int len,off_t val)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 
seen_inode(void ** list,struct stat * st,char * name)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 
write_longname(struct archive_handler * tar,char * name,char type)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 
filter(struct arg_list * lst,char * name)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 
add_file(struct archive_handler * tar,char ** nam,struct stat * st)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     fprintf(stderr, "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), dev_major(st->st_rdev));
232     itoo(hdr.minor, sizeof(hdr.minor), dev_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 
add_to_tar(struct dirtree * node)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 (!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 
compress_stream(struct archive_handler * tar_hdl)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 
extract_to_stdout(struct archive_handler * tar)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 
extract_to_command(struct archive_handler * tar)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 
extract_to_disk(struct archive_handler * tar)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   flags = strlen(file_hdr->name);
369   if (flags>2) {
370     if (strstr(file_hdr->name, "/../") || !strcmp(file_hdr->name, "../") ||
371         !strcmp(file_hdr->name+flags-3, "/.."))
372     {
373       error_msg("drop %s", file_hdr->name);
374     }
375   }
376 
377   if (file_hdr->name[flags-1] == '/') file_hdr->name[flags-1] = 0;
378   //Regular file with preceding path
379   if ((s = strrchr(file_hdr->name, '/'))) {
380     if (mkpathat(AT_FDCWD, file_hdr->name, 00, 2) && errno !=EEXIST) {
381       error_msg(":%s: not created", file_hdr->name);
382       return;
383     }
384   }
385 
386   //remove old file, if exists
387   if (!(toys.optflags & FLAG_k) && !S_ISDIR(file_hdr->mode)
388       && !lstat( file_hdr->name, &ex)) {
389     if (unlink(file_hdr->name)) {
390       perror_msg("can't remove: %s",file_hdr->name);
391     }
392   }
393 
394   //hard link
395   if (S_ISREG(file_hdr->mode) && file_hdr->link_target) {
396     if (link(file_hdr->link_target, file_hdr->name))
397       perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
398     goto COPY;
399   }
400 
401   switch (file_hdr->mode & S_IFMT) {
402     case S_IFREG:
403       flags = O_WRONLY|O_CREAT|O_EXCL;
404       if (toys.optflags & FLAG_overwrite) flags = O_WRONLY|O_CREAT|O_TRUNC;
405       dst_fd = open(file_hdr->name, flags, file_hdr->mode & 07777);
406       if (dst_fd == -1) perror_msg("%s: can't open", file_hdr->name);
407       break;
408     case S_IFDIR:
409       if ((mkdir(file_hdr->name, file_hdr->mode) == -1) && errno != EEXIST)
410         perror_msg("%s: can't create", file_hdr->name);
411       break;
412     case S_IFLNK:
413       if (symlink(file_hdr->link_target, file_hdr->name))
414         perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
415       break;
416     case S_IFBLK:
417     case S_IFCHR:
418     case S_IFIFO:
419       if (mknod(file_hdr->name, file_hdr->mode, file_hdr->device))
420         perror_msg("can't create '%s'", file_hdr->name);
421       break;
422     default:
423       printf("type not yet supported\n");
424       break;
425   }
426 
427   //copy file....
428 COPY:
429   copy_in_out(tar->src_fd, dst_fd, file_hdr->size);
430   tar->offset += file_hdr->size;
431   close(dst_fd);
432 
433   if (S_ISLNK(file_hdr->mode)) return;
434   if (!(toys.optflags & FLAG_o)) {
435     //set ownership..., --no-same-owner, --numeric-owner
436     uid_t u = file_hdr->uid;
437     gid_t g = file_hdr->gid;
438 
439     if (!(toys.optflags & FLAG_numeric_owner)) {
440       struct group *gr = getgrnam(file_hdr->gname);
441       struct passwd *pw = getpwnam(file_hdr->uname);
442       if (pw) u = pw->pw_uid;
443       if (gr) g = gr->gr_gid;
444     }
445     if (chown(file_hdr->name, u, g))
446       perror_msg("chown %d:%d '%s'", u, g, file_hdr->name);;
447   }
448 
449   if (toys.optflags & FLAG_p) // || !(toys.optflags & FLAG_no_same_permissions))
450     chmod(file_hdr->name, file_hdr->mode);
451 
452   //apply mtime
453   if (!(toys.optflags & FLAG_m)) {
454     struct timeval times[2] = {{file_hdr->mtime, 0},{file_hdr->mtime, 0}};
455     utimes(file_hdr->name, times);
456   }
457 }
458 
add_to_list(struct arg_list ** llist,char * name)459 static void add_to_list(struct arg_list **llist, char *name)
460 {
461   struct arg_list **list = llist;
462 
463   while (*list) list=&((*list)->next);
464   *list = xzalloc(sizeof(struct arg_list));
465   (*list)->arg = name;
466   if ((name[strlen(name)-1] == '/') && strlen(name) != 1)
467     name[strlen(name)-1] = '\0';
468 }
469 
add_from_file(struct arg_list ** llist,struct arg_list * flist)470 static void add_from_file(struct arg_list **llist, struct arg_list *flist)
471 {
472   char *line = NULL;
473 
474   while (flist) {
475     int fd = 0;
476 
477     if (strcmp((char *)flist->arg, "-"))
478       fd = xopen((char *)flist->arg, O_RDONLY);
479 
480     while ((line = get_line(fd))) {
481       add_to_list(llist, line);
482     }
483     if (fd) close(fd);
484     flist = flist->next;
485   }
486 }
487 
init_handler()488 static struct archive_handler *init_handler()
489 {
490   struct archive_handler *tar_hdl = xzalloc(sizeof(struct archive_handler));
491   tar_hdl->extract_handler = extract_to_disk;
492   return tar_hdl;
493 }
494 
495 //convert octal to int
otoi(char * str,int len)496 static int otoi(char *str, int len)
497 {
498   long val;
499   char *endp, inp[len+1]; //1 for NUL termination
500 
501   memcpy(inp, str, len);
502   inp[len] = '\0'; //nul-termination made sure
503   val = strtol(inp, &endp, 8);
504   if (*endp && *endp != ' ') error_exit("invalid param");
505   return (int)val;
506 }
507 
extract_stream(struct archive_handler * tar_hdl)508 static void extract_stream(struct archive_handler *tar_hdl)
509 {
510   int pipefd[2];
511   pid_t cpid;
512 
513   if (pipe(pipefd) == -1) error_exit("pipe");
514 
515   cpid = fork();
516   if (cpid == -1) perror_exit("fork");
517 
518   if (!cpid) {    /* Child reads from pipe */
519     char *argv[] = {"gunzip", "-cf", "-", NULL};
520     xclose(pipefd[0]); /* Close unused read*/
521     dup2(tar_hdl->src_fd, 0);
522     dup2(pipefd[1], 1); //write to pipe
523     xexec(argv);
524   } else {
525     xclose(pipefd[1]);          /* Close unused read end */
526     dup2(pipefd[0], tar_hdl->src_fd); //read from pipe
527   }
528 }
529 
process_extended_hdr(struct archive_handler * tar,int size)530 static char *process_extended_hdr(struct archive_handler *tar, int size)
531 {
532   char *value = NULL, *p, *buf = xzalloc(size+1);
533 
534   if (readall(tar->src_fd, buf, size) != size) error_exit("short read");
535   buf[size] = 0;
536   tar->offset += size;
537   p = buf;
538 
539   while (size) {
540     char *key;
541     int len, n;
542 
543     // extended records are of the format: "LEN NAME=VALUE\n"
544     sscanf(p, "%d %n", &len, &n);
545     key = p + n;
546     p += len;
547     size -= len;
548     p[-1] = 0;
549     if (size < 0) {
550       error_msg("corrupted extended header");
551       break;
552     }
553 
554     len = strlen("path=");
555     if (!strncmp(key, "path=", len)) {
556       value = key + strlen("path=");
557       break;
558     }
559   }
560   if (value) value = xstrdup(value);
561   free(buf);
562   return value;
563 }
564 
tar_skip(struct archive_handler * tar,int sz)565 static void tar_skip(struct archive_handler *tar, int sz)
566 {
567   int x;
568 
569   while ((x = lskip(tar->src_fd, sz))) {
570     tar->offset += sz - x;
571     sz = x;
572   }
573   tar->offset += sz;
574 }
575 
unpack_tar(struct archive_handler * tar_hdl)576 static void unpack_tar(struct archive_handler *tar_hdl)
577 {
578   struct tar_hdr tar;
579   struct file_header *file_hdr;
580   int i, j, maj, min, sz, e = 0;
581   unsigned int cksum;
582   unsigned char *gzMagic;
583   char *longname = NULL, *longlink = NULL;
584 
585   while (1) {
586     cksum = 0;
587     if (tar_hdl->offset % 512) {
588       sz = 512 - tar_hdl->offset % 512;
589       tar_skip(tar_hdl, sz);
590     }
591     i = readall(tar_hdl->src_fd, &tar, 512);
592     tar_hdl->offset += i;
593     if (i != 512) {
594       if (i >= 2) goto CHECK_MAGIC; //may be a small (<512 byte)zipped file
595       error_exit("read error");
596     }
597 
598     if (!tar.name[0]) {
599       if (e) return; //end of tar 2 empty blocks
600       e = 1;//empty jump to next block
601       continue;
602     }
603     if (strncmp(tar.magic, "ustar", 5)) {
604       //try detecting by reading magic
605 CHECK_MAGIC:
606       gzMagic = (unsigned char*)&tar;
607       if ((gzMagic[0] == 0x1f) && (gzMagic[1] == 0x8b)
608           && !lseek(tar_hdl->src_fd, -i, SEEK_CUR)) {
609         tar_hdl->offset -= i;
610         extract_stream(tar_hdl);
611         continue;
612       }
613       error_exit("invalid tar format");
614     }
615 
616     for (j = 0; j<148; j++) cksum += (unsigned int)((char*)&tar)[j];
617     for (j = 156; j<500; j++) cksum += (unsigned int)((char*)&tar)[j];
618     //cksum field itself treated as ' '
619     for ( j= 0; j<8; j++) cksum += (unsigned int)' ';
620 
621     if (cksum != otoi(tar.chksum, sizeof(tar.chksum))) error_exit("wrong cksum");
622 
623     file_hdr = &tar_hdl->file_hdr;
624     memset(file_hdr, 0, sizeof(struct file_header));
625     file_hdr->mode = otoi(tar.mode, sizeof(tar.mode));
626     file_hdr->uid = otoi(tar.uid, sizeof(tar.uid));
627     file_hdr->gid = otoi(tar.gid, sizeof(tar.gid));
628     file_hdr->size = otoi(tar.size, sizeof(tar.size));
629     file_hdr->mtime = otoi(tar.mtime, sizeof(tar.mtime));
630     file_hdr->uname = xstrdup(tar.uname);
631     file_hdr->gname = xstrdup(tar.gname);
632     maj = otoi(tar.major, sizeof(tar.major));
633     min = otoi(tar.minor, sizeof(tar.minor));
634     file_hdr->device = dev_makedev(maj, min);
635 
636     if (tar.type <= '7') {
637       if (tar.link[0]) {
638         sz = sizeof(tar.link);
639         file_hdr->link_target = xmalloc(sz + 1);
640         memcpy(file_hdr->link_target, tar.link, sz);
641         file_hdr->link_target[sz] = '\0';
642       }
643 
644       file_hdr->name = xzalloc(256);// pathname supported size
645       if (tar.prefix[0]) {
646         memcpy(file_hdr->name, tar.prefix, sizeof(tar.prefix));
647         sz = strlen(file_hdr->name);
648         if (file_hdr->name[sz-1] != '/') file_hdr->name[sz] = '/';
649       }
650       sz = strlen(file_hdr->name);
651       memcpy(file_hdr->name + sz, tar.name, sizeof(tar.name));
652       if (file_hdr->name[255]) error_exit("filename too long");
653     }
654 
655     switch (tar.type) {
656       //    case '\0':
657       case '0':
658       case '7':
659       case '1': //Hard Link
660         file_hdr->mode |= S_IFREG;
661         break;
662       case '2':
663         file_hdr->mode |= S_IFLNK;
664         break;
665       case '3':
666         file_hdr->mode |= S_IFCHR;
667         break;
668       case '4':
669         file_hdr->mode |= S_IFBLK;
670         break;
671       case '5':
672         file_hdr->mode |= S_IFDIR;
673         break;
674       case '6':
675         file_hdr->mode |= S_IFIFO;
676         break;
677       case 'K':
678         longlink = xzalloc(file_hdr->size +1);
679         xread(tar_hdl->src_fd, longlink, file_hdr->size);
680         tar_hdl->offset += file_hdr->size;
681         continue;
682       case 'L':
683         free(longname);
684         longname = xzalloc(file_hdr->size +1);
685         xread(tar_hdl->src_fd, longname, file_hdr->size);
686         tar_hdl->offset += file_hdr->size;
687         continue;
688       case 'D':
689       case 'M':
690       case 'N':
691       case 'S':
692       case 'V':
693       case 'g':  // pax global header
694         tar_skip(tar_hdl, file_hdr->size);
695         continue;
696       case 'x':  // pax extended header
697         free(longname);
698         longname = process_extended_hdr(tar_hdl, file_hdr->size);
699         continue;
700       default: break;
701     }
702 
703     if (longname) {
704       free(file_hdr->name);
705       file_hdr->name = longname;
706       longname = NULL;
707     }
708     if (longlink) {
709       free(file_hdr->link_target);
710       file_hdr->link_target = longlink;
711       longlink = NULL;
712     }
713 
714     if ((file_hdr->mode & S_IFREG) &&
715         file_hdr->name[strlen(file_hdr->name)-1] == '/') {
716       file_hdr->name[strlen(file_hdr->name)-1] = '\0';
717       file_hdr->mode &= ~S_IFREG;
718       file_hdr->mode |= S_IFDIR;
719     }
720 
721     if ((file_hdr->link_target && *(file_hdr->link_target))
722         || S_ISLNK(file_hdr->mode) || S_ISDIR(file_hdr->mode))
723       file_hdr->size = 0;
724 
725     if (filter(TT.exc, file_hdr->name) ||
726         (TT.inc && !filter(TT.inc, file_hdr->name))) goto SKIP;
727     add_to_list(&TT.pass, xstrdup(file_hdr->name));
728 
729     if (toys.optflags & FLAG_t) {
730       if (toys.optflags & FLAG_v) {
731         char perm[11];
732         struct tm *lc = localtime((const time_t*)&(file_hdr->mtime));
733 
734         mode_to_string(file_hdr->mode, perm);
735         printf("%s %s/%s %9ld %d-%02d-%02d %02d:%02d:%02d ",perm,file_hdr->uname,
736             file_hdr->gname, (long)file_hdr->size, 1900+lc->tm_year,
737             1+lc->tm_mon, lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec);
738       }
739       printf("%s",file_hdr->name);
740       if (file_hdr->link_target) printf(" -> %s",file_hdr->link_target);
741       xputc('\n');
742 SKIP:
743       tar_skip(tar_hdl, file_hdr->size);
744     } else {
745       if (toys.optflags & FLAG_v) printf("%s\n",file_hdr->name);
746       tar_hdl->extract_handler(tar_hdl);
747     }
748     free(file_hdr->name);
749     free(file_hdr->link_target);
750     free(file_hdr->uname);
751     free(file_hdr->gname);
752   }
753 }
754 
tar_main(void)755 void tar_main(void)
756 {
757   struct archive_handler *tar_hdl;
758   int fd = 0;
759   struct arg_list *tmp;
760   char **args = toys.optargs;
761 
762   if (!geteuid()) toys.optflags |= FLAG_p;
763 
764   for (tmp = TT.exc; tmp; tmp = tmp->next)
765     tmp->arg = xstrdup(tmp->arg); //freeing at the end fails otherwise
766 
767   while(*args) add_to_list(&TT.inc, xstrdup(*args++));
768   if (toys.optflags & FLAG_X) add_from_file(&TT.exc, TT.exc_file);
769   if (toys.optflags & FLAG_T) add_from_file(&TT.inc, TT.inc_file);
770 
771   if (toys.optflags & FLAG_c) {
772     if (!TT.inc) error_exit("empty archive");
773     fd = 1;
774   }
775   if ((toys.optflags & FLAG_f) && strcmp(TT.fname, "-"))
776     fd = xcreate(TT.fname, fd*(O_WRONLY|O_CREAT|O_TRUNC), 0666);
777   if (toys.optflags & FLAG_C) xchdir(TT.dir);
778 
779   tar_hdl = init_handler();
780   tar_hdl->src_fd = fd;
781 
782   if ((toys.optflags & FLAG_x) || (toys.optflags & FLAG_t)) {
783     if (toys.optflags & FLAG_O) tar_hdl->extract_handler = extract_to_stdout;
784     if (toys.optflags & FLAG_to_command) {
785       signal(SIGPIPE, SIG_IGN); //will be using pipe between child & parent
786       tar_hdl->extract_handler = extract_to_command;
787     }
788     if (toys.optflags & FLAG_z) extract_stream(tar_hdl);
789     unpack_tar(tar_hdl);
790     for (tmp = TT.inc; tmp; tmp = tmp->next)
791       if (!filter(TT.exc, tmp->arg) && !filter(TT.pass, tmp->arg))
792         error_msg("'%s' not in archive", tmp->arg);
793   } else if (toys.optflags & FLAG_c) {
794     //create the tar here.
795     if (toys.optflags & FLAG_z) compress_stream(tar_hdl);
796     for (tmp = TT.inc; tmp; tmp = tmp->next) {
797       TT.handle = tar_hdl;
798       //recurse thru dir and add files to archive
799       dirtree_flagread(tmp->arg, DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_h),
800         add_to_tar);
801     }
802     memset(toybuf, 0, 1024);
803     writeall(tar_hdl->src_fd, toybuf, 1024);
804     seen_inode(&TT.inodes, 0, 0);
805   }
806 
807   if (CFG_TOYBOX_FREE) {
808     close(tar_hdl->src_fd);
809     free(tar_hdl);
810     llist_traverse(TT.exc, llist_free_arg);
811     llist_traverse(TT.inc, llist_free_arg);
812     llist_traverse(TT.pass, llist_free_arg);
813   }
814 }
815