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