1 /* tar.c - create/extract archives
3 * Copyright 2014 Ashwini Kumar <ak.ashwini81@gmail.com>
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
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))
16 usage: tar -[cxtzhmvO] [-X FILE] [-T FILE] [-f TARFILE] [-C DIR]
18 Create, extract, or list files from a tar file
22 f Name of TARFILE ('-' for stdin/out)
28 z (De)compress using gzip
29 C Change to DIR before operation
31 exclude=FILE File to exclude
32 X File with names to exclude
33 T File with names to include
41 struct arg_list *inc_file;
42 struct arg_list *exc_file;
46 struct arg_list *inc, *pass;
47 void *inodes, *handle;
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];
57 char *name, *link_target, *uname, *gname;
66 struct archive_handler {
68 struct file_header file_hdr;
70 void (*extract_handler)(struct archive_handler*);
74 struct inode_list *next;
80 static void copy_in_out(int src, int dst, off_t size)
82 int i, rd, rem = size%512, cnt;
84 cnt = size/512 + (rem?1:0);
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);
94 static void itoo(char *str, int len, off_t val)
96 char *t, tmp[sizeof(off_t)*3+1];
97 int cnt = sprintf(tmp, "%0*llo", len, val);
104 static struct inode_list *seen_inode(void **list, struct stat *st, char *name)
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;
110 for (new = *list; new; new = new->next)
111 if(new->ino == st->st_ino && new->dev == st->st_dev)
114 new = xzalloc(sizeof(*new));
115 new->ino = st->st_ino;
116 new->dev = st->st_dev;
117 new->arg = xstrdup(name);
124 static void write_longname(struct archive_handler *tar, char *name, char type)
127 unsigned int sum = 0;
128 int i, sz = strlen(name) +1;
129 char buf[512] = {0,};
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);
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);
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)));
151 static int filter(struct arg_list *lst, char *name)
153 struct arg_list *cur;
155 for (cur = lst; cur; cur = cur->next)
156 if (!fnmatch(cur->arg, name, 1<<3)) return 1;
160 static void add_file(struct archive_handler *tar, char **nam, struct stat *st)
165 struct inode_list *node;
167 char *c, *p, *name = *nam, *lnk, *hname, buf[512] = {0,};
168 unsigned int sum = 0;
171 for (p = name; *p; p++)
172 if ((p == name || p[-1] == '/') && *p != '/'
173 && filter(TT.exc, p)) return;
175 if (S_ISDIR(st->st_mode) && name[strlen(name)-1] != '/') {
176 lnk = xmprintf("%s/",name);
181 //remove leading '/' or relative path '../' component
182 if (*hname == '/') hname++;
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);
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] = ' ';
200 if ((node = seen_inode(&TT.inodes, st, hname))) {
201 //this is a hard link
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)) {
208 if (st->st_size <= (off_t)0777777777777LL)
209 itoo(hdr.size, sizeof(hdr.size), st->st_size);
211 error_msg("can't store file '%s' of size '%d'\n", hname, st->st_size);
214 } else if (S_ISLNK(st->st_mode)) {
215 hdr.type = '2'; //'K' long link
216 if (!(lnk = xreadlink(name))) {
217 perror_msg("readlink");
220 if (strlen(lnk) > sizeof(hdr.link))
221 write_longname(tar, hname, 'K'); //write longname LINK
222 xstrncpy(hdr.link, lnk, sizeof(hdr.link));
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));
232 error_msg("unknown file type '%s'");
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);
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);
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);
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);
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)));
263 static int add_to_tar(struct dirtree *node)
267 struct archive_handler *hdl = (struct archive_handler*)TT.handle;
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)));
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
279 if (toys.optflags & FLAG_no_recursion) return 0;
280 return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
283 static void compress_stream(struct archive_handler *tar_hdl)
288 if (pipe(pipefd) == -1) error_exit("pipe");
290 signal(SIGPIPE, SIG_IGN);
292 if (cpid == -1) perror_exit("fork");
294 if (!cpid) { /* Child reads from pipe */
295 char *argv[] = {"gzip", "-f", NULL};
296 xclose(pipefd[1]); /* Close unused write*/
298 dup2(tar_hdl->src_fd, 1); //write to tar fd
301 xclose(pipefd[0]); /* Close unused read end */
302 dup2(pipefd[1], tar_hdl->src_fd); //write to pipe
306 static void extract_to_stdout(struct archive_handler *tar)
308 struct file_header *file_hdr = &tar->file_hdr;
310 copy_in_out(tar->src_fd, 0, file_hdr->size);
311 tar->offset += file_hdr->size;
314 static void extract_to_command(struct archive_handler *tar)
316 int pipefd[2], status = 0;
318 struct file_header *file_hdr = &tar->file_hdr;
320 if (pipe(pipefd) == -1) error_exit("pipe");
321 if (!S_ISREG(file_hdr->mode)) return; //only regular files are supported.
324 if (cpid == -1) perror_exit("fork");
326 if (!cpid) { // Child reads from pipe
327 char buf[64], *argv[4] = {"sh", "-c", TT.tocmd, NULL};
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);
344 xclose(pipefd[1]); // Close unused write
346 signal(SIGPIPE, SIG_DFL);
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;
353 waitpid(cpid, &status, 0);
354 if (WIFSIGNALED(status))
355 xprintf("tar : %d: child returned %d\n", cpid, WTERMSIG(status));
359 static void extract_to_disk(struct archive_handler *tar)
361 int flags, dst_fd = -1;
364 struct file_header *file_hdr = &tar->file_hdr;
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);
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);
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);
391 switch (file_hdr->mode & S_IFMT) {
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);
399 if ((mkdir(file_hdr->name, file_hdr->mode) == -1) && errno != EEXIST)
400 perror_msg("%s: can't create", file_hdr->name);
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);
409 if (mknod(file_hdr->name, file_hdr->mode, file_hdr->device))
410 perror_msg("can't create '%s'", file_hdr->name);
413 printf("type not yet supported\n");
419 copy_in_out(tar->src_fd, dst_fd, file_hdr->size);
420 tar->offset += file_hdr->size;
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;
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;
435 chown(file_hdr->name, u, g);
438 if (toys.optflags & FLAG_p) // || !(toys.optflags & FLAG_no_same_permissions))
439 chmod(file_hdr->name, file_hdr->mode);
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);
448 static void add_to_list(struct arg_list **llist, char *name)
450 struct arg_list **list = llist;
452 while (*list) list=&((*list)->next);
453 *list = xzalloc(sizeof(struct arg_list));
455 if ((name[strlen(name)-1] == '/') && strlen(name) != 1)
456 name[strlen(name)-1] = '\0';
459 static void add_from_file(struct arg_list **llist, struct arg_list *flist)
466 if (strcmp((char *)flist->arg, "-"))
467 fd = xopen((char *)flist->arg, O_RDONLY);
469 while ((line = get_line(fd))) {
470 add_to_list(llist, line);
477 static struct archive_handler *init_handler()
479 struct archive_handler *tar_hdl = xzalloc(sizeof(struct archive_handler));
480 tar_hdl->extract_handler = extract_to_disk;
484 //convert octal to int
485 static int otoi(char *str, int len)
488 char *endp, inp[len+1]; //1 for NUL termination
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");
497 static void extract_stream(struct archive_handler *tar_hdl)
502 if (pipe(pipefd) == -1) error_exit("pipe");
505 if (cpid == -1) perror_exit("fork");
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
514 xclose(pipefd[1]); /* Close unused read end */
515 dup2(pipefd[0], tar_hdl->src_fd); //read from pipe
519 static char *process_extended_hdr(struct archive_handler *tar, int size)
521 char *value = NULL, *p, *buf = xzalloc(size+1);
523 if (readall(tar->src_fd, buf, size) != size) error_exit("short read");
532 // extended records are of the format: "LEN NAME=VALUE\n"
533 sscanf(p, "%d %n", &len, &n);
539 error_msg("corrupted extended header");
543 len = strlen("path=");
544 if (!strncmp(key, "path=", len)) {
545 value = key + strlen("path=");
549 if (value) value = xstrdup(value);
554 static void tar_skip(struct archive_handler *tar, int sz)
558 while ((x = lskip(tar->src_fd, sz))) {
559 tar->offset += sz - x;
565 static void unpack_tar(struct archive_handler *tar_hdl)
568 struct file_header *file_hdr;
569 int i, j, maj, min, sz, e = 0;
571 unsigned char *gzMagic;
572 char *longname = NULL, *longlink = NULL;
576 if (tar_hdl->offset % 512) {
577 sz = 512 - tar_hdl->offset % 512;
578 tar_skip(tar_hdl, sz);
580 i = readall(tar_hdl->src_fd, &tar, 512);
581 tar_hdl->offset += i;
583 if (i >= 2) goto CHECK_MAGIC; //may be a small (<512 byte)zipped file
584 error_exit("read error");
588 if (e) return; //end of tar 2 empty blocks
589 e = 1;//empty jump to next block
592 if (strncmp(tar.magic, "ustar", 5)) {
593 //try detecting by reading 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);
602 error_exit("invalid tar format");
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)' ';
610 if (cksum != otoi(tar.chksum, sizeof(tar.chksum))) error_exit("wrong cksum");
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);
625 if (tar.type <= '7') {
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';
633 file_hdr->name = xzalloc(256);// pathname supported size
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] = '/';
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");
648 case '1': //Hard Link
649 file_hdr->mode |= S_IFREG;
652 file_hdr->mode |= S_IFLNK;
655 file_hdr->mode |= S_IFCHR;
658 file_hdr->mode |= S_IFBLK;
661 file_hdr->mode |= S_IFDIR;
664 file_hdr->mode |= S_IFIFO;
667 longlink = xzalloc(file_hdr->size +1);
668 xread(tar_hdl->src_fd, longlink, file_hdr->size);
669 tar_hdl->offset += file_hdr->size;
673 longname = xzalloc(file_hdr->size +1);
674 xread(tar_hdl->src_fd, longname, file_hdr->size);
675 tar_hdl->offset += file_hdr->size;
682 case 'g': // pax global header
683 tar_skip(tar_hdl, file_hdr->size);
685 case 'x': // pax extended header
687 longname = process_extended_hdr(tar_hdl, file_hdr->size);
693 free(file_hdr->name);
694 file_hdr->name = longname;
698 free(file_hdr->link_target);
699 file_hdr->link_target = longlink;
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;
710 if ((file_hdr->link_target && *(file_hdr->link_target))
711 || S_ISLNK(file_hdr->mode) || S_ISDIR(file_hdr->mode))
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));
718 if (toys.optflags & FLAG_t) {
719 if (toys.optflags & FLAG_v) {
721 struct tm *lc = localtime((const time_t*)&(file_hdr->mtime));
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);
728 printf("%s",file_hdr->name);
729 if (file_hdr->link_target) printf(" -> %s",file_hdr->link_target);
732 tar_skip(tar_hdl, file_hdr->size);
734 if (toys.optflags & FLAG_v) printf("%s\n",file_hdr->name);
735 tar_hdl->extract_handler(tar_hdl);
737 free(file_hdr->name);
738 free(file_hdr->link_target);
739 free(file_hdr->uname);
740 free(file_hdr->gname);
746 struct archive_handler *tar_hdl;
747 int fd = 0, flags = O_RDONLY;
748 struct arg_list *tmp;
749 char **args = toys.optargs;
756 if (!geteuid()) toys.optflags |= FLAG_p;
758 for (tmp = TT.exc; tmp; tmp = tmp->next)
759 tmp->arg = xstrdup(tmp->arg); //freeing at the end fails otherwise
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);
765 if (toys.optflags & FLAG_c) {
766 if (!TT.inc) error_exit("empty archive");
767 fd = 1, flags = O_WRONLY|O_CREAT|O_TRUNC;
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);
773 tar_hdl = init_handler();
774 tar_hdl->src_fd = fd;
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;
782 if (toys.optflags & FLAG_z) extract_stream(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) {
792 //recurse thru dir and add files to archive
793 struct dirtree *root = dirtree_add_node(0,tmp->arg,toys.optflags & FLAG_h);
795 if (root) dirtree_handle_callback(root, add_to_tar);
797 memset(toybuf, 0, 1024);
798 writeall(tar_hdl->src_fd, toybuf, 1024);
799 seen_inode(&TT.inodes, 0, 0);
802 if (CFG_TOYBOX_FREE) {
803 close(tar_hdl->src_fd);
805 llist_traverse(TT.exc, llist_free_arg);
806 llist_traverse(TT.inc, llist_free_arg);
807 llist_traverse(TT.pass, llist_free_arg);