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