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