From 36a773b362b4182e2540dbd11127d73b10e2e685 Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Thu, 3 Jan 1980 02:43:44 -0800 Subject: [PATCH] BSD 3 development Work on file usr/src/cmd/tar.c Synthesized-from: 3bsd --- usr/src/cmd/tar.c | 950 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 950 insertions(+) create mode 100644 usr/src/cmd/tar.c diff --git a/usr/src/cmd/tar.c b/usr/src/cmd/tar.c new file mode 100644 index 0000000000..60329bf9c8 --- /dev/null +++ b/usr/src/cmd/tar.c @@ -0,0 +1,950 @@ +#include +#include +#include +#include +#include + +char *sprintf(); +char *strcat(); +daddr_t bsrch(); +#define TBLOCK 512 +#define NBLOCK 20 +#define NAMSIZ 100 +union hblock { + char dummy[TBLOCK]; + struct header { + char name[NAMSIZ]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[NAMSIZ]; + } dbuf; +} dblock, tbuf[NBLOCK]; + +struct linkbuf { + ino_t inum; + dev_t devnum; + int count; + char pathname[NAMSIZ]; + struct linkbuf *nextp; +} *ihead; + +struct stat stbuf; + +int rflag, xflag, vflag, tflag, mt, cflag, mflag, fflag; +int term, chksum, wflag, recno, first, linkerrok; +int freemem = 1; +int nblock = 1; + +daddr_t low; +daddr_t high; + +FILE *tfile; +char tname[] = "/tmp/tarXXXXXX"; + + +char *usefile; +char magtape[] = "/dev/mt1"; + +char *malloc(); + +main(argc, argv) +int argc; +char *argv[]; +{ + char *cp; + int onintr(), onquit(), onhup(), onterm(); + + if (argc < 2) + usage(); + + tfile = NULL; + usefile = magtape; + argv[argc] = 0; + argv++; + for (cp = *argv++; *cp; cp++) + switch(*cp) { + case 'f': + usefile = *argv++; + fflag++; + if (nblock == 1) + nblock = 0; + break; + case 'c': + cflag++; + rflag++; + break; + case 'u': + mktemp(tname); + if ((tfile = fopen(tname, "w")) == NULL) { + fprintf(stderr, "Tar: cannot create temporary file (%s)\n", tname); + done(1); + } + fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); + /* FALL THROUGH */ + case 'r': + rflag++; +noupdate: + if (nblock != 1 && cflag == 0) { + fprintf(stderr, "Tar: Blocked tapes cannot be updated (yet)\n"); + done(1); + } + break; + case 'v': + vflag++; + break; + case 'w': + wflag++; + break; + case 'x': + xflag++; + break; + case 't': + tflag++; + break; + case 'm': + mflag++; + break; + case '-': + break; + case '0': + case '1': + case '4': + case '5': + case '7': + case '8': + magtape[7] = *cp; + usefile = magtape; + break; + case 'b': + nblock = atoi(*argv++); + if (nblock > NBLOCK || nblock <= 0) { + fprintf(stderr, "Invalid blocksize. (Max %d)\n", NBLOCK); + done(1); + } + if (rflag && !cflag) + goto noupdate; + break; + case 'l': + linkerrok++; + break; + default: + fprintf(stderr, "tar: %c: unknown option\n", *cp); + usage(); + } + + if (rflag) { + if (cflag && tfile != NULL) { + usage(); + done(1); + } + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, onhup); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) + signal(SIGQUIT, onquit); +/* + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, onterm); +*/ + if (strcmp(usefile, "-") == 0) { + if (cflag == 0) { + fprintf(stderr, "Can only create standard output archives\n"); + done(1); + } + mt = dup(1); + nblock = 1; + } + else if ((mt = open(usefile, 2)) < 0) { + if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { + fprintf(stderr, "tar: cannot open %s\n", usefile); + done(1); + } + } + if (cflag == 0 && nblock == 0) + nblock = 1; + dorep(argv); + } + else if (xflag) { + if (strcmp(usefile, "-") == 0) { + mt = dup(0); + nblock = 1; + } + else if ((mt = open(usefile, 0)) < 0) { + fprintf(stderr, "tar: cannot open %s\n", usefile); + done(1); + } + doxtract(argv); + } + else if (tflag) { + if (strcmp(usefile, "-") == 0) { + mt = dup(0); + nblock = 1; + } + else if ((mt = open(usefile, 0)) < 0) { + fprintf(stderr, "tar: cannot open %s\n", usefile); + done(1); + } + dotable(); + } + else + usage(); + done(0); +} + +usage() +{ + fprintf(stderr, "tar: usage tar -{txru}[cvfblm] [tapefile] [blocksize] file1 file2...\n"); + done(1); +} + +dorep(argv) +char *argv[]; +{ + register char *cp, *cp2; + char wdir[60]; + + if (!cflag) { + getdir(); + do { + passtape(); + if (term) + done(0); + getdir(); + } while (!endtape()); + if (tfile != NULL) { + char buf[200]; + + strcat(buf, "sort +0 -1 +1nr "); + strcat(buf, tname); + strcat(buf, " -o "); + strcat(buf, tname); + sprintf(buf, "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX;mv %sX %s", + tname, tname, tname, tname, tname, tname); + fflush(tfile); + system(buf); + freopen(tname, "r", tfile); + fstat(fileno(tfile), &stbuf); + high = stbuf.st_size; + } + } + + getwdir(wdir); + while (*argv && ! term) { + cp2 = *argv; + if (!strcmp(cp2, "-C") && argv[1]) { + argv++; + if (chdir(*argv) < 0) + perror(*argv); + else + getwdir(wdir); + argv++; + continue; + } + for (cp = *argv; *cp; cp++) + if (*cp == '/') + cp2 = cp; + if (cp2 != *argv) { + *cp2 = '\0'; + chdir(*argv); + *cp2 = '/'; + cp2++; + } + putfile(*argv++, cp2); + chdir(wdir); + } + putempty(); + putempty(); + flushtape(); + if (linkerrok == 1) + for (; ihead != NULL; ihead = ihead->nextp) + if (ihead->count != 0) + fprintf(stderr, "Missing links to %s\n", ihead->pathname); +} + +endtape() +{ + if (dblock.dbuf.name[0] == '\0') { + backtape(); + return(1); + } + else + return(0); +} + +getdir() +{ + register struct stat *sp; + int i; + + readtape( (char *) &dblock); + if (dblock.dbuf.name[0] == '\0') + return; + sp = &stbuf; + sscanf(dblock.dbuf.mode, "%o", &i); + sp->st_mode = i; + sscanf(dblock.dbuf.uid, "%o", &i); + sp->st_uid = i; + sscanf(dblock.dbuf.gid, "%o", &i); + sp->st_gid = i; + sscanf(dblock.dbuf.size, "%lo", &sp->st_size); + sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); + sscanf(dblock.dbuf.chksum, "%o", &chksum); + if (chksum != checksum()) { + fprintf(stderr, "directory checksum error\n"); + done(2); + } + if (tfile != NULL) + fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); +} + +passtape() +{ + long blocks; + char buf[TBLOCK]; + + if (dblock.dbuf.linkflag == '1') + return; + blocks = stbuf.st_size; + blocks += TBLOCK-1; + blocks /= TBLOCK; + + while (blocks-- > 0) + readtape(buf); +} + +putfile(longname, shortname) +char *longname; +char *shortname; +{ + int infile; + long blocks; + char buf[TBLOCK]; + register char *cp, *cp2; + struct direct dbuf; + int i, j; + + infile = open(shortname, 0); + if (infile < 0) { + fprintf(stderr, "tar: %s: cannot open file\n", longname); + return; + } + + fstat(infile, &stbuf); + + if (tfile != NULL && checkupdate(longname) == 0) { + close(infile); + return; + } + if (checkw('r', longname) == 0) { + close(infile); + return; + } + + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + for (i = 0, cp = buf; *cp++ = longname[i++];); + *--cp = '/'; + cp++; + i = 0; + chdir(shortname); + while (read(infile, (char *)&dbuf, sizeof(dbuf)) > 0 && !term) { + if (dbuf.d_ino == 0) { + i++; + continue; + } + if (strcmp(".", dbuf.d_name) == 0 || strcmp("..", dbuf.d_name) == 0) { + i++; + continue; + } + cp2 = cp; + for (j=0; j < DIRSIZ; j++) + *cp2++ = dbuf.d_name[j]; + *cp2 = '\0'; + close(infile); + putfile(buf, cp); + infile = open(".", 0); + i++; + lseek(infile, (long) (sizeof(dbuf) * i), 0); + } + close(infile); + chdir(".."); + return; + } + if ((stbuf.st_mode & S_IFMT) != S_IFREG) { + fprintf(stderr, "tar: %s is not a file. Not dumped\n", longname); + return; + } + + tomodes(&stbuf); + + cp2 = longname; + for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++); + if (i >= NAMSIZ) { + fprintf(stderr, "%s: file name too long\n", longname); + close(infile); + return; + } + + if (stbuf.st_nlink > 1) { + struct linkbuf *lp; + int found = 0; + + for (lp = ihead; lp != NULL; lp = lp->nextp) { + if (lp->inum == stbuf.st_ino && lp->devnum == stbuf.st_dev) { + found++; + break; + } + } + if (found) { + strcpy(dblock.dbuf.linkname, lp->pathname); + dblock.dbuf.linkflag = '1'; + sprintf(dblock.dbuf.chksum, "%6o", checksum()); + writetape( (char *) &dblock); + if (vflag) { + fprintf(stderr, "a %s ", longname); + fprintf(stderr, "link to %s\n", lp->pathname); + } + lp->count--; + close(infile); + return; + } + else { + lp = (struct linkbuf *) malloc(sizeof(*lp)); + if (lp == NULL) { + if (freemem) { + fprintf(stderr, "Out of memory. Link information lost\n"); + freemem = 0; + } + } + else { + lp->nextp = ihead; + ihead = lp; + lp->inum = stbuf.st_ino; + lp->devnum = stbuf.st_dev; + lp->count = stbuf.st_nlink - 1; + strcpy(lp->pathname, longname); + } + } + } + + blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; + if (vflag) { + fprintf(stderr, "a %s ", longname); + fprintf(stderr, "%ld blocks\n", blocks); + } + sprintf(dblock.dbuf.chksum, "%6o", checksum()); + writetape( (char *) &dblock); + + while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { + writetape(buf); + blocks--; + } + close(infile); + if (blocks != 0 || i != 0) + fprintf(stderr, "%s: file changed size\n", longname); + while (blocks-- > 0) + putempty(); +} + + + +doxtract(argv) +char *argv[]; +{ + long blocks, bytes; + char buf[TBLOCK]; + char **cp; + int ofile; + + for (;;) { + getdir(); + if (endtape()) + break; + + if (*argv == 0) + goto gotit; + + for (cp = argv; *cp; cp++) + if (prefix(*cp, dblock.dbuf.name)) + goto gotit; + passtape(); + continue; + +gotit: + if (checkw('x', dblock.dbuf.name) == 0) { + passtape(); + continue; + } + + checkdir(dblock.dbuf.name); + + if (dblock.dbuf.linkflag == '1') { + unlink(dblock.dbuf.name); + if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { + fprintf(stderr, "%s: cannot link\n", dblock.dbuf.name); + continue; + } + if (vflag) + fprintf(stderr, "%s linked to %s\n", dblock.dbuf.name, dblock.dbuf.linkname); + continue; + } + if ((ofile = creat(dblock.dbuf.name, stbuf.st_mode & 07777)) < 0) { + fprintf(stderr, "tar: %s - cannot create\n", dblock.dbuf.name); + passtape(); + continue; + } + + chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); + + blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; + if (vflag) + fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", dblock.dbuf.name, bytes, blocks); + while (blocks-- > 0) { + readtape(buf); + if (bytes > TBLOCK) { + if (write(ofile, buf, TBLOCK) < 0) { + fprintf(stderr, "tar: %s: HELP - extract write error\n", dblock.dbuf.name); + done(2); + } + } else + if (write(ofile, buf, (int) bytes) < 0) { + fprintf(stderr, "tar: %s: HELP - extract write error\n", dblock.dbuf.name); + done(2); + } + bytes -= TBLOCK; + } + close(ofile); + if (mflag == 0) { + time_t timep[2]; + + timep[0] = time(NULL); + timep[1] = stbuf.st_mtime; + utime(dblock.dbuf.name, timep); + } + } +} + +dotable() +{ + for (;;) { + getdir(); + if (endtape()) + break; + if (vflag) + longt(&stbuf); + printf("%s", dblock.dbuf.name); + if (dblock.dbuf.linkflag == '1') + printf(" linked to %s", dblock.dbuf.linkname); + printf("\n"); + passtape(); + } +} + +putempty() +{ + char buf[TBLOCK]; + char *cp; + + for (cp = buf; cp < &buf[TBLOCK]; ) + *cp++ = '\0'; + writetape(buf); +} + +longt(st) +register struct stat *st; +{ + register char *cp; + char *ctime(); + + pmode(st); + printf("%3d/%1d", st->st_uid, st->st_gid); + printf("%7D", st->st_size); + cp = ctime(&st->st_mtime); + printf(" %-12.12s %-4.4s ", cp+4, cp+20); +} + +#define SUID 04000 +#define SGID 02000 +#define ROWN 0400 +#define WOWN 0200 +#define XOWN 0100 +#define RGRP 040 +#define WGRP 020 +#define XGRP 010 +#define ROTH 04 +#define WOTH 02 +#define XOTH 01 +#define STXT 01000 +int m1[] = { 1, ROWN, 'r', '-' }; +int m2[] = { 1, WOWN, 'w', '-' }; +int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; +int m4[] = { 1, RGRP, 'r', '-' }; +int m5[] = { 1, WGRP, 'w', '-' }; +int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; +int m7[] = { 1, ROTH, 'r', '-' }; +int m8[] = { 1, WOTH, 'w', '-' }; +int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; + +int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; + +pmode(st) +register struct stat *st; +{ + register int **mp; + + for (mp = &m[0]; mp < &m[9];) + select(*mp++, st); +} + +select(pairp, st) +int *pairp; +struct stat *st; +{ + register int n, *ap; + + ap = pairp; + n = *ap++; + while (--n>=0 && (st->st_mode&*ap++)==0) + ap++; + printf("%c", *ap); +} + +checkdir(name) +register char *name; +{ + register char *cp; + int i; + for (cp = name; *cp; cp++) { + if (*cp == '/') { + *cp = '\0'; + if (access(name, 01) < 0) { + register int pid, rp; + + if ((pid = fork()) == 0) { + execl("/bin/mkdir", "mkdir", name, 0); + execl("/usr/bin/mkdir", "mkdir", name, 0); + fprintf(stderr, "tar: cannot find mkdir!\n"); + done(0); + } + while ((rp = wait(&i)) >= 0 && rp != pid) + ; + chown(name, stbuf.st_uid, stbuf.st_gid); + } + *cp = '/'; + } + } +} + +onintr() +{ + signal(SIGINT, SIG_IGN); + term++; +} + +onquit() +{ + signal(SIGQUIT, SIG_IGN); + term++; +} + +onhup() +{ + signal(SIGHUP, SIG_IGN); + term++; +} + +onterm() +{ + signal(SIGTERM, SIG_IGN); + term++; +} + +tomodes(sp) +register struct stat *sp; +{ + register char *cp; + + for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) + *cp = '\0'; + sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); + sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); + sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); + sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); + sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); +} + +checksum() +{ + register i; + register char *cp; + + for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) + *cp = ' '; + i = 0; + for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) + i += *cp; + return(i); +} + +checkw(c, name) +char *name; +{ + if (wflag) { + printf("%c ", c); + if (vflag) + longt(&stbuf); + printf("%s: ", name); + if (response() == 'y'){ + return(1); + } + return(0); + } + return(1); +} + +response() +{ + char c; + + c = getchar(); + if (c != '\n') + while (getchar() != '\n'); + else c = 'n'; + return(c); +} + +checkupdate(arg) +char *arg; +{ + char name[100]; + long mtime; + daddr_t seekp; + daddr_t lookup(); + + rewind(tfile); + for (;;) { + if ((seekp = lookup(arg)) < 0) + return(1); + fseek(tfile, seekp, 0); + fscanf(tfile, "%s %lo", name, &mtime); + if (stbuf.st_mtime > mtime) + return(1); + else + return(0); + } +} + +done(n) +{ + unlink(tname); + exit(n); +} + +prefix(s1, s2) +register char *s1, *s2; +{ + while (*s1) + if (*s1++ != *s2++) + return(0); + if (*s2) + return(*s2 == '/'); + return(1); +} + +getwdir(s) +char *s; +{ + int i; + int pipdes[2]; + + pipe(pipdes); + if ((i = fork()) == 0) { + close(1); + dup(pipdes[1]); + execl("/bin/pwd", "pwd", 0); + execl("/usr/bin/pwd", "pwd", 0); + fprintf(stderr, "pwd failed!\n"); + printf("/\n"); + exit(1); + } + while (wait((int *)NULL) != -1) + ; + read(pipdes[0], s, 50); + while(*s != '\n') + s++; + *s = '\0'; + close(pipdes[0]); + close(pipdes[1]); +} + +#define N 200 +int njab; +daddr_t +lookup(s) +char *s; +{ + register i; + daddr_t a; + + for(i=0; s[i]; i++) + if(s[i] == ' ') + break; + a = bsrch(s, i, low, high); + return(a); +} + +daddr_t +bsrch(s, n, l, h) +daddr_t l, h; +char *s; +{ + register i, j; + char b[N]; + daddr_t m, m1; + + njab = 0; + +loop: + if(l >= h) + return(-1L); + m = l + (h-l)/2 - N/2; + if(m < l) + m = l; + fseek(tfile, m, 0); + fread(b, 1, N, tfile); + njab++; + for(i=0; i= h) + return(-1L); + m1 = m; + j = i; + for(i++; i 0) { + l = m1; + goto loop; + } + return(m); +} + +cmp(b, s, n) +char *b, *s; +{ + register i; + + if(b[0] != '\n') + exit(2); + for(i=0; i s[i]) + return(-1); + if(b[i+1] < s[i]) + return(1); + } + return(b[i+1] == ' '? 0 : -1); +} + +readtape(buffer) +char *buffer; +{ + int i, j; + + if (recno >= nblock || first == 0) { + if (first == 0 && nblock == 0) + j = fflag ? NBLOCK : 1; /* orignally, NBLOCK; */ + else + j = nblock; + if ((i = read(mt, tbuf, TBLOCK*j)) < 0) { + fprintf(stderr, "Tar: tape read error\n"); + done(3); + } + if (first == 0) { + if ((i % TBLOCK) != 0) { + fprintf(stderr, "Tar: tape blocksize error\n"); + done(3); + } + i /= TBLOCK; + if (rflag && i != 1) { + fprintf(stderr, "Tar: Cannot update blocked tapes (yet)\n"); + done(4); + } + if (i != nblock && (i != 1 || nblock == 0)) { + fprintf(stderr, "Tar: blocksize = %d\n", i); + nblock = i; + } + } + recno = 0; + } + first = 1; + copy(buffer, &tbuf[recno++]); + return(TBLOCK); +} + +writetape(buffer) +char *buffer; +{ + first = 1; + if (nblock == 0) + nblock = 1; + if (recno >= nblock) { + if (write(mt, tbuf, TBLOCK*nblock) < 0) { + fprintf(stderr, "Tar: tape write error\n"); + done(2); + } + recno = 0; + } + copy(&tbuf[recno++], buffer); + if (recno >= nblock) { + if (write(mt, tbuf, TBLOCK*nblock) < 0) { + fprintf(stderr, "Tar: tape write error\n"); + done(2); + } + recno = 0; + } + return(TBLOCK); +} + +backtape() +{ + lseek(mt, (long) -TBLOCK, 1); + if (recno >= nblock) { + recno = nblock - 1; + if (read(mt, tbuf, TBLOCK*nblock) < 0) { + fprintf(stderr, "Tar: tape read error after seek\n"); + done(4); + } + lseek(mt, (long) -TBLOCK, 1); + } +} + +flushtape() +{ + write(mt, tbuf, TBLOCK*nblock); +} + +copy(to, from) +register char *to, *from; +{ + register i; + + i = TBLOCK; + do { + *to++ = *from++; + } while (--i); +} -- 2.20.1