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