|
|
1.1 root 1: /*
2: * Tape archive
3: * tar [0-7bcflmrtuvwx]+ [blocks] [archive] pathname*
4: */
5:
6: #include <stdio.h>
7: #include <sys/types.h>
8: #include <errno.h>
9: #include <canon.h>
10: #include <sys/stat.h>
11: #include <sys/dir.h>
12:
13: #define S_PERM 07777 /* should be in stat.h */
14:
15: /* Possible actions for do_checksum_error(). */
16: #define CLEAR 0 /* Print all pending messages. */
17: #define ADD 1 /* Add another pending message. */
18:
19: #define MAXBLK 20
20: #define roundup(n, r) (((n)+(r)-1)/(r))
21:
22: typedef struct dirhd_t {
23: dev_t t_dev;
24: ino_t t_ino;
25: unsigned short t_nlink,
26: t_mode,
27: t_uid,
28: t_gid;
29: fsize_t t_size;
30: time_t t_mtime;
31: char *t_name;
32: struct dirhd_t *t_cont[];
33: } dirhd_t;
34:
35: typedef union tarhd_t {
36: struct {
37: char th_name[100],
38: th_mode[8],
39: th_uid[8],
40: th_gid[8],
41: th_size[12],
42: th_mtime[12],
43: th_check[8],
44: th_islink,
45: th_link[100],
46: th_pad[255];
47: } th_info;
48: char th_data[BUFSIZ];
49: } tarhd_t;
50:
51: typedef unsigned short flag_t; /* fastest type for machine */
52:
53: flag_t linkmsg = 0, /* message if not all links found */
54: modtime = 1, /* restore modtimes */
55: verbose = 0;
56: unixbug = 0; /* avoid bug in U**X tar */
57: FILE *whether = (FILE *)NULL, /* ask about each file */
58: *tarfile;
59: char tapedev[10] = '\0';
60: char *archive = &tapedev[0];
61: unsigned short blocking = 1; /* blocking factor */
62: time_t oldtime[2], /* for utime */
63: recently, /* set to 6 months ago for tv key */
64: time();
65:
66: dirhd_t *newdirhd(),
67: *update(),
68: *research();
69: tarhd_t *readhdr(),
70: *readblk(),
71: *writeblk();
72: char *havelink();
73: long getoctl();
74: extern char *malloc();
75: extern char *ctime();
76:
77: main(argc, argv)
78: int argc;
79: char *argv[];
80: {
81: char *key,
82: unit = '\0',
83: function = 0,
84: deffunc,
85: prefix[101] = '\0';
86: unsigned short arg = 2;
87: dirhd_t *args;
88:
89: if (argc < 2) {
90: fprintf(stderr,
91: "Usage: %s [crtux][0-7bflmvw] [blocks] [archive] pathname*\n",
92: argv[0]);
93: exit(-1);
94: }
95: for (key = argv[1]; *key != '\0'; key++) switch (*key) {
96: case '0':
97: case '1':
98: case '2':
99: case '3':
100: case '4':
101: case '5':
102: case '6':
103: case '7':
104: unit = *key;
105: deffunc = 't';
106: continue;
107: case 'b':
108: if (argc <= arg)
109: fatal("missing blocking factor");
110: else if ((blocking = atoi(argv[arg++])) <= 0
111: || blocking > MAXBLK)
112: fatal("illegal blocking factor");
113: deffunc = 'r';
114: continue;
115: case 'f':
116: if (argc <= arg)
117: fatal("missing archive name");
118: else
119: archive = argv[arg++];
120: deffunc = 't';
121: continue;
122: case 'l':
123: linkmsg = 1;
124: deffunc = 'r';
125: continue;
126: case 'm':
127: modtime = 0;
128: deffunc = 'x';
129: continue;
130: case 'v':
131: verbose = 1;
132: deffunc = 't';
133: continue;
134: case 'U':
135: unixbug = 1;
136: deffunc = 't';
137: continue;
138: case 'w':
139: whether = fopen("/dev/tty", "r+w");
140: deffunc = 'x';
141: continue;
142: case 'c':
143: case 'r':
144: case 't':
145: case 'u':
146: case 'x':
147: if (function)
148: fatal("keys c, r, t, u, x are mutually exclusive");
149: else
150: function = *key;
151: continue;
152: default:
153: fatal("illegal key '%c'", *key);
154: }
155: if (!function)
156: function = deffunc;
157: oldtime[0] = time((time_t *)0);
158: if (verbose && function=='t')
159: recently = oldtime[0] - 6*((time_t)30*24*60*60);
160:
161: /* construct descriptors for args given */
162:
163: args = (dirhd_t *) malloc(sizeof (dirhd_t)
164: + (argc-arg)*sizeof (dirhd_t *));
165: if (args == NULL)
166: fatal("out of memory");
167: args->t_mode = S_IFDIR;
168: args->t_nlink = 0;
169: for (; arg < argc; arg++) {
170: dirhd_t *argp;
171:
172: if ((argp = newdirhd(argv[arg], strlen(argv[arg]))) == NULL)
173: fprintf(stderr, "Tar: %s: out of memory\n", argv[arg]);
174: else
175: args->t_cont[args->t_nlink++] = argp;
176: }
177:
178: /* open archive file */
179:
180: if (*archive == '\0')
181: sprintf(archive, "/dev/%smt%c", blocking==1 ? "" : "r", unit);
182: if (function=='t' || function=='x')
183: if (strcmp(archive, "-")==0)
184: tarfile = stdin;
185: else
186: tarfile = fopen(archive, "r");
187: else if (function=='c')
188: if (strcmp(archive, "-")==0)
189: tarfile = stdout;
190: else
191: tarfile = fopen(archive, "w");
192: else
193: tarfile = fopen(archive, "r+w");
194: if (tarfile==NULL) {
195: exit(perror("Tar: 1: %s", archive));
196: }
197: setbuf(tarfile, NULL);
198:
199: /* perform required function */
200:
201: switch (function) {
202: case 't':
203: table(args);
204: break;
205: case 'x':
206: extract(args);
207: break;
208: case 'r':
209: while (readblk() != NULL)
210: ;
211: goto doappend;
212: case 'u':
213: if ((args = update(prefix, args, readhdr())) == NULL)
214: break;
215: case 'c':
216: doappend:
217: append(prefix, args);
218: flushtar();
219: }
220: /* Flush any remaining checksum messages. */
221: do_checksum_error(NULL, CLEAR);
222:
223: exit(errno);
224: }
225:
226: fatal(args)
227: char *args;
228: {
229: /* Flush any remaining checksum messages. */
230: do_checksum_error(NULL, CLEAR);
231:
232: fprintf(stderr, "tar: %r\n", &args);
233: exit(-1);
234: }
235:
236: dirhd_t *
237: newdirhd(name, len)
238: register char *name;
239: unsigned short len;
240: {
241: register dirhd_t *dp;
242:
243: if ((dp = (dirhd_t *) malloc(sizeof (dirhd_t))) != NULL
244: && (dp->t_name = malloc(len+1)) == NULL) {
245: free(dp);
246: dp = NULL;
247: }
248: if (dp != NULL) {
249: dp->t_nlink = 0;
250: strncpy(dp->t_name, name, len);
251: dp->t_name[len] = '\0';
252: }
253: return (dp);
254: }
255: int
256: perror(args)
257: char *args;
258: {
259: register int err;
260:
261: if ((err=errno) >= sys_nerr)
262: fprintf(stderr, "%r: Bad error number\n", &args);
263: else if (err)
264: fprintf(stderr, "%r: %s\n", &args, sys_errlist[err]);
265: return (err);
266: }
267:
268: table(args)
269: register dirhd_t *args;
270: {
271: register tarhd_t *header;
272:
273: for (; (header = readhdr()) != NULL; skipfile(header)) {
274: if (argcont(args, header->th_info.th_name, 0) < 0)
275: continue;
276: if (verbose) {
277: register unsigned short mode = getoct(header->th_info.th_mode);
278: unsigned short uid = getoct(header->th_info.th_uid),
279: gid = getoct(header->th_info.th_gid);
280: fsize_t size = getoctl(header->th_info.th_size);
281: time_t mtime = getoctl(header->th_info.th_mtime);
282: char *timestr = ctime(&mtime);
283:
284: if (header->th_info.th_name[strnlen(header->th_info.th_name, 100)-1]
285: == '/')
286: putchar('d');
287: else
288: putchar('-');
289: printf("%c%c%c",
290: mode&S_IREAD ? 'r' : '-',
291: mode&S_IWRITE ? 'w' : '-',
292: mode&S_ISUID ? 's' :
293: mode&S_IEXEC ? 'x' : '-');
294: printf("%c%c%c",
295: mode&S_IREAD>>3 ? 'r' : '-',
296: mode&S_IWRITE>>3 ? 'w' : '-',
297: mode&S_ISGID ? 's' :
298: mode&S_IEXEC>>3 ? 'x' : '-');
299: printf("%c%c%c",
300: mode&S_IREAD>>6 ? 'r' : '-',
301: mode&S_IWRITE>>6 ? 'w' : '-',
302: mode&S_ISVTX ? 't' :
303: mode&S_IEXEC>>6 ? 'x' : '-');
304: printf("%3d %3d %6ld %.11s%.5s ",
305: gid,
306: uid,
307: size,
308: timestr,
309: mtime > recently ? timestr+11 : timestr+19);
310: }
311: printf("%.100s", header->th_info.th_name);
312: if (header->th_info.th_islink)
313: if (verbose)
314: printf("\n%33s link to %s\n", "",
315: header->th_info.th_link);
316: else
317: printf(" link to %s\n", header->th_info.th_link);
318: else
319: putchar('\n');
320: }
321: }
322:
323: extract(args)
324: register dirhd_t *args;
325: {
326: register tarhd_t *header;
327: short skipping = 0;
328:
329: while ((header = readhdr()) != NULL) {
330: register char name[101];
331: unsigned short namelen = strnlen(header->th_info.th_name, 100),
332: mode,
333: uid,
334: gid;
335:
336: if (!skipping || contains(name, header->th_info.th_name) >= 0) {
337: strncpy(name, header->th_info.th_name, namelen);
338: name[namelen--] = '\0';
339: if ((skipping = argcont(args, name, 0)) >= 0)
340: skipping = disallow('x', name);
341: }
342: switch (skipping) {
343: case -1:
344: skipping = 0;
345: case 1:
346: skipfile(header);
347: continue;
348: }
349: if (verbose)
350: printf("x %s\n", name);
351: mode = getoct(header->th_info.th_mode);
352: uid = getoct(header->th_info.th_uid);
353: gid = getoct(header->th_info.th_gid);
354: oldtime[1] = getoctl(header->th_info.th_mtime);
355: if (name[namelen] == '/') {
356: name[namelen] = '\0';
357: makepath(name);
358: chmod(name, mode);
359: name[namelen] = '/';
360: } else if (header->th_info.th_islink == '\0') {
361: int fd = recreate(name, mode);
362: fsize_t size = getoctl(header->th_info.th_size);
363:
364: for (; size > 0; size -= sizeof (tarhd_t)) {
365: int my_size;
366:
367: /* Handle unexpected EOF - mods by [email protected] */
368: if ((header = readblk()) == NULL) {
369: fprintf(stderr,
370: "Unexpected end of the file %s\n",
371: name);
372: break;
373: }
374: if (size > sizeof(tarhd_t))
375: my_size = sizeof(tarhd_t);
376: else
377: my_size = (int) size;
378: if (fd >= 0 && (write(fd, header->th_data,
379: my_size) != my_size))
380:
381: perror("Tar: 2: %s", name);
382: }
383: if (fd >= 0)
384: close(fd);
385: } else {
386: struct stat statbuf;
387: flag_t xlink = 1;
388:
389: if (stat(header->th_info.th_link, &statbuf) < 0)
390: close(recreate(header->th_info.th_link, mode));
391: else if (havelink(statbuf.st_dev, statbuf.st_ino, 0)
392: != NULL)
393: xlink = 0;
394: if (xlink)
395: fprintf(stderr, "Tar: Must extract %s\n",
396: header->th_info.th_link);
397: unlink(name);
398: mkparent(name);
399: if (link(header->th_info.th_link, name) < 0)
400: fprintf(stderr, "Tar: Can't link %s to %s\n",
401: name, header->th_info.th_link);
402: }
403: if (modtime)
404: utime(name, oldtime);
405: chown(name, uid, gid);
406: }
407: }
408:
409: dirhd_t *
410: update(name, args, header)
411: char *name;
412: register dirhd_t *args;
413: tarhd_t *header;
414: {
415: unsigned short namelen = strlen(name);
416: flag_t donedir = 0;
417:
418: if (header == NULL)
419: return (args);
420: if (args->t_nlink == 0 && (args = research(name, args)) == NULL)
421: return (NULL);
422: do switch (args->t_mode&S_IFMT) {
423: register short arg;
424: register dirhd_t *argp;
425:
426: case S_IFREG:
427: if (args->t_mtime <= getoctl(header->th_info.th_mtime))
428: args->t_nlink = 0;
429: skipfile(header);
430: continue;
431: case S_IFDIR:
432: if (namelen != 0 && !donedir) {
433: name[namelen] = '/';
434: donedir++;
435: }
436: if ((arg = argcont(args, header->th_info.th_name+namelen+donedir, -1))
437: >= 0) {
438: strcpy(name+namelen+donedir,
439: (argp=args->t_cont[arg])->t_name);
440: if ((args->t_cont[arg] = update(name, argp, header))
441: == NULL)
442: args->t_cont[arg]
443: = args->t_cont[--args->t_nlink];
444: } else
445: skipfile(header);
446: name[namelen+donedir] = '\0';
447: } while ((header=readhdr()) != NULL
448: && contains(name, header->th_info.th_name));
449: if (header != NULL)
450: ungetblk();
451: if (args->t_nlink == 0) {
452: if (namelen != 0)
453: free(args->t_name);
454: free((char *) args);
455: return (NULL);
456: } else
457: return (args);
458: }
459:
460: append(name, args)
461: char *name;
462: register dirhd_t *args;
463: {
464: unsigned short namelen;
465: register unsigned short arg;
466: register dirhd_t *argp;
467:
468: if ((namelen = strlen(name)) != 0 && disallow('a', name))
469: return;
470: if (args->t_nlink == 0 && (args = research(name, args)) == NULL)
471: return;
472: switch (args->t_mode&S_IFMT) {
473: case S_IFDIR:
474: if (namelen != 0) {
475: name[namelen++] = '/'; name[namelen] = '\0';
476: writehdr(name, args, "");
477: }
478: for (arg = 0; arg < args->t_nlink; arg++) {
479: strcpy(name+namelen, (argp=args->t_cont[arg])->t_name);
480: append(name, argp);
481: }
482: break;
483: case S_IFREG:
484: if (args->t_nlink != 1) {
485: char *link;
486:
487: if ((link=havelink(args->t_dev,
488: args->t_ino, 1))!=NULL) {
489: writehdr(name, args, link);
490: break;
491: } else {
492: filelink(args->t_dev,
493: args->t_ino,
494: args->t_nlink,
495: name);
496: }
497: }
498: writehdr(name, args, "");
499: writefil(name, args->t_size);
500: }
501: if (namelen != 0)
502: free(args->t_name);
503: free((char *) args);
504: }
505:
506: dirhd_t *
507: research(name, args)
508: char *name;
509: register dirhd_t *args;
510: {
511: unsigned short namelen;
512: register short nfile;
513: int fd;
514: struct stat statbuf;
515:
516: if ((namelen = strlen(name)) == 0)
517: name = ".";
518: if (stat(name, &statbuf) < 0) {
519: perror("Tar: 3: %s", name);
520: return (args);
521: }
522: args->t_dev = statbuf.st_dev;
523: args->t_ino = statbuf.st_ino;
524: args->t_nlink = statbuf.st_nlink;
525: args->t_uid = statbuf.st_uid;
526: args->t_gid = statbuf.st_gid;
527: args->t_mtime = statbuf.st_mtime;
528: switch ((args->t_mode = statbuf.st_mode)&S_IFMT) {
529: case S_IFREG:
530: args->t_size = statbuf.st_size;
531: return (args);
532: default:
533: args->t_size = 0;
534: return (args);
535: case S_IFDIR:
536: args->t_size = 0;
537: }
538: if ((nfile = (short) (statbuf.st_size/sizeof (struct direct))) > 2) {
539: args = (dirhd_t *) realloc((char *)args,
540: sizeof (dirhd_t) + (nfile-2)*sizeof (dirhd_t *));
541: if (args == NULL) {
542: fprintf(stderr, "Tar: %s: out of memory\n", name);
543: return (NULL);
544: }
545: }
546: args->t_nlink = 0;
547: if ((fd = open(name, 0)) < 0) {
548: perror("Tar: 4: %s", name);
549: return (args);
550: }
551: for (; nfile > 0; --nfile) {
552: struct direct dir_ent;
553: unsigned short arglen;
554: dirhd_t *argp;
555:
556: switch (read(fd, (char *)&dir_ent, sizeof (struct direct))) {
557: case -1:
558: perror("Tar: 5: %s", name);
559: case 0:
560: break;
561: default:
562: if (dir_ent.d_ino == 0
563: || strcmp(dir_ent.d_name, ".") == 0
564: || strcmp(dir_ent.d_name, "..") == 0)
565: continue;
566: else if ((arglen=strnlen(dir_ent.d_name, DIRSIZ))
567: + namelen > 99)
568: fprintf(stderr,
569: "Tar: %s/%.*s: name too long\n",
570: name, DIRSIZ, dir_ent.d_name);
571: else if ((argp = newdirhd(dir_ent.d_name, arglen))
572: == NULL)
573: fprintf(stderr,
574: "Tar: %s/%.*s: out of memory\n",
575: name, DIRSIZ, dir_ent.d_name);
576: else
577: args->t_cont[args->t_nlink++] = argp;
578: continue;
579: }
580: break;
581: }
582: close(fd);
583: return (args);
584: }
585:
586: int
587: argcont(args, name, ret)
588: register dirhd_t *args;
589: char *name;
590: int ret;
591: {
592: register unsigned short arg;
593:
594: if (args->t_nlink == 0)
595: return (ret);
596: else for (arg = 0; arg < args->t_nlink; arg++)
597: if (contains(args->t_cont[arg]->t_name, name))
598: return (arg);
599: return (-1);
600: }
601:
602: int
603: strnlen(str, maxlen)
604: register char *str;
605: register unsigned short maxlen;
606: {
607: register unsigned short len = 0;
608:
609: while (maxlen && *str++ != '\0') {
610: --maxlen; ++len;
611: }
612: return (len);
613: }
614:
615: /*
616: * Create file system paths
617: */
618:
619: int
620: makepath(pathname)
621: char *pathname;
622: {
623: struct stat statbuf;
624: register int err;
625:
626: if (stat(pathname, &statbuf) == 0)
627: if ((statbuf.st_mode&S_IFMT) == S_IFDIR)
628: return (0);
629: else
630: errno = ENOTDIR;
631: else if (errno == ENOENT) {
632: errno = 0;
633: if ((err=mkparent(pathname)) != 0)
634: return err;
635: return mkdir(pathname);
636: }
637: return (perror("Tar: 6: %s", pathname));
638: }
639:
640: int
641: mkparent(pathname)
642: register char *pathname;
643: {
644: register char *pathend = &pathname[strlen(pathname)];
645:
646: while (pathend > pathname && *--pathend != '/')
647: ;
648: if (pathend > pathname) {
649: *pathend = '\0';
650: errno = makepath(pathname);
651: *pathend = '/';
652: } else
653: errno = 0;
654: return (errno);
655: }
656:
657: mkdir(pathname)
658: char *pathname;
659: {
660: int status;
661:
662: switch(fork()) {
663: case -1:
664: break;
665: case 0:
666: close(2);
667: execl("/bin/mkdir", "mkdir", pathname, NULL);
668: exit(errno);
669: default:
670: wait(&status);
671: errno = status>>8;
672: }
673: return (perror("Tar: 7: %s", pathname));
674: }
675:
676: int
677: recreate(pathname, mode)
678: char *pathname;
679: unsigned short mode;
680: {
681: int fd;
682:
683: if ((fd = create(pathname, mode)) < 0
684: && (errno != ENOENT
685: || mkparent(pathname) == 0 && (fd = create(pathname, mode)) < 0))
686: perror("Tar: 8: %s", pathname);
687: errno = 0;
688: return (fd);
689: }
690:
691: int
692: create(pathname, mode)
693: char *pathname;
694: unsigned short mode;
695: {
696: int fd;
697:
698: unlink(pathname);
699: if ((fd = creat(pathname, mode)) >= 0) {
700: struct stat statbuf;
701:
702: fstat(fd, &statbuf);
703: filelink(statbuf.st_dev, statbuf.st_ino,
704: statbuf.st_nlink, pathname);
705: }
706: return (fd);
707: }
708:
709: /*
710: * Ask about current action
711: */
712:
713: int
714: disallow(function, pathname)
715: char function,
716: *pathname;
717: {
718: while (whether) {
719: register int c1,
720: c;
721:
722: fprintf(whether, "%c %s? ", function, pathname);
723: for (c1=c=getc(whether); c!=EOF && c!='\n'; c=getc(whether))
724: ;
725: switch (c1) {
726: case EOF:
727: case 'x':
728: if (function == 'a')
729: flushtar();
730: exit(errno);
731: case '\n':
732: case 'n':
733: case 'N':
734: return (1);
735: case 'y':
736: case 'Y':
737: return (0);
738: }
739: }
740: return (0);
741: }
742:
743: /*
744: * High level I/O routines
745: */
746:
747: tarhd_t *
748: readhdr()
749: {
750: register tarhd_t *header;
751:
752: while ((header = readblk()) != NULL) {
753: if (header->th_info.th_name[0] == '\0')
754: if (unixbug) {
755: ungetblk();
756: return (NULL);
757: } else
758: continue;
759: else {
760: int check = getoct(header->th_info.th_check);
761:
762: strncpy(header->th_info.th_check, " ",
763: sizeof(header->th_info.th_check));
764: if (checksum(header->th_data, sizeof(tarhd_t)) != check){
765: do_checksum_error(header->th_info.th_name, ADD);
766: } else {
767: do_checksum_error(NULL, CLEAR);
768: break;
769: }
770: }
771: }
772: /* We shouldn't have to check EVERY header, but if we do it here
773: * it gets done for every routine.
774: * Newer tar programs use the first eight bytes of the
775: * pad field as magic to indicate the type of archive.
776: * With old tar archives, these eight characters should be
777: * NUL. We'll only check the first one.
778: */
779: /* Check to see if this is a v7 style tar archive. */
780: if ((char)0 != header->th_info.th_pad[0]) {
781: fatal("%.8s archive, not v7 archive.",
782: header->th_info.th_pad);
783:
784: }
785: return (header);
786: }
787:
788: skipfile(header)
789: tarhd_t *header;
790: {
791: register fsize_t size;
792:
793: if (header->th_info.th_islink)
794: return;
795: for (size = getoctl(header->th_info.th_size);
796: size > 0 && readblk() != NULL;
797: size -= sizeof (tarhd_t))
798: ;
799: }
800:
801: writehdr(name, args, link)
802: char *name;
803: register dirhd_t *args;
804: char *link;
805: {
806: register tarhd_t *header = writeblk();
807:
808: if (verbose)
809: fprintf(stderr, "a %s", name);
810: strncpy(header->th_info.th_name, name, sizeof(header->th_info.th_name));
811: putoct(header->th_info.th_mode, args->t_mode&S_PERM);
812: putoct(header->th_info.th_uid, args->t_uid);
813: putoct(header->th_info.th_gid, args->t_gid);
814: putoctl(header->th_info.th_size, args->t_size);
815: putoctl(header->th_info.th_mtime, args->t_mtime);
816: strncpy(header->th_info.th_check, " ", sizeof(header->th_info.th_check));
817: if (*link == '\0') {
818: header->th_info.th_islink = 0;
819: if (verbose)
820: if (args->t_size == 0)
821: putc('\n', stderr);
822: else
823: fprintf(stderr, " %ld block%s\n",
824: roundup(args->t_size, BUFSIZ),
825: args->t_size <= BUFSIZ ? "" : "s");
826: } else {
827: header->th_info.th_islink = '1';
828: if (verbose)
829: fprintf(stderr, " link to %s\n", link);
830: }
831: strncpy(header->th_info.th_link, link, sizeof(header->th_info.th_link));
832: strncpy(header->th_info.th_pad, "", sizeof(header->th_info.th_pad));
833: putoct(header->th_info.th_check, checksum(header->th_data, sizeof(tarhd_t)));
834: }
835:
836: writefil(name, size)
837: char *name;
838: register fsize_t size;
839: {
840: int fd;
841: register tarhd_t *header;
842:
843: if ((fd = open(name, 0)) < 0) {
844: perror("Tar: 9: %s", name);
845: }
846: for (; size > 0; size -= sizeof (tarhd_t)) {
847: header = writeblk();
848: if (fd >= 0)
849: read(fd, header->th_data, sizeof (tarhd_t));
850: else
851: strncpy(header->th_data, "", sizeof (tarhd_t));
852: }
853: if (fd >= 0)
854: close(fd);
855: }
856:
857: /*
858: * Tape I/O, with record blocking if specified
859: */
860:
861: tarhd_t buffer[MAXBLK],
862: *current = &buffer[0];
863:
864: tarhd_t *
865: readblk()
866: {
867: static unsigned short blocks = 0;
868:
869: if (feof(tarfile))
870: return (NULL);
871: if (current == &buffer[blocks]) {
872: current = &buffer[0];
873: blocks = fread((char *) buffer,
874: sizeof (tarhd_t), MAXBLK, tarfile);
875: if (ferror(tarfile)) {
876: exit(perror("Tar: 10: %s", archive));
877: } else if (feof(tarfile)) {
878: /* This is a hack. We should actually find
879: * out why returning NULL is not good enough.
880: *
881: * Really a pain without a symbolic debugger!
882: */
883: exit(0);
884: }
885: }
886: return (current++);
887: }
888:
889: ungetblk()
890: {
891: --current;
892: }
893:
894: tarhd_t *
895: writeblk()
896: {
897: if (current == &buffer[blocking]) {
898: current = &buffer[0];
899: fwrite((char *)buffer, sizeof (tarhd_t), blocking, tarfile);
900: if (ferror(tarfile) || feof(tarfile)) {
901: exit(perror("Tar: 11: %s", archive));
902: }
903: }
904: return (current++);
905: }
906:
907: flushtar()
908: {
909: register tarhd_t *header;
910:
911: while ((header=writeblk()) != &buffer[0])
912: strncpy(header->th_data, "", sizeof (tarhd_t));
913: if (linkmsg)
914: misslink();
915: }
916:
917: /*
918: * Keep track of files by ino in hash table
919: */
920:
921: typedef struct link_t {
922: dev_t t_dev;
923: ino_t t_ino;
924: unsigned short t_nlink;
925: struct link_t *t_next;
926: char t_link[];
927: } link_t;
928:
929: #define NHASH 64
930:
931: link_t *linklist[NHASH];
932:
933: filelink(dev, ino, nlink, link)
934: dev_t dev;
935: ino_t ino;
936: unsigned short nlink;
937: char *link;
938: {
939: unsigned short id = ino%NHASH;
940: register link_t *lp;
941:
942: lp = (link_t *) malloc(sizeof (link_t) + strlen(link) + 1);
943: if (lp == NULL)
944: fprintf(stderr, "Tar: %s: note: link info lost\n", link);
945: else {
946: lp->t_next = linklist[id];
947: linklist[id] = lp;
948: lp->t_dev = dev;
949: lp->t_ino = ino;
950: lp->t_nlink = nlink;
951: strcpy(lp->t_link, link);
952: }
953: }
954:
955: char *
956: havelink(dev, ino, flag)
957: dev_t dev;
958: ino_t ino;
959: flag_t flag;
960: {
961: register link_t *lp;
962:
963: for (lp = linklist[ino%NHASH]; lp != NULL; lp = lp->t_next) {
964: if (lp->t_ino == ino && lp->t_dev == dev) {
965: if (flag)
966: --lp->t_nlink;
967: return (lp->t_link);
968: }
969: }
970: return (NULL);
971: }
972:
973: misslink()
974: {
975: unsigned short ino;
976:
977: for (ino = 0; ino < NHASH; ino++) {
978: register link_t *lp;
979:
980: for (lp = linklist[ino]; lp != NULL; lp=lp->t_next) {
981: register short nlink;
982:
983: if (nlink = lp->t_nlink - 1)
984: fprintf(stderr,
985: "Tar: missed %d link%s to %s\n",
986: nlink, nlink==1 ? "" : "s",
987: lp->t_link);
988: }
989: }
990: }
991:
992: /*
993: * Read unsigned octal numbers
994: */
995:
996: int
997: getoct(cp)
998: register char *cp;
999: {
1000: register int val = 0;
1001: register char c;
1002:
1003: while (*cp == ' ')
1004: cp++;
1005: while ((c = *cp++ - '0') >= 0 && c <= 7)
1006: val = val<<3 | c;
1007: return (val);
1008: }
1009:
1010: long
1011: getoctl(cp)
1012: register char *cp;
1013: {
1014: register long val = 0;
1015: register char c;
1016:
1017: while (*cp==' ')
1018: cp++;
1019: while ((c = *cp++ - '0') >= 0 && c <= 7)
1020: val = val<<3 | c;
1021: return (val);
1022: }
1023:
1024: /*
1025: * Write unsigned octal numbers
1026: * in fixed format
1027: */
1028:
1029: putoct(str, val)
1030: char *str;
1031: unsigned short val;
1032: {
1033: register char *cp;
1034:
1035: *(cp = &str[7]) = '\0';
1036: *--cp = ' ';
1037: *--cp = (val&07) + '0';
1038: while (cp != str)
1039: *--cp = (val>>=3) ? (val&07) + '0' : ' ';
1040: }
1041:
1042: putoctl(str, val)
1043: char *str;
1044: register unsigned long val;
1045: {
1046: register char *cp;
1047:
1048: *(cp = &str[11]) = ' ';
1049: *--cp = (val&07) + '0';
1050: while (cp != str)
1051: *--cp = (val>>=3) ? (val&07) + '0' : ' ';
1052: }
1053:
1054: /*
1055: * Compute checksum of string
1056: */
1057: int
1058: checksum(str, len)
1059: register char *str;
1060: register int len;
1061: {
1062: register int check = 0;
1063:
1064: if (len) do
1065: check += *str++;
1066: while (--len);
1067: return (check);
1068: }
1069:
1070: /*
1071: * Return -1 if dname is a directory prefix of fname
1072: * 0 if no match
1073: * 1 if complete match
1074: */
1075: int
1076: contains(dname, fname)
1077: register char *dname,
1078: *fname;
1079: {
1080: if (*dname=='\0')
1081: return (-1);
1082: while (*dname!='\0')
1083: if (*dname++ != *fname++)
1084: return (0);
1085: if (*fname=='\0')
1086: return (1);
1087: else if (*fname=='/' || *--fname=='/')
1088: return (-1);
1089: else
1090: return (0);
1091: }
1092:
1093: /* Handle the processing of a checksum error.
1094: * This is special because sometimes end of archive will look like
1095: * a lot of checksum errors.
1096: */
1097: int
1098: do_checksum_error(name, action)
1099: char *name;
1100: int action;
1101: {
1102: #define MSG_SIZE (100 + sizeof("Tar: %.100s: bad checksum\n") + 1)
1103: #define MAX_CHECKERR 5 /* Give up after 5 consecutive checksum errors. */
1104:
1105: static error_count = 0; /* Number of checksums we've seen. */
1106: static char *msg_list = NULL; /* Error message we've queued. */
1107: char tmp_buf[MSG_SIZE]; /* Someplace to build new errors. */
1108:
1109:
1110: switch (action) {
1111: case ADD:
1112: /* If there have been too many checksum errors, or if
1113: * we can't allocate more memory for more error messages,
1114: * throw away the existing messages, and look for another
1115: * valid block.
1116: */
1117: if (++error_count > MAX_CHECKERR ||
1118: (msg_list = (char *)realloc(msg_list,
1119: strlen(msg_list) + MSG_SIZE +1)) ==
1120: NULL) {
1121: fprintf(stderr,
1122: "Tar: %s: This doesn't look like a tar archive.\n",
1123: archive);
1124: free(msg_list);
1125: msg_list = 0;
1126: error_count = 0;
1127: fprintf(stderr, "Tar: Scanning for next file.\n");
1128: scan_for_next();
1129: }
1130:
1131: sprintf(tmp_buf, "Tar: %.100s: bad checksum\n",
1132: name);
1133: strcat(msg_list, tmp_buf);
1134: break;
1135: case CLEAR:
1136: if (NULL != msg_list) {
1137: fprintf(stderr, "%s", msg_list);
1138: free(msg_list);
1139: msg_list = NULL;
1140: }
1141: error_count = 0;
1142: break;
1143: } /* switch (action) */
1144: } /* do_checksum_error() */
1145:
1146: /* Find the next valid block. */
1147: int
1148: scan_for_next()
1149: {
1150: int check;
1151: tarhd_t *header;
1152:
1153: while ( (header = readblk()) != NULL ) {
1154: check = getoct(header->th_info.th_check);
1155:
1156: strncpy(header->th_info.th_check, " ",
1157: sizeof(header->th_info.th_check));
1158: if (checksum(header->th_data, sizeof(tarhd_t)) == check){
1159: /* Found a good header! */
1160: ungetblk();
1161: return;
1162: }
1163: } /* while (more blocks to read) */
1164: /* If we got here, it means we ran out of things to read. */
1165: fatal("no more valid blocks");
1166:
1167: } /* scan_for_next() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.