date and time created 85/06/06 11:06:25 by dist
[unix-history] / usr / src / old / tar / tar.c
CommitLineData
654c61ee 1#ifndef lint
75115c46 2static char *sccsid = "@(#)tar.c 4.23 (Berkeley) %G%";
654c61ee 3#endif
555a248b 4
1e5bf3dc
KD
5/*
6 * Tape Archival Program
7 */
415c8aef 8#include <stdio.h>
d7ab2ea5 9#include <sys/param.h>
415c8aef 10#include <sys/stat.h>
654c61ee 11#include <sys/dir.h>
dfdd2236 12#include <sys/ioctl.h>
06eff236 13#include <sys/mtio.h>
828d5b76 14#include <sys/time.h>
415c8aef 15#include <signal.h>
654c61ee 16#include <errno.h>
415c8aef 17
415c8aef 18#define TBLOCK 512
9547dafa 19#define NBLOCK 20
415c8aef 20#define NAMSIZ 100
75115c46 21#define FILEBLOCK 20
555a248b 22
1e5bf3dc
KD
23#define writetape(b) writetbuf(b, 1)
24#define min(a,b) ((a) < (b) ? (a) : (b))
25#define max(a,b) ((a) > (b) ? (a) : (b))
26
415c8aef
BJ
27union hblock {
28 char dummy[TBLOCK];
29 struct header {
30 char name[NAMSIZ];
31 char mode[8];
32 char uid[8];
33 char gid[8];
34 char size[12];
35 char mtime[12];
36 char chksum[8];
37 char linkflag;
38 char linkname[NAMSIZ];
39 } dbuf;
555a248b 40};
415c8aef
BJ
41
42struct linkbuf {
43 ino_t inum;
44 dev_t devnum;
45 int count;
46 char pathname[NAMSIZ];
47 struct linkbuf *nextp;
555a248b
BJ
48};
49
50union hblock dblock;
095da6e7 51union hblock *tbuf;
555a248b
BJ
52struct linkbuf *ihead;
53struct stat stbuf;
54
55int rflag;
56int xflag;
57int vflag;
58int tflag;
59int cflag;
60int mflag;
61int fflag;
654c61ee 62int iflag;
555a248b
BJ
63int oflag;
64int pflag;
65int wflag;
66int hflag;
8678ae71 67int Bflag;
654c61ee 68int Fflag;
555a248b
BJ
69
70int mt;
75115c46 71int mtdev = 1;
555a248b
BJ
72int term;
73int chksum;
74int recno;
75115c46 75int first = 0;
555a248b 76int linkerrok;
415c8aef 77int freemem = 1;
75115c46 78int nblock = 0;
555a248b
BJ
79int onintr();
80int onquit();
81int onhup();
82int onterm();
415c8aef
BJ
83
84daddr_t low;
85daddr_t high;
555a248b 86daddr_t bsrch();
415c8aef 87
ed4dfcb6 88FILE *vfile = stdout;
415c8aef
BJ
89FILE *tfile;
90char tname[] = "/tmp/tarXXXXXX";
415c8aef 91char *usefile;
555a248b 92char magtape[] = "/dev/rmt8";
415c8aef 93char *malloc();
555a248b
BJ
94char *sprintf();
95char *strcat();
654c61ee 96char *rindex();
5ee3622a 97char *getcwd();
13fc8845 98char *getwd();
415c8aef
BJ
99
100main(argc, argv)
101int argc;
102char *argv[];
103{
104 char *cp;
415c8aef
BJ
105
106 if (argc < 2)
107 usage();
108
109 tfile = NULL;
110 usefile = magtape;
111 argv[argc] = 0;
112 argv++;
113 for (cp = *argv++; *cp; cp++)
114 switch(*cp) {
555a248b 115
415c8aef 116 case 'f':
654c61ee
SL
117 if (*argv == 0) {
118 fprintf(stderr,
119 "tar: tapefile must be specified with 'f' option\n");
120 usage();
121 }
415c8aef
BJ
122 usefile = *argv++;
123 fflag++;
415c8aef 124 break;
555a248b 125
415c8aef
BJ
126 case 'c':
127 cflag++;
128 rflag++;
129 break;
555a248b 130
415c8aef
BJ
131 case 'o':
132 oflag++;
133 break;
555a248b 134
415c8aef
BJ
135 case 'p':
136 pflag++;
137 break;
555a248b 138
415c8aef
BJ
139 case 'u':
140 mktemp(tname);
141 if ((tfile = fopen(tname, "w")) == NULL) {
555a248b
BJ
142 fprintf(stderr,
143 "Tar: cannot create temporary file (%s)\n",
144 tname);
415c8aef
BJ
145 done(1);
146 }
147 fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
555a248b
BJ
148 /*FALL THRU*/
149
415c8aef
BJ
150 case 'r':
151 rflag++;
415c8aef 152 break;
555a248b 153
415c8aef
BJ
154 case 'v':
155 vflag++;
156 break;
555a248b 157
415c8aef
BJ
158 case 'w':
159 wflag++;
160 break;
555a248b 161
415c8aef
BJ
162 case 'x':
163 xflag++;
164 break;
555a248b 165
415c8aef
BJ
166 case 't':
167 tflag++;
168 break;
555a248b 169
415c8aef
BJ
170 case 'm':
171 mflag++;
172 break;
555a248b 173
415c8aef
BJ
174 case '-':
175 break;
555a248b 176
415c8aef
BJ
177 case '0':
178 case '1':
179 case '4':
180 case '5':
1e5bf3dc 181 case '7':
415c8aef
BJ
182 case '8':
183 magtape[8] = *cp;
184 usefile = magtape;
185 break;
555a248b 186
415c8aef 187 case 'b':
095da6e7
SL
188 if (*argv == 0) {
189 fprintf(stderr,
190 "tar: blocksize must be specified with 'b' option\n");
191 usage();
192 }
193 nblock = atoi(*argv);
194 if (nblock <= 0) {
195 fprintf(stderr,
196 "tar: invalid blocksize \"%s\"\n", *argv);
415c8aef
BJ
197 done(1);
198 }
095da6e7 199 argv++;
415c8aef 200 break;
555a248b 201
415c8aef
BJ
202 case 'l':
203 linkerrok++;
204 break;
555a248b
BJ
205
206 case 'h':
207 hflag++;
208 break;
209
654c61ee
SL
210 case 'i':
211 iflag++;
212 break;
213
8678ae71
KM
214 case 'B':
215 Bflag++;
216 break;
217
654c61ee
SL
218 case 'F':
219 Fflag++;
220 break;
221
415c8aef
BJ
222 default:
223 fprintf(stderr, "tar: %c: unknown option\n", *cp);
224 usage();
225 }
226
555a248b
BJ
227 if (!rflag && !xflag && !tflag)
228 usage();
415c8aef 229 if (rflag) {
555a248b 230 if (cflag && tfile != NULL)
415c8aef 231 usage();
415c8aef
BJ
232 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
233 signal(SIGINT, onintr);
234 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
235 signal(SIGHUP, onhup);
236 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
237 signal(SIGQUIT, onquit);
555a248b 238#ifdef notdef
415c8aef
BJ
239 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
240 signal(SIGTERM, onterm);
555a248b 241#endif
415c8aef
BJ
242 if (strcmp(usefile, "-") == 0) {
243 if (cflag == 0) {
555a248b 244 fprintf(stderr,
095da6e7 245 "tar: can only create standard output archives\n");
415c8aef
BJ
246 done(1);
247 }
ed4dfcb6
KD
248 vfile = stderr;
249 setlinebuf(vfile);
415c8aef 250 mt = dup(1);
555a248b 251 } else if ((mt = open(usefile, 2)) < 0) {
415c8aef 252 if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) {
555a248b
BJ
253 fprintf(stderr,
254 "tar: cannot open %s\n", usefile);
415c8aef
BJ
255 done(1);
256 }
257 }
415c8aef 258 dorep(argv);
555a248b 259 done(0);
415c8aef 260 }
555a248b
BJ
261 if (strcmp(usefile, "-") == 0) {
262 mt = dup(0);
555a248b
BJ
263 } else if ((mt = open(usefile, 0)) < 0) {
264 fprintf(stderr, "tar: cannot open %s\n", usefile);
265 done(1);
415c8aef 266 }
555a248b
BJ
267 if (xflag)
268 doxtract(argv);
415c8aef 269 else
555a248b 270 dotable();
415c8aef
BJ
271 done(0);
272}
273
274usage()
275{
555a248b 276 fprintf(stderr,
1e5bf3dc 277"tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
415c8aef
BJ
278 done(1);
279}
280
281dorep(argv)
555a248b 282 char *argv[];
415c8aef
BJ
283{
284 register char *cp, *cp2;
f21b792d 285 char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
415c8aef
BJ
286
287 if (!cflag) {
288 getdir();
289 do {
290 passtape();
291 if (term)
292 done(0);
293 getdir();
294 } while (!endtape());
095da6e7 295 backtape();
415c8aef
BJ
296 if (tfile != NULL) {
297 char buf[200];
298
555a248b
BJ
299 sprintf(buf,
300"sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
415c8aef
BJ
301 tname, tname, tname, tname, tname, tname);
302 fflush(tfile);
303 system(buf);
304 freopen(tname, "r", tfile);
305 fstat(fileno(tfile), &stbuf);
306 high = stbuf.st_size;
307 }
308 }
309
5ee3622a 310 (void) getcwd(wdir);
415c8aef
BJ
311 while (*argv && ! term) {
312 cp2 = *argv;
313 if (!strcmp(cp2, "-C") && argv[1]) {
314 argv++;
315 if (chdir(*argv) < 0)
316 perror(*argv);
317 else
5ee3622a 318 (void) getcwd(wdir);
415c8aef
BJ
319 argv++;
320 continue;
321 }
f21b792d 322 parent = wdir;
415c8aef
BJ
323 for (cp = *argv; *cp; cp++)
324 if (*cp == '/')
325 cp2 = cp;
326 if (cp2 != *argv) {
327 *cp2 = '\0';
f21b792d
SL
328 if (chdir(*argv) < 0) {
329 perror(*argv);
330 continue;
331 }
5ee3622a 332 parent = getcwd(tempdir);
415c8aef
BJ
333 *cp2 = '/';
334 cp2++;
335 }
f21b792d 336 putfile(*argv++, cp2, parent);
3bda777c 337 if (chdir(wdir) < 0) {
1e5bf3dc 338 fprintf(stderr, "cannot change back?: ");
3bda777c
KM
339 perror(wdir);
340 }
415c8aef
BJ
341 }
342 putempty();
343 putempty();
344 flushtape();
555a248b
BJ
345 if (linkerrok == 0)
346 return;
347 for (; ihead != NULL; ihead = ihead->nextp) {
348 if (ihead->count == 0)
349 continue;
095da6e7 350 fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
555a248b 351 }
415c8aef
BJ
352}
353
354endtape()
355{
1e5bf3dc 356 return (dblock.dbuf.name[0] == '\0');
415c8aef
BJ
357}
358
359getdir()
360{
361 register struct stat *sp;
362 int i;
363
654c61ee 364top:
555a248b 365 readtape((char *)&dblock);
415c8aef
BJ
366 if (dblock.dbuf.name[0] == '\0')
367 return;
368 sp = &stbuf;
369 sscanf(dblock.dbuf.mode, "%o", &i);
370 sp->st_mode = i;
371 sscanf(dblock.dbuf.uid, "%o", &i);
372 sp->st_uid = i;
373 sscanf(dblock.dbuf.gid, "%o", &i);
374 sp->st_gid = i;
375 sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
376 sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
377 sscanf(dblock.dbuf.chksum, "%o", &chksum);
654c61ee 378 if (chksum != (i = checksum())) {
095da6e7 379 fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
654c61ee
SL
380 chksum, i);
381 if (iflag)
382 goto top;
415c8aef
BJ
383 done(2);
384 }
385 if (tfile != NULL)
386 fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
387}
388
389passtape()
390{
391 long blocks;
1e5bf3dc 392 char *bufp;
415c8aef
BJ
393
394 if (dblock.dbuf.linkflag == '1')
395 return;
396 blocks = stbuf.st_size;
397 blocks += TBLOCK-1;
398 blocks /= TBLOCK;
399
1e5bf3dc
KD
400 while (blocks-- > 0)
401 readtbuf(&bufp, TBLOCK);
415c8aef
BJ
402}
403
f21b792d 404putfile(longname, shortname, parent)
555a248b
BJ
405 char *longname;
406 char *shortname;
f21b792d 407 char *parent;
415c8aef 408{
1e5bf3dc
KD
409 int infile = 0;
410 long blocks;
415c8aef 411 char buf[TBLOCK];
1e5bf3dc 412 char *origbuf;
1e5bf3dc 413 char *bigbuf;
415c8aef 414 register char *cp, *cp2;
aeb5c9b4
KM
415 struct direct *dp;
416 DIR *dirp;
1e5bf3dc 417 int i, j;
f21b792d 418 char newparent[NAMSIZ+64];
654c61ee 419 extern int errno;
1e5bf3dc
KD
420 int maxread;
421 int hint; /* amount to write to get "in sync" */
415c8aef 422
f21b792d 423 if (!hflag)
654c61ee
SL
424 i = lstat(shortname, &stbuf);
425 else
426 i = stat(shortname, &stbuf);
427 if (i < 0) {
428 switch (errno) {
429 case EACCES:
430 fprintf(stderr, "tar: %s: cannot open file\n", longname);
431 break;
432 case ENOENT:
433 fprintf(stderr, "tar: %s: no such file or directory\n",
434 longname);
435 break;
436 default:
437 fprintf(stderr, "tar: %s: cannot stat file\n", longname);
438 break;
439 }
f21b792d
SL
440 return;
441 }
654c61ee 442 if (tfile != NULL && checkupdate(longname) == 0)
415c8aef 443 return;
654c61ee
SL
444 if (checkw('r', longname) == 0)
445 return;
446 if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
415c8aef 447 return;
415c8aef 448
654c61ee
SL
449 switch (stbuf.st_mode & S_IFMT) {
450 case S_IFDIR:
555a248b
BJ
451 for (i = 0, cp = buf; *cp++ = longname[i++];)
452 ;
415c8aef
BJ
453 *--cp = '/';
454 *++cp = 0 ;
415c8aef 455 if (!oflag) {
555a248b 456 if ((cp - buf) >= NAMSIZ) {
095da6e7
SL
457 fprintf(stderr, "tar: %s: file name too long\n",
458 longname);
555a248b
BJ
459 return;
460 }
461 stbuf.st_size = 0;
462 tomodes(&stbuf);
463 strcpy(dblock.dbuf.name,buf);
464 sprintf(dblock.dbuf.chksum, "%6o", checksum());
465 writetape((char *)&dblock);
415c8aef 466 }
f21b792d 467 sprintf(newparent, "%s/%s", parent, shortname);
3bda777c
KM
468 if (chdir(shortname) < 0) {
469 perror(shortname);
470 return;
471 }
aeb5c9b4 472 if ((dirp = opendir(".")) == NULL) {
095da6e7
SL
473 fprintf(stderr, "tar: %s: directory read error\n",
474 longname);
3bda777c 475 if (chdir(parent) < 0) {
1e5bf3dc 476 fprintf(stderr, "cannot change back?: ");
3bda777c
KM
477 perror(parent);
478 }
aeb5c9b4
KM
479 return;
480 }
481 while ((dp = readdir(dirp)) != NULL && !term) {
482 if (dp->d_ino == 0)
415c8aef 483 continue;
555a248b
BJ
484 if (!strcmp(".", dp->d_name) ||
485 !strcmp("..", dp->d_name))
415c8aef 486 continue;
aeb5c9b4
KM
487 strcpy(cp, dp->d_name);
488 i = telldir(dirp);
489 closedir(dirp);
f21b792d 490 putfile(buf, cp, newparent);
aeb5c9b4
KM
491 dirp = opendir(".");
492 seekdir(dirp, i);
415c8aef 493 }
aeb5c9b4 494 closedir(dirp);
3bda777c 495 if (chdir(parent) < 0) {
1e5bf3dc 496 fprintf(stderr, "cannot change back?: ");
3bda777c
KM
497 perror(parent);
498 }
654c61ee
SL
499 break;
500
501 case S_IFLNK:
502 tomodes(&stbuf);
503 if (strlen(longname) >= NAMSIZ) {
095da6e7
SL
504 fprintf(stderr, "tar: %s: file name too long\n",
505 longname);
654c61ee
SL
506 return;
507 }
508 strcpy(dblock.dbuf.name, longname);
555a248b 509 if (stbuf.st_size + 1 >= NAMSIZ) {
095da6e7
SL
510 fprintf(stderr, "tar: %s: symbolic link too long\n",
511 longname);
555a248b
BJ
512 return;
513 }
f21b792d 514 i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
555a248b 515 if (i < 0) {
f21b792d 516 perror(longname);
555a248b
BJ
517 return;
518 }
519 dblock.dbuf.linkname[i] = '\0';
520 dblock.dbuf.linkflag = '2';
521 if (vflag) {
ed4dfcb6
KD
522 fprintf(vfile, "a %s ", longname);
523 fprintf(vfile, "symbolic link to %s\n",
095da6e7 524 dblock.dbuf.linkname);
555a248b
BJ
525 }
526 sprintf(dblock.dbuf.size, "%11lo", 0);
527 sprintf(dblock.dbuf.chksum, "%6o", checksum());
528 writetape((char *)&dblock);
654c61ee
SL
529 break;
530
531 case S_IFREG:
532 if ((infile = open(shortname, 0)) < 0) {
533 fprintf(stderr, "tar: %s: cannot open file\n", longname);
415c8aef
BJ
534 return;
535 }
654c61ee
SL
536 tomodes(&stbuf);
537 if (strlen(longname) >= NAMSIZ) {
095da6e7
SL
538 fprintf(stderr, "tar: %s: file name too long\n",
539 longname);
1e5bf3dc 540 close(infile);
654c61ee
SL
541 return;
542 }
543 strcpy(dblock.dbuf.name, longname);
544 if (stbuf.st_nlink > 1) {
545 struct linkbuf *lp;
546 int found = 0;
547
548 for (lp = ihead; lp != NULL; lp = lp->nextp)
549 if (lp->inum == stbuf.st_ino &&
550 lp->devnum == stbuf.st_dev) {
551 found++;
552 break;
553 }
554 if (found) {
555 strcpy(dblock.dbuf.linkname, lp->pathname);
556 dblock.dbuf.linkflag = '1';
557 sprintf(dblock.dbuf.chksum, "%6o", checksum());
1e5bf3dc 558 writetape( (char *) &dblock);
654c61ee 559 if (vflag) {
ed4dfcb6
KD
560 fprintf(vfile, "a %s ", longname);
561 fprintf(vfile, "link to %s\n",
095da6e7 562 lp->pathname);
654c61ee
SL
563 }
564 lp->count--;
565 close(infile);
566 return;
567 }
568 lp = (struct linkbuf *) malloc(sizeof(*lp));
569 if (lp == NULL) {
570 if (freemem) {
571 fprintf(stderr,
095da6e7 572 "tar: out of memory, link information lost\n");
654c61ee
SL
573 freemem = 0;
574 }
575 } else {
576 lp->nextp = ihead;
577 ihead = lp;
578 lp->inum = stbuf.st_ino;
579 lp->devnum = stbuf.st_dev;
580 lp->count = stbuf.st_nlink - 1;
581 strcpy(lp->pathname, longname);
415c8aef
BJ
582 }
583 }
1e5bf3dc 584 blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
654c61ee 585 if (vflag) {
ed4dfcb6
KD
586 fprintf(vfile, "a %s ", longname);
587 fprintf(vfile, "%ld blocks\n", blocks);
654c61ee
SL
588 }
589 sprintf(dblock.dbuf.chksum, "%6o", checksum());
1e5bf3dc
KD
590 hint = writetape((char *)&dblock);
591 maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
1e5bf3dc
KD
592 if ((bigbuf = malloc(maxread)) == 0) {
593 maxread = TBLOCK;
594 bigbuf = buf;
595 }
415c8aef 596
1e5bf3dc
KD
597 while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
598 && blocks > 0) {
599 register int nblks;
600
601 nblks = ((i-1)/TBLOCK)+1;
602 if (nblks > blocks)
603 nblks = blocks;
604 hint = writetbuf(bigbuf, nblks);
605 blocks -= nblks;
654c61ee 606 }
1e5bf3dc
KD
607 close(infile);
608 if (bigbuf != buf)
1e5bf3dc 609 free(bigbuf);
1e5bf3dc 610 if (blocks != 0 || i != 0)
095da6e7
SL
611 fprintf(stderr, "tar: %s: file changed size\n",
612 longname);
654c61ee
SL
613 while (--blocks >= 0)
614 putempty();
615 break;
616
617 default:
618 fprintf(stderr, "tar: %s is not a file. Not dumped\n",
095da6e7 619 longname);
654c61ee 620 break;
415c8aef 621 }
415c8aef
BJ
622}
623
415c8aef 624doxtract(argv)
555a248b 625 char *argv[];
415c8aef
BJ
626{
627 long blocks, bytes;
415c8aef
BJ
628 char **cp;
629 int ofile;
630
631 for (;;) {
632 getdir();
633 if (endtape())
634 break;
415c8aef
BJ
635 if (*argv == 0)
636 goto gotit;
415c8aef
BJ
637 for (cp = argv; *cp; cp++)
638 if (prefix(*cp, dblock.dbuf.name))
639 goto gotit;
640 passtape();
641 continue;
642
643gotit:
644 if (checkw('x', dblock.dbuf.name) == 0) {
645 passtape();
646 continue;
647 }
654c61ee
SL
648 if (Fflag) {
649 char *s;
650
651 if ((s = rindex(dblock.dbuf.name, '/')) == 0)
652 s = dblock.dbuf.name;
653 else
654 s++;
655 if (checkf(s, stbuf.st_mode, Fflag) == 0) {
656 passtape();
657 continue;
658 }
659 }
555a248b 660 if (checkdir(dblock.dbuf.name))
415c8aef 661 continue;
555a248b
BJ
662 if (dblock.dbuf.linkflag == '2') {
663 unlink(dblock.dbuf.name);
664 if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
095da6e7
SL
665 fprintf(stderr, "tar: %s: symbolic link failed\n",
666 dblock.dbuf.name);
555a248b
BJ
667 continue;
668 }
669 if (vflag)
ed4dfcb6 670 fprintf(vfile, "x %s symbolic link to %s\n",
095da6e7 671 dblock.dbuf.name, dblock.dbuf.linkname);
75115c46
KD
672#ifdef notdef
673 /* ignore alien orders */
674 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
675 if (mflag == 0) {
676 struct timeval tv[2];
677
678 tv[0].tv_sec = time(0);
679 tv[0].tv_usec = 0;
680 tv[1].tv_sec = stbuf.st_mtime;
681 tv[1].tv_usec = 0;
682 utimes(dblock.dbuf.name, tv);
683 }
684 if (pflag)
685 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
686#endif
555a248b
BJ
687 continue;
688 }
415c8aef
BJ
689 if (dblock.dbuf.linkflag == '1') {
690 unlink(dblock.dbuf.name);
691 if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
095da6e7
SL
692 fprintf(stderr, "tar: %s: cannot link\n",
693 dblock.dbuf.name);
415c8aef
BJ
694 continue;
695 }
696 if (vflag)
75115c46 697 fprintf(vfile, "%s linked to %s",
095da6e7 698 dblock.dbuf.name, dblock.dbuf.linkname);
415c8aef
BJ
699 continue;
700 }
555a248b
BJ
701 if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
702 fprintf(stderr, "tar: %s - cannot create\n",
095da6e7 703 dblock.dbuf.name);
415c8aef
BJ
704 passtape();
705 continue;
706 }
1e5bf3dc 707 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
415c8aef
BJ
708 blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
709 if (vflag)
75115c46 710 fprintf(vfile, "x %s, %ld bytes, %ld tape blocks",
095da6e7 711 dblock.dbuf.name, bytes, blocks);
1e5bf3dc
KD
712 for (; blocks > 0;) {
713 register int nread;
714 char *bufp;
715 register int nwant;
716
717 nwant = NBLOCK*TBLOCK;
718 if (nwant > (blocks*TBLOCK))
719 nwant = (blocks*TBLOCK);
720 nread = readtbuf(&bufp, nwant);
721 if (bytes > nread) {
722 if (write(ofile, bufp, nread) < 0) {
723 fprintf(stderr,
724 "tar: %s: HELP - extract write error\n",
725 dblock.dbuf.name);
726 done(2);
727 }
728 } else if (write(ofile, bufp, (int) bytes) < 0) {
555a248b 729 fprintf(stderr,
095da6e7
SL
730 "tar: %s: HELP - extract write error\n",
731 dblock.dbuf.name);
555a248b
BJ
732 done(2);
733 }
1e5bf3dc
KD
734 bytes -= nread;
735 blocks -= (((nread-1)/TBLOCK)+1);
75115c46 736 fprintf(stderr,"\n");
415c8aef
BJ
737 }
738 close(ofile);
739 if (mflag == 0) {
828d5b76 740 struct timeval tv[2];
415c8aef 741
828d5b76
SL
742 tv[0].tv_sec = time(0);
743 tv[0].tv_usec = 0;
744 tv[1].tv_sec = stbuf.st_mtime;
745 tv[1].tv_usec = 0;
746 utimes(dblock.dbuf.name, tv);
415c8aef 747 }
cd2661db 748 if (pflag)
555a248b 749 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
415c8aef
BJ
750 }
751}
752
753dotable()
754{
755 for (;;) {
756 getdir();
757 if (endtape())
758 break;
759 if (vflag)
760 longt(&stbuf);
761 printf("%s", dblock.dbuf.name);
762 if (dblock.dbuf.linkflag == '1')
763 printf(" linked to %s", dblock.dbuf.linkname);
555a248b
BJ
764 if (dblock.dbuf.linkflag == '2')
765 printf(" symbolic link to %s", dblock.dbuf.linkname);
415c8aef
BJ
766 printf("\n");
767 passtape();
768 }
769}
770
771putempty()
772{
773 char buf[TBLOCK];
415c8aef 774
095da6e7 775 bzero(buf, sizeof (buf));
415c8aef
BJ
776 writetape(buf);
777}
778
779longt(st)
555a248b 780 register struct stat *st;
415c8aef
BJ
781{
782 register char *cp;
783 char *ctime();
784
785 pmode(st);
786 printf("%3d/%1d", st->st_uid, st->st_gid);
787 printf("%7D", st->st_size);
788 cp = ctime(&st->st_mtime);
789 printf(" %-12.12s %-4.4s ", cp+4, cp+20);
790}
791
792#define SUID 04000
793#define SGID 02000
794#define ROWN 0400
795#define WOWN 0200
796#define XOWN 0100
797#define RGRP 040
798#define WGRP 020
799#define XGRP 010
800#define ROTH 04
801#define WOTH 02
802#define XOTH 01
803#define STXT 01000
804int m1[] = { 1, ROWN, 'r', '-' };
805int m2[] = { 1, WOWN, 'w', '-' };
806int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
807int m4[] = { 1, RGRP, 'r', '-' };
808int m5[] = { 1, WGRP, 'w', '-' };
809int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
810int m7[] = { 1, ROTH, 'r', '-' };
811int m8[] = { 1, WOTH, 'w', '-' };
812int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
813
814int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
815
816pmode(st)
555a248b 817 register struct stat *st;
415c8aef
BJ
818{
819 register int **mp;
820
821 for (mp = &m[0]; mp < &m[9];)
822 select(*mp++, st);
823}
824
825select(pairp, st)
555a248b
BJ
826 int *pairp;
827 struct stat *st;
415c8aef
BJ
828{
829 register int n, *ap;
830
831 ap = pairp;
832 n = *ap++;
833 while (--n>=0 && (st->st_mode&*ap++)==0)
834 ap++;
835 printf("%c", *ap);
836}
837
838checkdir(name)
555a248b 839 register char *name;
415c8aef
BJ
840{
841 register char *cp;
555a248b 842
654c61ee
SL
843 /*
844 * Quick check for existance of directory.
845 */
846 if ((cp = rindex(name, '/')) == 0)
847 return (0);
848 *cp = '\0';
849 if (access(name, 0) >= 0) {
850 *cp = '/';
851 return (cp[1] == '\0');
852 }
853 *cp = '/';
854
855 /*
856 * No luck, try to make all directories in path.
857 */
415c8aef 858 for (cp = name; *cp; cp++) {
555a248b
BJ
859 if (*cp != '/')
860 continue;
861 *cp = '\0';
654c61ee 862 if (access(name, 0) < 0) {
13fc8845
SL
863 if (mkdir(name, 0777) < 0) {
864 perror(name);
654c61ee
SL
865 *cp = '/';
866 return (0);
415c8aef 867 }
1e5bf3dc 868 chown(name, stbuf.st_uid, stbuf.st_gid);
07269bf2 869 if (pflag && cp[1] == '\0')
13fc8845 870 chmod(name, stbuf.st_mode & 0777);
415c8aef 871 }
555a248b 872 *cp = '/';
415c8aef 873 }
555a248b 874 return (cp[-1]=='/');
415c8aef
BJ
875}
876
877onintr()
878{
879 signal(SIGINT, SIG_IGN);
880 term++;
881}
882
883onquit()
884{
885 signal(SIGQUIT, SIG_IGN);
886 term++;
887}
888
889onhup()
890{
891 signal(SIGHUP, SIG_IGN);
892 term++;
893}
894
895onterm()
896{
897 signal(SIGTERM, SIG_IGN);
898 term++;
899}
900
901tomodes(sp)
902register struct stat *sp;
903{
904 register char *cp;
905
906 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
907 *cp = '\0';
908 sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
909 sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
910 sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
911 sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
912 sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
913}
914
915checksum()
916{
917 register i;
918 register char *cp;
919
555a248b
BJ
920 for (cp = dblock.dbuf.chksum;
921 cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
415c8aef
BJ
922 *cp = ' ';
923 i = 0;
924 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
925 i += *cp;
555a248b 926 return (i);
415c8aef
BJ
927}
928
929checkw(c, name)
555a248b 930 char *name;
415c8aef 931{
555a248b
BJ
932 if (!wflag)
933 return (1);
934 printf("%c ", c);
935 if (vflag)
936 longt(&stbuf);
937 printf("%s: ", name);
938 return (response() == 'y');
415c8aef
BJ
939}
940
941response()
942{
943 char c;
944
945 c = getchar();
946 if (c != '\n')
555a248b
BJ
947 while (getchar() != '\n')
948 ;
949 else
950 c = 'n';
951 return (c);
415c8aef
BJ
952}
953
654c61ee
SL
954checkf(name, mode, howmuch)
955 char *name;
956 int mode, howmuch;
957{
958 int l;
959
ed4dfcb6
KD
960 if ((mode & S_IFMT) == S_IFDIR){
961 if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
962 return(0);
963 return(1);
964 }
654c61ee
SL
965 if ((l = strlen(name)) < 3)
966 return (1);
967 if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
968 return (0);
969 if (strcmp(name, "core") == 0 ||
970 strcmp(name, "errs") == 0 ||
971 (howmuch > 1 && strcmp(name, "a.out") == 0))
972 return (0);
973 /* SHOULD CHECK IF IT IS EXECUTABLE */
974 return (1);
975}
976
415c8aef 977checkupdate(arg)
555a248b 978 char *arg;
415c8aef
BJ
979{
980 char name[100];
555a248b 981 long mtime;
415c8aef
BJ
982 daddr_t seekp;
983 daddr_t lookup();
984
985 rewind(tfile);
986 for (;;) {
987 if ((seekp = lookup(arg)) < 0)
555a248b 988 return (1);
415c8aef
BJ
989 fseek(tfile, seekp, 0);
990 fscanf(tfile, "%s %lo", name, &mtime);
555a248b 991 return (stbuf.st_mtime > mtime);
415c8aef
BJ
992 }
993}
994
995done(n)
996{
1e5bf3dc 997 unlink(tname);
415c8aef
BJ
998 exit(n);
999}
1000
1001prefix(s1, s2)
555a248b 1002 register char *s1, *s2;
415c8aef
BJ
1003{
1004 while (*s1)
1005 if (*s1++ != *s2++)
555a248b 1006 return (0);
415c8aef 1007 if (*s2)
555a248b
BJ
1008 return (*s2 == '/');
1009 return (1);
415c8aef
BJ
1010}
1011
415c8aef
BJ
1012#define N 200
1013int njab;
555a248b 1014
415c8aef
BJ
1015daddr_t
1016lookup(s)
555a248b 1017 char *s;
415c8aef
BJ
1018{
1019 register i;
1020 daddr_t a;
1021
1022 for(i=0; s[i]; i++)
555a248b 1023 if (s[i] == ' ')
415c8aef
BJ
1024 break;
1025 a = bsrch(s, i, low, high);
555a248b 1026 return (a);
415c8aef
BJ
1027}
1028
1029daddr_t
1030bsrch(s, n, l, h)
555a248b
BJ
1031 daddr_t l, h;
1032 char *s;
415c8aef
BJ
1033{
1034 register i, j;
1035 char b[N];
1036 daddr_t m, m1;
1037
1038 njab = 0;
1039
1040loop:
555a248b
BJ
1041 if (l >= h)
1042 return (-1L);
415c8aef 1043 m = l + (h-l)/2 - N/2;
555a248b 1044 if (m < l)
415c8aef
BJ
1045 m = l;
1046 fseek(tfile, m, 0);
1047 fread(b, 1, N, tfile);
1048 njab++;
1049 for(i=0; i<N; i++) {
555a248b 1050 if (b[i] == '\n')
415c8aef
BJ
1051 break;
1052 m++;
1053 }
555a248b
BJ
1054 if (m >= h)
1055 return (-1L);
415c8aef
BJ
1056 m1 = m;
1057 j = i;
1058 for(i++; i<N; i++) {
1059 m1++;
555a248b 1060 if (b[i] == '\n')
415c8aef
BJ
1061 break;
1062 }
1063 i = cmp(b+j, s, n);
555a248b 1064 if (i < 0) {
415c8aef
BJ
1065 h = m;
1066 goto loop;
1067 }
555a248b 1068 if (i > 0) {
415c8aef
BJ
1069 l = m1;
1070 goto loop;
1071 }
555a248b 1072 return (m);
415c8aef
BJ
1073}
1074
1075cmp(b, s, n)
555a248b 1076 char *b, *s;
415c8aef
BJ
1077{
1078 register i;
1079
555a248b 1080 if (b[0] != '\n')
1e5bf3dc 1081 exit(2);
415c8aef 1082 for(i=0; i<n; i++) {
555a248b
BJ
1083 if (b[i+1] > s[i])
1084 return (-1);
1085 if (b[i+1] < s[i])
1086 return (1);
415c8aef 1087 }
555a248b 1088 return (b[i+1] == ' '? 0 : -1);
415c8aef
BJ
1089}
1090
1e5bf3dc 1091readtape (buffer)
555a248b 1092 char *buffer;
1e5bf3dc
KD
1093{
1094 char *bufp;
1095 int nread;
1096
ed4dfcb6 1097 if (first==0) getbuf();
1e5bf3dc
KD
1098 readtbuf (&bufp, TBLOCK);
1099 bcopy(bufp, buffer, TBLOCK);
1100 return(TBLOCK);
1101}
1102
1103readtbuf(bufpp, size)
1104 char **bufpp;
1105 int size;
415c8aef 1106{
06eff236 1107 register int i;
415c8aef
BJ
1108
1109 if (recno >= nblock || first == 0) {
8678ae71 1110 if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
095da6e7 1111 fprintf(stderr, "tar: tape read error\n");
415c8aef
BJ
1112 done(3);
1113 }
1114 if (first == 0) {
1115 if ((i % TBLOCK) != 0) {
095da6e7 1116 fprintf(stderr, "tar: tape blocksize error\n");
415c8aef
BJ
1117 done(3);
1118 }
1119 i /= TBLOCK;
06eff236 1120 if (i != nblock) {
095da6e7 1121 fprintf(stderr, "tar: blocksize = %d\n", i);
415c8aef
BJ
1122 nblock = i;
1123 }
75115c46 1124 first = 1;
415c8aef
BJ
1125 }
1126 recno = 0;
1127 }
1e5bf3dc
KD
1128 if (size > ((nblock-recno)*TBLOCK))
1129 size = (nblock-recno)*TBLOCK;
1130 *bufpp = (char *)&tbuf[recno];
1131 recno += (size/TBLOCK);
1132 return (size);
415c8aef
BJ
1133}
1134
1e5bf3dc
KD
1135writetbuf(buffer, n)
1136 register char *buffer;
1137 register int n;
415c8aef 1138{
75115c46
KD
1139 int i;
1140 if (first==0) {
1141 getbuf();
1142 first = 1;
1143 }
415c8aef 1144 if (recno >= nblock) {
75115c46
KD
1145 if ( write(mt, tbuf, TBLOCK*nblock) < 0) {
1146 perror("tar");
415c8aef
BJ
1147 done(2);
1148 }
1149 recno = 0;
1150 }
1e5bf3dc
KD
1151
1152 /*
1153 * Special case: We have an empty tape buffer, and the
1154 * users data size is >= the tape block size: Avoid
1155 * the bcopy and dma direct to tape. BIG WIN. Add the
1156 * residual to the tape buffer.
1157 */
1158 while (recno == 0 && n >= nblock) {
1159 if (write(mt, buffer, TBLOCK*nblock) < 0) {
75115c46 1160 perror("tar");
415c8aef
BJ
1161 done(2);
1162 }
1e5bf3dc
KD
1163 n -= nblock;
1164 buffer += (nblock * TBLOCK);
415c8aef 1165 }
1e5bf3dc
KD
1166
1167 while (n-- > 0) {
1168 bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1169 buffer += TBLOCK;
1170 if (recno >= nblock) {
1171 if (write(mt, tbuf, TBLOCK*nblock) < 0) {
75115c46
KD
1172 fprintf(stderr,"tar: tape write error\n");
1173 done(2);
1e5bf3dc
KD
1174 }
1175 recno = 0;
1176 }
1177 }
1178
1179 /* Tell the user how much to write to get in sync */
1180 return (nblock - recno);
415c8aef
BJ
1181}
1182
1183backtape()
1184{
06eff236
BJ
1185 static struct mtop mtop = {MTBSR, 1};
1186 struct mtget mtget;
1187
06eff236
BJ
1188 if (mtdev == 0) {
1189 if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
095da6e7 1190 fprintf(stderr, "tar: tape backspace error\n");
415c8aef
BJ
1191 done(4);
1192 }
06eff236
BJ
1193 } else
1194 lseek(mt, (long) -TBLOCK*nblock, 1);
1195 recno--;
415c8aef
BJ
1196}
1197
1198flushtape()
1199{
1e5bf3dc 1200 write(mt, tbuf, TBLOCK*nblock);
415c8aef
BJ
1201}
1202
8678ae71
KM
1203bread(fd, buf, size)
1204 int fd;
1205 char *buf;
1206 int size;
1207{
1208 int count;
75115c46 1209 int i;
8678ae71
KM
1210 static int lastread = 0;
1211
75115c46
KD
1212 if (!Bflag) {
1213 return (read(fd, buf, size));
1214 }
1215
1216
8678ae71
KM
1217 for (count = 0; count < size; count += lastread) {
1218 if (lastread < 0) {
1219 if (count > 0)
1220 return (count);
1221 return (lastread);
1222 }
1223 lastread = read(fd, buf, size - count);
1224 buf += lastread;
1225 }
1226 return (count);
1227}
5ee3622a
SL
1228
1229char *
1230getcwd(buf)
1231 char *buf;
1232{
5ee3622a
SL
1233 if (getwd(buf) == NULL) {
1234 fprintf(stderr, "tar: %s\n", buf);
1e5bf3dc 1235 exit(1);
5ee3622a
SL
1236 }
1237 return (buf);
1238}
ed4dfcb6
KD
1239
1240getbuf()
1241{
75115c46
KD
1242 struct mtget mtget;
1243
ed4dfcb6
KD
1244 if ( mtdev == 1) {
1245 fstat(mt, &stbuf);
1246 if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1247 mtdev = 0;
1248 else
1249 mtdev = -1;
1250 }
75115c46 1251 if (nblock==0) {
ed4dfcb6
KD
1252 if (mtdev == 0)
1253 nblock = FILEBLOCK;
1254 else {
1255 fstat(mt, &stbuf);
1256 nblock = stbuf.st_blocks / TBLOCK;
1257 }
1258 }
75115c46 1259 if (nblock == 0) nblock = FILEBLOCK;
ed4dfcb6
KD
1260 tbuf = (union hblock *)malloc(nblock*TBLOCK);
1261 if (tbuf == NULL) {
1262 fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1263 nblock);
1264 done(1);
1265 }
1266}
75115c46
KD
1267
1268
1269chgreel(x, fl)
1270 int x, fl;
1271{
1272 register int f;
1273 char str[BUFSIZ];
1274 char *pstr;
1275 FILE *devtty;
1276 struct stat statb;
1277
1278 perror("tar");
1279 fprintf(stderr, "Can't %s\n", x ? "write output": "read input");
1280 fstat(fl, &statb);
1281 if ((statb.st_mode & S_IFMT) != S_IFCHR)
1282 done(2);
1283
1284 close(fl);
1285 devtty = fopen("/dev/tty", "r");
1286 for (;;) {
1287 fprintf(stderr, "tar: If you want to go on, type \"yes\" or a new\npathname of a device/file name when you are ready\n");
1288 if (fgets(str, sizeof (str), devtty) == NULL)
1289 break;
1290 str[strlen(str) - 1] = '\0';
1291
1292 switch (*str) {
1293 case '\0':
1294 case 'N':
1295 case 'n':
1296 goto done;
1297
1298 case 'Y':
1299 case 'y':
1300 case '\n':
1301 pstr = usefile;
1302 break;
1303
1304 default:
1305 pstr = str;
1306 }
1307 if ((f = open(pstr, x ? 1 : 0)) >= 0) {
1308 fclose(devtty);
1309 return (f);
1310 }
1311 fprintf(stderr, "tar: open of %s failed\n", pstr);
1312 }
1313done:
1314 fclose(devtty);
1315 return (-1);
1316}