1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <bio.h> 6 7 #define TBLOCK 512 8 #define NBLOCK 40 /* maximum blocksize */ 9 #define DBLOCK 20 /* default blocksize */ 10 #define NAMSIZ 100 11 union hblock 12 { 13 char dummy[TBLOCK]; 14 struct header 15 { 16 char name[NAMSIZ]; 17 char mode[8]; 18 char uid[8]; 19 char gid[8]; 20 char size[12]; 21 char mtime[12]; 22 char chksum[8]; 23 char linkflag; 24 char linkname[NAMSIZ]; 25 } dbuf; 26 } dblock, tbuf[NBLOCK]; 27 28 Dir stbuf; 29 Biobuf bout; 30 31 int rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag; 32 int uflag, gflag; 33 int chksum, recno, first; 34 int nblock = DBLOCK; 35 36 void usage(void); 37 void dorep(char **); 38 int endtar(void); 39 void getdir(void); 40 void passtar(void); 41 void putfile(char *, char *); 42 void doxtract(char **); 43 void dotable(void); 44 void putempty(void); 45 void longt(Dir *); 46 int checkdir(char *); 47 void tomodes(Dir *); 48 int checksum(void); 49 int checkupdate(char *); 50 int prefix(char *, char *); 51 int readtar(char *); 52 int writetar(char *); 53 void backtar(void); 54 void flushtar(void); 55 void affix(int, char *); 56 char *findname(char *); 57 void fixname(char *); 58 int volprompt(void); 59 void 60 main(int argc, char **argv) 61 { 62 char *usefile; 63 char *cp, *ap; 64 65 if (argc < 2) 66 usage(); 67 68 Binit(&bout, 1, OWRITE); 69 usefile = 0; 70 argv[argc] = 0; 71 argv++; 72 for (cp = *argv++; *cp; cp++) 73 switch(*cp) { 74 case 'f': 75 usefile = *argv++; 76 if(!usefile) 77 usage(); 78 fflag++; 79 break; 80 case 'u': 81 ap = *argv++; 82 if(!ap) 83 usage(); 84 uflag = strtoul(ap, 0, 0); 85 break; 86 case 'g': 87 ap = *argv++; 88 if(!ap) 89 usage(); 90 gflag = strtoul(ap, 0, 0); 91 break; 92 case 'c': 93 cflag++; 94 rflag++; 95 break; 96 case 'r': 97 rflag++; 98 break; 99 case 'v': 100 vflag++; 101 break; 102 case 'x': 103 xflag++; 104 break; 105 case 'T': 106 Tflag++; 107 break; 108 case 't': 109 tflag++; 110 break; 111 case '-': 112 break; 113 default: 114 fprint(2, "tar: %c: unknown option\n", *cp); 115 usage(); 116 } 117 118 fmtinstall('M', dirmodeconv); 119 120 if (rflag) { 121 if (!usefile) { 122 if (cflag == 0) { 123 fprint(2, "Can only create standard output archives\n"); 124 exits("arg error"); 125 } 126 mt = dup(1, -1); 127 nblock = 1; 128 } 129 else if ((mt = open(usefile, ORDWR)) < 0) { 130 if (cflag == 0 || (mt = create(usefile, OWRITE, 0666)) < 0) { 131 fprint(2, "tar: cannot open %s\n", usefile); 132 exits("open"); 133 } 134 } 135 dorep(argv); 136 } 137 else if (xflag) { 138 if (!usefile) { 139 mt = dup(0, -1); 140 nblock = 1; 141 } 142 else if ((mt = open(usefile, OREAD)) < 0) { 143 fprint(2, "tar: cannot open %s\n", usefile); 144 exits("open"); 145 } 146 doxtract(argv); 147 } 148 else if (tflag) { 149 if (!usefile) { 150 mt = dup(0, -1); 151 nblock = 1; 152 } 153 else if ((mt = open(usefile, OREAD)) < 0) { 154 fprint(2, "tar: cannot open %s\n", usefile); 155 exits("open"); 156 } 157 dotable(); 158 } 159 else 160 usage(); 161 exits(0); 162 } 163 164 void 165 usage(void) 166 { 167 fprint(2, "tar: usage tar {txrc}[vf] [tarfile] file1 file2...\n"); 168 exits("usage"); 169 } 170 171 void 172 dorep(char **argv) 173 { 174 char *cp, *cp2; 175 176 if (!cflag) { 177 getdir(); 178 do { 179 passtar(); 180 getdir(); 181 } while (!endtar()); 182 } 183 184 while (*argv) { 185 cp2 = *argv; 186 if (!strcmp(cp2, "-C") && argv[1]) { 187 argv++; 188 if (chdir(*argv) < 0) 189 perror(*argv); 190 argv++; 191 continue; 192 } 193 for (cp = *argv; *cp; cp++) 194 if (*cp == '/') 195 cp2 = cp; 196 if (cp2 != *argv) { 197 *cp2 = '\0'; 198 chdir(*argv); 199 *cp2 = '/'; 200 cp2++; 201 } 202 putfile(*argv++, cp2); 203 } 204 putempty(); 205 putempty(); 206 flushtar(); 207 } 208 209 int 210 endtar(void) 211 { 212 if (dblock.dbuf.name[0] == '\0') { 213 backtar(); 214 return(1); 215 } 216 else 217 return(0); 218 } 219 220 void 221 getdir(void) 222 { 223 Dir *sp; 224 225 readtar((char*)&dblock); 226 if (dblock.dbuf.name[0] == '\0') 227 return; 228 sp = &stbuf; 229 sp->mode = strtol(dblock.dbuf.mode, 0, 8); 230 strncpy(sp->uid, "adm", sizeof(sp->uid)); 231 strncpy(sp->gid, "adm", sizeof(sp->gid)); 232 sp->length = strtol(dblock.dbuf.size, 0, 8); 233 sp->mtime = strtol(dblock.dbuf.mtime, 0, 8); 234 chksum = strtol(dblock.dbuf.chksum, 0, 8); 235 if (chksum != checksum()) { 236 fprint(2, "directory checksum error\n"); 237 exits("checksum error"); 238 } 239 if(xflag){ 240 fixname(dblock.dbuf.name); 241 fixname(dblock.dbuf.linkname); 242 } 243 } 244 245 void 246 passtar(void) 247 { 248 long blocks; 249 char buf[TBLOCK]; 250 251 if (dblock.dbuf.linkflag == '1' || dblock.dbuf.linkflag == 's') 252 return; 253 blocks = stbuf.length; 254 blocks += TBLOCK-1; 255 blocks /= TBLOCK; 256 257 while (blocks-- > 0) 258 readtar(buf); 259 } 260 261 void 262 putfile(char *longname, char *sname) 263 { 264 int infile; 265 long blocks; 266 char buf[TBLOCK], shortname[NAMELEN+4]; 267 char *cp, *cp2; 268 Dir db[50]; 269 int i, n; 270 271 sprint(shortname, "./%s", sname); 272 infile = open(shortname, OREAD); 273 if (infile < 0) { 274 fprint(2, "tar: %s: cannot open file\n", longname); 275 return; 276 } 277 278 dirfstat(infile, &stbuf); 279 280 if (stbuf.qid.path & CHDIR) { 281 for (i = 0, cp = buf; *cp++ = longname[i++];); 282 *--cp = '/'; 283 *++cp = 0; 284 if( (cp - buf) >= NAMSIZ) { 285 fprint(2, "%s: file name too long\n", longname); 286 close(infile); 287 return; 288 } 289 stbuf.length = 0; 290 tomodes(&stbuf); 291 strcpy(dblock.dbuf.name,buf); 292 sprint(dblock.dbuf.chksum, "%6o", checksum()); 293 writetar( (char *) &dblock); 294 if (chdir(shortname) < 0) { 295 fprint(2, "tar: can't cd to %s\n", shortname); 296 exits("cd"); 297 } 298 while ((n = dirread(infile, db, sizeof(db))) > 0) { 299 n /= sizeof(Dir); 300 for(i = 0; i < n; i++) { 301 strncpy(cp, db[i].name, NAMELEN); 302 putfile(buf, cp); 303 } 304 } 305 close(infile); 306 if (chdir("..") < 0) { 307 fprint(2, "tar: can't cd to ..\n"); 308 exits("cd"); 309 } 310 return; 311 } 312 313 tomodes(&stbuf); 314 315 cp2 = longname; 316 for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++); 317 if (i >= NAMSIZ) { 318 fprint(2, "%s: file name too long\n", longname); 319 close(infile); 320 return; 321 } 322 323 blocks = (stbuf.length + (TBLOCK-1)) / TBLOCK; 324 if (vflag) { 325 fprint(2, "a %s ", longname); 326 fprint(2, "%ld blocks\n", blocks); 327 } 328 sprint(dblock.dbuf.chksum, "%6o", checksum()); 329 writetar( (char *) &dblock); 330 331 while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 332 writetar(buf); 333 blocks--; 334 } 335 close(infile); 336 if (blocks != 0 || i != 0) 337 fprint(2, "%s: file changed size\n", longname); 338 while (blocks-- > 0) 339 putempty(); 340 } 341 342 343 void 344 doxtract(char **argv) 345 { 346 Dir mydir; 347 long blocks, bytes; 348 char buf[TBLOCK], outname[NAMSIZ+4]; 349 char **cp; 350 int ofile; 351 352 for (;;) { 353 getdir(); 354 if (endtar()) 355 break; 356 357 if (*argv == 0) 358 goto gotit; 359 360 for (cp = argv; *cp; cp++) 361 if (prefix(*cp, dblock.dbuf.name)) 362 goto gotit; 363 passtar(); 364 continue; 365 366 gotit: 367 if(checkdir(dblock.dbuf.name)) 368 continue; 369 370 if (dblock.dbuf.linkflag == '1') { 371 fprint(2, "tar: can't link %s %s\n", 372 dblock.dbuf.linkname, dblock.dbuf.name); 373 remove(dblock.dbuf.name); 374 continue; 375 } 376 if (dblock.dbuf.linkflag == 's') { 377 fprint(2, "%s: cannot symlink\n", dblock.dbuf.name); 378 continue; 379 } 380 if(dblock.dbuf.name[0] != '/') 381 sprint(outname, "./%s", dblock.dbuf.name); 382 else 383 strcpy(outname, dblock.dbuf.name); 384 if ((ofile = create(outname, OWRITE, stbuf.mode & 0777)) < 0) { 385 fprint(2, "tar: %s - cannot create\n", dblock.dbuf.name); 386 passtar(); 387 continue; 388 } 389 390 blocks = ((bytes = stbuf.length) + TBLOCK-1)/TBLOCK; 391 if (vflag) 392 fprint(2, "x %s, %ld bytes\n", 393 dblock.dbuf.name, bytes); 394 while (blocks-- > 0) { 395 readtar(buf); 396 if (bytes > TBLOCK) { 397 if (write(ofile, buf, TBLOCK) < 0) { 398 fprint(2, "tar: %s: HELP - extract write error\n", dblock.dbuf.name); 399 exits("extract write"); 400 } 401 } else 402 if (write(ofile, buf, bytes) < 0) { 403 fprint(2, "tar: %s: HELP - extract write error\n", dblock.dbuf.name); 404 exits("extract write"); 405 } 406 bytes -= TBLOCK; 407 } 408 if(Tflag){ 409 dirfstat(ofile, &mydir); 410 mydir.mtime = stbuf.mtime; 411 dirfwstat(ofile, &mydir); 412 } 413 close(ofile); 414 } 415 } 416 417 void 418 dotable(void) 419 { 420 for (;;) { 421 getdir(); 422 if (endtar()) 423 break; 424 if (vflag) 425 longt(&stbuf); 426 Bprint(&bout, "%s", dblock.dbuf.name); 427 if (dblock.dbuf.linkflag == '1') 428 Bprint(&bout, " linked to %s", dblock.dbuf.linkname); 429 if (dblock.dbuf.linkflag == 's') 430 Bprint(&bout, " -> %s", dblock.dbuf.linkname); 431 Bprint(&bout, "\n"); 432 passtar(); 433 } 434 } 435 436 void 437 putempty(void) 438 { 439 char buf[TBLOCK]; 440 441 memset(buf, 0, TBLOCK); 442 writetar(buf); 443 } 444 445 void 446 longt(Dir *st) 447 { 448 char *cp; 449 450 Bprint(&bout, "%M %4d/%1d", st->mode, 0, 0); /* 0/0 uid/gid */ 451 Bprint(&bout, "%7d", st->length); 452 cp = ctime(st->mtime); 453 Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); 454 } 455 456 int 457 checkdir(char *name) 458 { 459 char *cp; 460 int f; 461 462 cp = name; 463 if(*cp == '/') 464 cp++; 465 for (; *cp; cp++) { 466 if (*cp == '/') { 467 *cp = '\0'; 468 if (access(name, 0) < 0) { 469 f = create(name, OREAD, CHDIR + 0777L); 470 close(f); 471 if(f < 0) 472 fprint(2, "tar: mkdir %s failed\n", name); 473 } 474 *cp = '/'; 475 } 476 } 477 return(cp[-1]=='/'); 478 } 479 480 void 481 tomodes(Dir *sp) 482 { 483 char *cp; 484 485 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 486 *cp = '\0'; 487 sprint(dblock.dbuf.mode, "%6o ", sp->mode & 0777); 488 sprint(dblock.dbuf.uid, "%6o ", uflag); 489 sprint(dblock.dbuf.gid, "%6o ", gflag); 490 sprint(dblock.dbuf.size, "%11lo ", sp->length); 491 sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime); 492 } 493 494 int 495 checksum(void) 496 { 497 int i; 498 char *cp; 499 500 for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 501 *cp = ' '; 502 i = 0; 503 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 504 i += *cp; 505 return(i); 506 } 507 508 int 509 prefix(char *s1, char *s2) 510 { 511 while (*s1) 512 if (*s1++ != *s2++) 513 return(0); 514 if (*s2) 515 return(*s2 == '/'); 516 return(1); 517 } 518 519 int 520 readtar(char *buffer) 521 { 522 int i; 523 524 if (recno >= nblock || first == 0) { 525 redo: 526 if ((i = read(mt, tbuf, TBLOCK*nblock)) <= 0) { 527 fprint(2, "Tar: archive read error\n"); 528 exits("archive read"); 529 } 530 if (first == 0) { 531 if ((i % TBLOCK) != 0) { 532 fprint(2, "Tar: archive blocksize error\n"); 533 exits("blocksize"); 534 } 535 i /= TBLOCK; 536 if (i != nblock) { 537 fprint(2, "Tar: blocksize = %d\n", i); 538 nblock = i; 539 } 540 } 541 recno = 0; 542 } 543 first = 1; 544 memmove(buffer, &tbuf[recno++], TBLOCK); 545 return(TBLOCK); 546 } 547 548 int 549 writetar(char *buffer) 550 { 551 first = 1; 552 if (recno >= nblock) { 553 if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) { 554 fprint(2, "Tar: archive write error\n"); 555 exits("write"); 556 } 557 recno = 0; 558 } 559 memmove(&tbuf[recno++], buffer, TBLOCK); 560 if (recno >= nblock) { 561 if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) { 562 fprint(2, "Tar: archive write error\n"); 563 exits("write"); 564 } 565 recno = 0; 566 } 567 return(TBLOCK); 568 } 569 570 /* 571 * backup over last tar block 572 */ 573 void 574 backtar(void) 575 { 576 seek(mt, -TBLOCK*nblock, 1); 577 recno--; 578 } 579 580 void 581 flushtar(void) 582 { 583 write(mt, tbuf, TBLOCK*nblock); 584 } 585 586 #define MAXFILENAME (NAMELEN-1) 587 int longnamefd; 588 589 void 590 affix(int n, char *ptr) 591 { 592 int i=0,m; 593 char ext[5]; 594 595 while(1) { 596 if((m=n%52)<26) ext[i++] = m + 'a'; 597 else ext[i++] = m + 'A' - 26; 598 if(n < 52)break; 599 n = n/52 - 1; /* so we have Z,aa not Z,ba */ 600 } 601 602 while(--i >= 0)*ptr++ = ext[i]; 603 *ptr = '\0'; 604 } 605 606 #define MAXOVER 1000 607 struct { 608 char *longname, 609 *shortname; 610 } pairs[MAXOVER]; 611 int npairs = 0; /* no. of tabulated pairs */ 612 613 int ntoolong = 0; /* no. of overlong pathnames */ 614 615 char * 616 findname(char *key) 617 { 618 int i, nprevious = 0, nprefix; 619 char *longptr, *shortptr, *endbit; 620 621 endbit = strrchr(key,'/'); 622 if(endbit == 0)endbit = key; 623 else endbit++; 624 nprefix = endbit - key; 625 626 for(i=0;i<npairs;i++){ 627 if(strcmp(key,pairs[i].longname) == 0) 628 return(pairs[i].shortname); 629 if(strncmp(key,pairs[i].longname,nprefix+MAXFILENAME-4) == 0) 630 nprevious++; 631 } 632 longptr = pairs[npairs].longname = malloc(strlen(key)+1); 633 shortptr = pairs[npairs].shortname = malloc(MAXFILENAME+1); 634 strcpy(longptr,key); 635 strncpy(shortptr,endbit,MAXFILENAME-4); 636 sprint(shortptr+MAXFILENAME-4,".."); 637 affix(nprevious,shortptr+MAXFILENAME-2); 638 npairs++; 639 return(shortptr); 640 } 641 642 void 643 fixname(char *original) 644 { 645 int length; 646 char newname[100]; 647 char *inend, *outptr=newname, *instart=original, 648 *outstart; 649 int changed = 0; 650 651 while(1){ 652 if(*instart == '\0')break; 653 if(*instart == '/')*outptr++ = *instart++; 654 outstart = outptr; 655 for(inend=instart;*inend != '\0' && *inend != '/';) 656 *outptr++ = *inend++; 657 *outptr = '\0'; 658 length = strlen(outstart); 659 if(length > MAXFILENAME){ 660 changed++; 661 strcpy(outstart,findname(newname)); 662 } 663 outptr = outstart + strlen(outstart); 664 instart = inend; 665 } 666 667 if(changed){ 668 if(ntoolong == 0) { 669 longnamefd = open("longnamelist", OWRITE); 670 if(longnamefd < 0){ 671 if((longnamefd = create("longnamelist", OWRITE, 0666)) == -1){ 672 fprint(2, "can't create longnamelist file\n"); 673 exits("create"); 674 } 675 } 676 seek(longnamefd, 0, 2); 677 fprint(2,"check out file 'longnamelist'\n"); 678 } 679 fprint(2, "%s changed to %s\n",original,newname); 680 fprint(longnamefd,"%s\t%s\n",original, newname); 681 strcpy(original,newname); 682 ntoolong++; 683 } 684 } 685