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