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