home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/dir.h>
- #include <signal.h>
-
- 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;
- 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++;
- 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++;
- if (nblock != 1 && cflag == 0) {
- noupdate:
- 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':
- 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;
- 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) {
- if (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 (wait(&i) >= 0);
- 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<N; i++) {
- if(b[i] == '\n')
- break;
- m++;
- }
- if(m >= h)
- return(-1L);
- m1 = m;
- j = i;
- for(i++; i<N; i++) {
- m1++;
- if(b[i] == '\n')
- break;
- }
- i = cmp(b+j, s, n);
- if(i < 0) {
- h = m;
- goto loop;
- }
- if(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<n; i++) {
- if(b[i+1] > 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 = 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) {
- 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);
- }
-