Commit | Line | Data |
---|---|---|
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 | |
9 | char 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 | 15 | static 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 |
48 | union 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 | |
63 | struct linkbuf { | |
64 | ino_t inum; | |
65 | dev_t devnum; | |
66 | int count; | |
67 | char pathname[NAMSIZ]; | |
68 | struct linkbuf *nextp; | |
555a248b BJ |
69 | }; |
70 | ||
71 | union hblock dblock; | |
095da6e7 | 72 | union hblock *tbuf; |
555a248b BJ |
73 | struct linkbuf *ihead; |
74 | struct stat stbuf; | |
75 | ||
76 | int rflag; | |
8b5119c0 | 77 | int sflag; |
555a248b BJ |
78 | int xflag; |
79 | int vflag; | |
80 | int tflag; | |
81 | int cflag; | |
82 | int mflag; | |
83 | int fflag; | |
654c61ee | 84 | int iflag; |
555a248b BJ |
85 | int oflag; |
86 | int pflag; | |
87 | int wflag; | |
88 | int hflag; | |
1c8f2f3c | 89 | int Hflag; |
8678ae71 | 90 | int Bflag; |
654c61ee | 91 | int Fflag; |
555a248b BJ |
92 | |
93 | int mt; | |
94 | int term; | |
95 | int chksum; | |
96 | int recno; | |
45a92ce3 JL |
97 | int first; |
98 | int prtlinkerr; | |
415c8aef | 99 | int freemem = 1; |
75115c46 | 100 | int nblock = 0; |
bb09bb86 | 101 | void onintr(), onquit(), onhup(); |
45a92ce3 | 102 | #ifdef notdef |
bb09bb86 | 103 | void onterm(); |
45a92ce3 | 104 | #endif |
415c8aef BJ |
105 | |
106 | daddr_t low; | |
107 | daddr_t high; | |
555a248b | 108 | daddr_t bsrch(); |
415c8aef | 109 | |
ed4dfcb6 | 110 | FILE *vfile = stdout; |
415c8aef | 111 | FILE *tfile; |
53eb5063 | 112 | char tname[] = _PATH_TMP; |
415c8aef | 113 | char *usefile; |
53eb5063 | 114 | char magtape[] = _PATH_MAGTAPE; |
bb09bb86 | 115 | char *cwd(); |
45a92ce3 | 116 | char *getmem(); |
415c8aef | 117 | |
af4fde50 KB |
118 | extern int errno; |
119 | ||
415c8aef | 120 | main(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 | ||
281 | usage() | |
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 |
288 | int |
289 | openmt(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 | 329 | dorep(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 | ||
407 | endtape() | |
408 | { | |
1e5bf3dc | 409 | return (dblock.dbuf.name[0] == '\0'); |
415c8aef BJ |
410 | } |
411 | ||
412 | getdir() | |
413 | { | |
414 | register struct stat *sp; | |
c243f257 | 415 | long tempquad; |
415c8aef BJ |
416 | int i; |
417 | ||
654c61ee | 418 | top: |
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 | ||
452 | passtape() | |
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 | 467 | putfile(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 | 671 | doxtract(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 |
793 | dotable(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 | ||
815 | putempty() | |
816 | { | |
817 | char buf[TBLOCK]; | |
415c8aef | 818 | |
095da6e7 | 819 | bzero(buf, sizeof (buf)); |
9c11b20b | 820 | (void) writetape(buf); |
415c8aef BJ |
821 | } |
822 | ||
823 | longt(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 | |
848 | int m1[] = { 1, ROWN, 'r', '-' }; | |
849 | int m2[] = { 1, WOWN, 'w', '-' }; | |
850 | int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; | |
851 | int m4[] = { 1, RGRP, 'r', '-' }; | |
852 | int m5[] = { 1, WGRP, 'w', '-' }; | |
853 | int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; | |
854 | int m7[] = { 1, ROTH, 'r', '-' }; | |
855 | int m8[] = { 1, WOTH, 'w', '-' }; | |
856 | int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; | |
857 | ||
858 | int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; | |
859 | ||
860 | pmode(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 | 869 | selectbits(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 | 887 | checkdir(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 | 927 | void |
415c8aef BJ |
928 | onintr() |
929 | { | |
9c11b20b | 930 | (void) signal(SIGINT, SIG_IGN); |
415c8aef BJ |
931 | term++; |
932 | } | |
933 | ||
bb09bb86 | 934 | void |
415c8aef BJ |
935 | onquit() |
936 | { | |
9c11b20b | 937 | (void) signal(SIGQUIT, SIG_IGN); |
415c8aef BJ |
938 | term++; |
939 | } | |
940 | ||
bb09bb86 | 941 | void |
415c8aef BJ |
942 | onhup() |
943 | { | |
9c11b20b | 944 | (void) signal(SIGHUP, SIG_IGN); |
415c8aef BJ |
945 | term++; |
946 | } | |
947 | ||
45a92ce3 | 948 | #ifdef notdef |
bb09bb86 | 949 | void |
415c8aef BJ |
950 | onterm() |
951 | { | |
9c11b20b | 952 | (void) signal(SIGTERM, SIG_IGN); |
415c8aef BJ |
953 | term++; |
954 | } | |
45a92ce3 | 955 | #endif |
415c8aef BJ |
956 | |
957 | tomodes(sp) | |
958 | register 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 | ||
971 | checksum() | |
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 | ||
985 | checkw(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 | ||
997 | response() | |
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 |
1010 | checkf(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 | 1034 | checkupdate(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 | ||
1052 | done(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 | */ | |
1062 | wantit(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 | 1082 | prefix(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 |
1094 | int njab; | |
555a248b | 1095 | |
415c8aef BJ |
1096 | daddr_t |
1097 | lookup(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 | ||
1110 | daddr_t | |
1111 | bsrch(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 | ||
1121 | loop: | |
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 | ||
1156 | cmp(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 | 1172 | readtape(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 | ||
1184 | readtbuf(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 |
1214 | writetbuf(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 | ||
1260 | backtape() | |
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 | ||
1279 | flushtape() | |
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 | ||
1288 | mterr(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 |
1297 | bread(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 | |
1320 | char * | |
bb09bb86 | 1321 | cwd() |
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 | |
1333 | getbuf() | |
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 | */ | |
1371 | char dirstack[NAMSIZ]; | |
1372 | #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ | |
1373 | time_t mtime[NTIM]; | |
75115c46 | 1374 | |
45a92ce3 JL |
1375 | dodirtimes(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 |
1415 | setimes(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 | ||
1429 | char * | |
1430 | getmem(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 | } |