home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-09-11 | 37.1 KB | 1,641 lines |
- Subject: v12i070: Public-domain TAR, Part03/03
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rs@uunet.UU.NET
-
- Submitted-by: John Gilmore <hoptoad!gnu@UUNET.UU.NET>
- Posting-number: Volume 12, Issue 70
- Archive-name: pdtar/part03
-
- : To unbundle, sh this file
- echo list.c
- cat >list.c <<'@@@ Fin de list.c'
- /*
- * List a tar archive.
- *
- * Also includes support routines for reading a tar archive.
- *
- * Pubic Domain version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
- *
- * @(#)list.c 1.31 11/5/87 Public Domain - gnu
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #ifndef MSDOS
- #include <sys/file.h>
- #endif /* MSDOS */
-
- #ifdef USG
- #include <sys/sysmacros.h> /* major() and minor() defined here */
- #endif
-
- char *ctime(); /* From libc.a */
-
- #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
-
- #include "tar.h"
- #include "port.h"
-
- long from_oct(); /* Decode octal number */
- void demode(); /* Print file mode */
-
- union record *head; /* Points to current archive header */
- struct stat hstat; /* Stat struct corresponding */
- int head_standard; /* Tape header is in ANSI format */
-
- void print_header();
- void skip_file();
-
-
- /*
- * Main loop for reading an archive.
- */
- void
- read_and(do_something)
- void (*do_something)();
- {
- int status = 3; /* Initial status at start of archive */
- int prev_status;
-
- name_gather(); /* Gather all the names */
- open_archive(1); /* Open for reading */
-
- for(;;) {
- prev_status = status;
- status = read_header();
- switch (status) {
-
- case 1: /* Valid header */
- /* We should decode next field (mode) first... */
- /* Ensure incoming names are null terminated. */
- head->header.name[NAMSIZ-1] = '\0';
-
- if (!name_match(head->header.name)) {
- /* Skip past it in the archive */
- userec(head);
- /* Skip to the next header on the archive */
- skip_file((long)hstat.st_size);
- continue;
- }
-
- (*do_something)();
- continue;
-
- /*
- * If the previous header was good, tell them
- * that we are skipping bad ones.
- */
- case 0: /* Invalid header */
- userec(head);
- switch (prev_status) {
- case 3: /* Error on first record */
- annorec(stderr, tar);
- fprintf(stderr,
- "Hmm, this doesn't look like a tar archive.\n");
- /* FALL THRU */
- case 2: /* Error after record of zeroes */
- case 1: /* Error after header rec */
- annorec(stderr, tar);
- fprintf(stderr,
- "Skipping to next file header...\n");
- case 0: /* Error after error */
- break;
- }
- continue;
-
- case 2: /* Record of zeroes */
- userec(head);
- status = prev_status; /* If error after 0's */
- if (f_ignorez)
- continue;
- /* FALL THRU */
- case EOF: /* End of archive */
- break;
- }
- break;
- };
-
- close_archive();
- names_notfound(); /* Print names not found */
- }
-
-
- /*
- * Print a header record, based on tar options.
- */
- void
- list_archive()
- {
-
- /* Save the record */
- saverec(&head);
-
- /* Print the header record */
- if (f_verbose) {
- if (f_verbose > 1)
- decode_header(head, &hstat, &head_standard, 0);
- print_header(stdout);
- }
-
- /* Skip past it in the archive */
- saverec((union record **) 0); /* Unsave it */
- userec(head);
-
- /* Skip to the next header on the archive */
- skip_file((long)hstat.st_size);
- }
-
-
- /*
- * Read a record that's supposed to be a header record.
- * Return its address in "head", and if it is good, the file's
- * size in hstat.st_size.
- *
- * Return 1 for success, 0 if the checksum is bad, EOF on eof,
- * 2 for a record full of zeros (EOF marker).
- *
- * You must always userec(head) to skip past the header which this
- * routine reads.
- */
- int
- read_header()
- {
- register int i;
- register long sum, recsum;
- register char *p;
- register union record *header;
-
- header = findrec();
- head = header; /* This is our current header */
- if (NULL == header) return EOF;
-
- recsum = from_oct(8, header->header.chksum);
-
- sum = 0;
- p = header->charptr;
- for (i = sizeof(*header); --i >= 0;) {
- /*
- * We can't use unsigned char here because of old compilers,
- * e.g. V7.
- */
- sum += 0xFF & *p++;
- }
-
- /* Adjust checksum to count the "chksum" field as blanks. */
- for (i = sizeof(header->header.chksum); --i >= 0;)
- sum -= 0xFF & header->header.chksum[i];
- sum += ' '* sizeof header->header.chksum;
-
- if (sum == recsum) {
- /*
- * Good record. Decode file size and return.
- */
- if (header->header.linkflag == LF_LINK)
- hstat.st_size = 0; /* Links 0 size on tape */
- else
- hstat.st_size = from_oct(1+12, header->header.size);
- return 1;
- }
-
- if (sum == 8*' ') {
- /*
- * This is a zeroed record...whole record is 0's except
- * for the 8 blanks we faked for the checksum field.
- */
- return 2;
- }
-
- return 0;
- }
-
-
- /*
- * Decode things from a file header record into a "struct stat".
- * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix
- * Standard" tar format or regular old tar format.
- *
- * read_header() has already decoded the checksum and length, so we don't.
- *
- * If wantug != 0, we want the uid/group info decoded from Unix Standard
- * tapes (for extraction). If == 0, we are just printing anyway, so save time.
- *
- * decode_header should NOT be called twice for the same record, since the
- * two calls might use different "wantug" values and thus might end up with
- * different uid/gid for the two calls. If anybody wants the uid/gid they
- * should decode it first, and other callers should decode it without uid/gid
- * before calling a routine, e.g. print_header, that assumes decoded data.
- */
- decode_header(header, st, stdp, wantug)
- register union record *header;
- register struct stat *st;
- int *stdp;
- int wantug;
- {
-
- st->st_mode = from_oct(8, header->header.mode);
- st->st_mtime = from_oct(1+12, header->header.mtime);
-
- if (0==strcmp(header->header.magic, TMAGIC)) {
- /* Unix Standard tar archive */
- *stdp = 1;
- if (wantug) {
- #ifdef NONAMES
- st->st_uid = from_oct(8, header->header.uid);
- st->st_gid = from_oct(8, header->header.gid);
- #else
- st->st_uid = finduid(header->header.uname);
- st->st_gid = findgid(header->header.gname);
- #endif
- }
- switch (header->header.linkflag)
- case LF_BLK: case LF_CHR:
- st->st_rdev = makedev(from_oct(8, header->header.devmajor),
- from_oct(8, header->header.devminor));
- } else {
- /* Old fashioned tar archive */
- *stdp = 0;
- st->st_uid = from_oct(8, header->header.uid);
- st->st_gid = from_oct(8, header->header.gid);
- st->st_rdev = 0;
- }
- }
-
-
- /*
- * Quick and dirty octal conversion.
- *
- * Result is -1 if the field is invalid (all blank, or nonoctal).
- */
- long
- from_oct(digs, where)
- register int digs;
- register char *where;
- {
- register long value;
-
- while (isspace(*where)) { /* Skip spaces */
- where++;
- if (--digs <= 0)
- return -1; /* All blank field */
- }
- value = 0;
- while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
- value = (value << 3) | (*where++ - '0');
- --digs;
- }
-
- if (digs > 0 && *where && !isspace(*where))
- return -1; /* Ended on non-space/nul */
-
- return value;
- }
-
-
- /*
- * Actually print it.
- *
- * Plain and fancy file header block logging.
- * Non-verbose just prints the name, e.g. for "tar t" or "tar x".
- * This should just contain file names, so it can be fed back into tar
- * with xargs or the "-T" option. The verbose option can give a bunch
- * of info, one line per file. I doubt anybody tries to parse its
- * format, or if they do, they shouldn't. Unix tar is pretty random here
- * anyway.
- *
- * Note that print_header uses the globals <head>, <hstat>, and
- * <head_standard>, which must be set up in advance. This is not very clean
- * and should be cleaned up. FIXME.
- */
- #define UGSWIDTH 11 /* min width of User, group, size */
- #define DATEWIDTH 19 /* Last mod date */
- static int ugswidth = UGSWIDTH; /* Max width encountered so far */
-
- void
- print_header(outfile)
- FILE *outfile;
- {
- char modes[11];
- char *timestamp;
- char uform[11], gform[11]; /* These hold formatted ints */
- char *user, *group;
- char size[24]; /* Holds a formatted long or maj, min */
- long longie; /* To make ctime() call portable */
- int pad;
-
- annofile(outfile, (char *)NULL);
-
- if (f_verbose <= 1) {
- /* Just the fax, mam. */
- fprintf(outfile, "%s\n", head->header.name);
- return;
- } else {
- /* File type and modes */
- modes[0] = '?';
- switch (head->header.linkflag) {
- case LF_NORMAL:
- case LF_OLDNORMAL:
- case LF_LINK:
- modes[0] = '-';
- if ('/' == head->header.name[strlen(head->header.name)-1])
- modes[0] = 'd';
- break;
- case LF_DIR: modes[0] = 'd'; break;
- case LF_SYMLINK:modes[0] = 'l'; break;
- case LF_BLK: modes[0] = 'b'; break;
- case LF_CHR: modes[0] = 'c'; break;
- case LF_FIFO: modes[0] = 'p'; break;
- case LF_CONTIG: modes[0] = 'C'; break;
- }
-
- demode((unsigned)hstat.st_mode, modes+1);
-
- /* Timestamp */
- longie = hstat.st_mtime;
- timestamp = ctime(&longie);
- timestamp[16] = '\0';
- timestamp[24] = '\0';
-
- /* User and group names */
- if (*head->header.uname && head_standard) {
- user = head->header.uname;
- } else {
- user = uform;
- (void)sprintf(uform, "%d", (int)hstat.st_uid);
- }
- if (*head->header.gname && head_standard) {
- group = head->header.gname;
- } else {
- group = gform;
- (void)sprintf(gform, "%d", (int)hstat.st_gid);
- }
-
- /* Format the file size or major/minor device numbers */
- switch (head->header.linkflag) {
- case LF_CHR:
- case LF_BLK:
- (void)sprintf(size, "%d,%d",
- major(hstat.st_rdev),
- minor(hstat.st_rdev));
- break;
-
- default:
- (void)sprintf(size, "%ld", (long)hstat.st_size);
- }
-
- /* Figure out padding and print the whole line. */
- pad = strlen(user) + strlen(group) + strlen(size) + 1;
- if (pad > ugswidth) ugswidth = pad;
-
- fprintf(outfile, "%s %s/%s %*s%s %s %s %.*s",
- modes,
- user,
- group,
- ugswidth - pad,
- "",
- size,
- timestamp+4, timestamp+20,
- sizeof(head->header.name),
- head->header.name);
-
- switch (head->header.linkflag) {
- case LF_SYMLINK:
- fprintf(outfile, " -> %s\n", head->header.linkname);
- break;
-
- case LF_LINK:
- fprintf(outfile, " link to %s\n", head->header.linkname);
- break;
-
- default:
- fprintf(outfile, " unknown file type '%c'\n",
- head->header.linkflag);
- break;
-
- case LF_OLDNORMAL:
- case LF_NORMAL:
- case LF_CHR:
- case LF_BLK:
- case LF_DIR:
- case LF_FIFO:
- case LF_CONTIG:
- putc('\n', outfile);
- break;
- }
- }
- }
-
- /*
- * Print a similar line when we make a directory automatically.
- */
- void
- pr_mkdir(pathname, length, mode, outfile)
- char *pathname;
- int length;
- int mode;
- FILE *outfile;
- {
- char modes[11];
-
- if (f_verbose > 1) {
- /* File type and modes */
- modes[0] = 'd';
- demode((unsigned)mode, modes+1);
-
- annofile(outfile, (char *)NULL);
- fprintf(outfile, "%s %*s %.*s\n",
- modes,
- ugswidth+DATEWIDTH,
- "Creating directory:",
- length,
- pathname);
- }
- }
-
-
- /*
- * Skip over <size> bytes of data in records in the archive.
- */
- void
- skip_file(size)
- register long size;
- {
- union record *x;
-
- while (size > 0) {
- x = findrec();
- if (x == NULL) { /* Check it... */
- annorec(stderr, tar);
- fprintf(stderr, "Unexpected EOF on archive file\n");
- exit(EX_BADARCH);
- }
- userec(x);
- size -= RECORDSIZE;
- }
- }
-
-
- /*
- * Decode the mode string from a stat entry into a 9-char string and a null.
- */
- void
- demode(mode, string)
- register unsigned mode;
- register char *string;
- {
- register unsigned mask;
- register char *rwx = "rwxrwxrwx";
-
- for (mask = 0400; mask != 0; mask >>= 1) {
- if (mode & mask)
- *string++ = *rwx++;
- else {
- *string++ = '-';
- rwx++;
- }
- }
-
- if (mode & S_ISUID)
- if (string[-7] == 'x')
- string[-7] = 's';
- else
- string[-7] = 'S';
- if (mode & S_ISGID)
- if (string[-4] == 'x')
- string[-4] = 's';
- else
- string[-4] = 'S';
- if (mode & S_ISVTX)
- if (string[-1] == 'x')
- string[-1] = 't';
- else
- string[-1] = 'T';
- *string = '\0';
- }
- @@@ Fin de list.c
- echo names.c
- cat >names.c <<'@@@ Fin de names.c'
- /*
- * Look up user and/or group names.
- *
- * This file should be modified for non-unix systems to do something
- * reasonable.
- *
- * @(#)names.c 1.3 10/30/87 Public Domain - gnu
- */
- #include <sys/types.h>
- #include "tar.h"
-
- extern char *strncpy();
-
- #ifndef NONAMES
- /* Whole module goes away if NONAMES defined. Otherwise... */
- #include <pwd.h>
- #include <grp.h>
-
- static int saveuid = -993;
- static char saveuname[TUNMLEN];
- static int my_uid = -993;
-
- static int savegid = -993;
- static char savegname[TGNMLEN];
- static int my_gid = -993;
-
- #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid )
- #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid )
-
- /*
- * Look up a user or group name from a uid/gid, maintaining a cache.
- * FIXME, for now it's a one-entry cache.
- * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
- *
- * This is ifdef'd because on Suns, it drags in about 38K of "yellow
- * pages" code, roughly doubling the program size. Thanks guys.
- */
- void
- finduname(uname, uid)
- char uname[TUNMLEN];
- int uid;
- {
- struct passwd *pw;
- extern struct passwd *getpwuid ();
-
- if (uid != saveuid) {
- saveuid = uid;
- saveuname[0] = '\0';
- pw = getpwuid(uid);
- if (pw)
- strncpy(saveuname, pw->pw_name, TUNMLEN);
- }
- strncpy(uname, saveuname, TUNMLEN);
- }
-
- int
- finduid(uname)
- char uname[TUNMLEN];
- {
- struct passwd *pw;
- extern struct passwd *getpwnam();
-
- if (uname[0] != saveuname[0] /* Quick test w/o proc call */
- || 0!=strncmp(uname, saveuname, TUNMLEN)) {
- strncpy(saveuname, uname, TUNMLEN);
- pw = getpwnam(uname);
- if (pw) {
- saveuid = pw->pw_uid;
- } else {
- saveuid = myuid;
- }
- }
- return saveuid;
- }
-
-
- void
- findgname(gname, gid)
- char gname[TGNMLEN];
- int gid;
- {
- struct group *gr;
- extern struct group *getgrgid ();
-
- if (gid != savegid) {
- savegid = gid;
- savegname[0] = '\0';
- (void)setgrent();
- gr = getgrgid(gid);
- if (gr)
- strncpy(savegname, gr->gr_name, TGNMLEN);
- }
- (void) strncpy(gname, savegname, TGNMLEN);
- }
-
-
- int
- findgid(gname)
- char gname[TUNMLEN];
- {
- struct group *gr;
- extern struct group *getgrnam();
-
- if (gname[0] != savegname[0] /* Quick test w/o proc call */
- || 0!=strncmp(gname, savegname, TUNMLEN)) {
- strncpy(savegname, gname, TUNMLEN);
- gr = getgrnam(gname);
- if (gr) {
- savegid = gr->gr_gid;
- } else {
- savegid = mygid;
- }
- }
- return savegid;
- }
- #endif
- @@@ Fin de names.c
- echo diffarch.c
- cat >diffarch.c <<'@@@ Fin de diffarch.c'
- /*
- * Diff files from a tar archive.
- *
- * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
- *
- * @(#) diffarch.c 1.10 87/11/11 Public Domain - gnu
- */
-
- #include <stdio.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #ifdef BSD42
- #include <sys/file.h>
- #endif
-
- #ifdef USG
- #include <fcntl.h>
- #endif
-
- /* Some systems don't have these #define's -- we fake it here. */
- #ifndef O_RDONLY
- #define O_RDONLY 0
- #endif
- #ifndef O_NDELAY
- #define O_NDELAY 0
- #endif
-
- extern int errno; /* From libc.a */
- extern char *valloc(); /* From libc.a */
-
- #include "tar.h"
- #include "port.h"
-
- extern union record *head; /* Points to current tape header */
- extern struct stat hstat; /* Stat struct corresponding */
- extern int head_standard; /* Tape header is in ANSI format */
-
- extern void print_header();
- extern void skip_file();
-
- char *filedata; /* Pointer to area for reading
- file contents into */
-
- /*
- * Initialize for a diff operation
- */
- diff_init()
- {
-
- /*NOSTRICT*/
- filedata = (char *) valloc((unsigned)blocksize);
- if (!filedata) {
- fprintf(stderr,
- "tar: could not allocate memory for diff buffer of %d bytes\n",
- blocking);
- exit(EX_ARGSBAD);
- }
- }
-
- /*
- * Diff a file against the archive.
- */
- void
- diff_archive()
- {
- register char *data;
- int fd, check, namelen, written;
- int err, firsttime;
- long size;
- struct stat filestat;
- char linkbuf[NAMSIZ+3];
-
- errno = EPIPE; /* FIXME, remove perrors */
-
- saverec(&head); /* Make sure it sticks around */
- userec(head); /* And go past it in the archive */
- decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */
-
- /* Print the record from 'head' and 'hstat' */
- if (f_verbose)
- print_header(stdout);
-
- switch (head->header.linkflag) {
-
- default:
- annofile(stderr, tar);
- fprintf(stderr,
- "Unknown file type '%c' for %s, diffed as normal file\n",
- head->header.linkflag, head->header.name);
- /* FALL THRU */
-
- case LF_OLDNORMAL:
- case LF_NORMAL:
- case LF_CONTIG:
- /*
- * Appears to be a file.
- * See if it's really a directory.
- */
- namelen = strlen(head->header.name)-1;
- if (head->header.name[namelen] == '/')
- goto really_dir;
-
- fd = open(head->header.name, O_NDELAY|O_RDONLY);
-
- if (fd < 0) {
- if (errno == ENOENT) {
- /* Expected error -- to stdout */
- annofile(stdout, (char *)NULL);
- fprintf(stdout, "%s: does not exist\n",
- head->header.name);
- } else {
- annofile(stderr, (char *)NULL);
- perror(head->header.name);
- }
- skip_file((long)hstat.st_size);
- goto quit;
- }
-
- err = fstat(fd, &filestat);
- if (err < 0) {
- annofile(stdout, (char *)NULL);
- fprintf(stdout, "Cannot fstat file ");
- perror(head->header.name);
- skip_file((long)hstat.st_size);
- goto qclose;
- }
-
- if ((filestat.st_mode & S_IFMT) != S_IFREG) {
- annofile(stdout, (char *)NULL);
- fprintf(stdout, "%s: not a regular file\n",
- head->header.name);
- skip_file((long)hstat.st_size);
- goto qclose;
- }
-
- filestat.st_mode &= ~S_IFMT;
- if (filestat.st_mode != hstat.st_mode)
- sigh("mode");
- if (filestat.st_uid != hstat.st_uid)
- sigh("uid");
- if (filestat.st_gid != hstat.st_gid)
- sigh("gid");
- if (filestat.st_size != hstat.st_size) {
- sigh("size");
- skip_file((long)hstat.st_size);
- goto qclose;
- }
- if (filestat.st_mtime != hstat.st_mtime)
- sigh("mod time");
-
- firsttime = 0;
-
- for (size = hstat.st_size;
- size > 0;
- size -= written) {
- /*
- * Locate data, determine max length
- * writeable, write it, record that
- * we have used the data, then check
- * if the write worked.
- */
- data = findrec()->charptr;
- if (data == NULL) { /* Check it... */
- annorec(stderr, tar);
- fprintf(stderr, "Unexpected EOF on archive file\n");
- break;
- }
- written = endofrecs()->charptr - data;
- if (written > size) written = size;
- errno = 0;
- check = read (fd, filedata, written);
- /*
- * The following is in violation of strict
- * typing, since the arg to userec
- * should be a struct rec *. FIXME.
- */
- userec(data + written - 1);
- if (check == written) {
- /* The read worked, now compare the data */
- if (bcmp(data, filedata, check) == 0)
- continue; /* It compares */
- if (firsttime++) {
- annofile(stdout, (char *)NULL);
- fprintf(stdout, "%s: data differs\n",
- head->header.name);
- }
- }
-
- /*
- * Error in reading from file.
- * Print it, skip to next file in archive.
- */
- annofile(stderr, tar);
- fprintf(stderr,
- "Tried to read %d bytes from file, could only read %d:\n",
- written, check);
- perror(head->header.name);
- skip_file((long)(size - written));
- break; /* Still do the close, mod time, chmod, etc */
- }
-
- qclose:
- check = close(fd);
- if (check < 0) {
- annofile(stderr, tar);
- fprintf(stderr, "Error while closing ");
- perror(head->header.name);
- }
-
- quit:
- break;
-
- case LF_LINK:
- check = 1; /* FIXME deal with this */
- /* check = link (head->header.linkname,
- head->header.name); */
- /* FIXME, don't worry uid, gid, etc... */
- if (check == 0)
- break;
- annofile(stderr, tar);
- fprintf(stderr, "Could not link %s to ",
- head->header.name);
- perror(head->header.linkname);
- break;
-
- #ifdef S_IFLNK
- case LF_SYMLINK:
- check = readlink(head->header.name, linkbuf,
- (sizeof linkbuf)-1);
-
- if (check < 0) {
- if (errno == ENOENT) {
- annofile(stdout, (char *)NULL);
- fprintf(stdout,
- "%s: no such file or directory\n",
- head->header.name);
- } else {
- annofile(stderr, tar);
- fprintf(stderr, "Could not read link");
- perror(head->header.name);
- }
- break;
- }
-
- linkbuf[check] = '\0'; /* Null-terminate it */
- if (strncmp(head->header.linkname, linkbuf, check) != 0) {
- annofile(stdout, (char *)NULL);
- fprintf(stdout, "%s: symlink differs\n",
- head->header.linkname);
- }
- break;
- #endif
-
- case LF_CHR:
- hstat.st_mode |= S_IFCHR;
- goto make_node;
-
- #ifdef S_IFBLK
- /* If local system doesn't support block devices, use default case */
- case LF_BLK:
- hstat.st_mode |= S_IFBLK;
- goto make_node;
- #endif
-
- #ifdef S_IFIFO
- /* If local system doesn't support FIFOs, use default case */
- case LF_FIFO:
- hstat.st_mode |= S_IFIFO;
- hstat.st_rdev = 0; /* FIXME, do we need this? */
- goto make_node;
- #endif
-
- make_node:
- /* FIXME, deal with umask */
-
- check = 1; /* FIXME, implement this */
- /* check = mknod(head->header.name, (int) hstat.st_mode,
- (int) hstat.st_rdev); */
- if (check != 0) {
- annofile(stderr, tar);
- fprintf(stderr, "Could not make ");
- perror(head->header.name);
- break;
- };
- break;
-
- case LF_DIR:
- /* Check for trailing / */
- namelen = strlen(head->header.name)-1;
- really_dir:
- while (namelen && head->header.name[namelen] == '/')
- head->header.name[namelen--] = '\0'; /* Zap / */
-
- check = 1; /* FIXME, implement this */
- /* check = mkdir(head->header.name, 0300 | (int)hstat.st_mode); */
- if (check != 0) {
- annofile(stderr, tar);
- fprintf(stderr, "Could not make directory ");
- perror(head->header.name);
- break;
- }
-
- break;
-
- }
-
- /* We don't need to save it any longer. */
- saverec((union record **) 0); /* Unsave it */
- }
-
- /*
- * Sigh about something that differs.
- */
- sigh(what)
- char *what;
- {
-
- annofile(stdout, (char *)NULL);
- fprintf(stdout, "%s: %s differs\n",
- head->header.name, what);
- }
- @@@ Fin de diffarch.c
- echo port.c
- cat >port.c <<'@@@ Fin de port.c'
- /*
- * @(#)port.c 1.15 87/11/05 Public Domain, by John Gilmore, 1986
- *
- * These are routines not available in all environments.
- *
- * I know this introduces an extra level of subroutine calls and is
- * slightly slower. Frankly, my dear, I don't give a damn. Let the
- * Missed-Em Vee losers suffer a little. This software is proud to
- * have been written on a BSD system.
- */
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <errno.h>
-
- #ifdef MSDOS
- #include <fcntl.h>
- #else
- #include <sys/file.h>
- #endif
-
- #include "tar.h"
-
- extern char **environ;
-
- #ifndef NULL
- #define NULL 0
- #endif
-
- /*
- * Some people (e.g. V7) don't have a #define for these.
- */
- #ifndef O_BINARY
- #define O_BINARY 0
- #endif
- #ifndef O_RDONLY
- #define O_RDONLY 0
- #endif
-
-
- #include "port.h"
-
-
- /*
- * Some computers are not so crass as to align themselves into the BSD
- * or USG camps. If a system supplies all of the routines we fake here,
- * add it to the list in the #ifndefs below and it'll all be skipped.
- * Make sure to add a matching #endif at the end of the file!
- *
- * We are avoiding #if defined() here for the sake of Minix, which comes
- * with the severely broken Amsterdam Compiler Kit. Thanks, Andy!
- */
- #ifndef mc300
- #ifndef mc500
- #ifndef mc700
-
-
- #ifndef BSD42
- /*
- * lstat() is a stat() which does not follow symbolic links.
- * If there are no symbolic links, just use stat().
- */
- int
- lstat (path, buf)
- char *path;
- struct stat *buf;
- {
- extern int stat ();
- return (stat (path, buf));
- }
-
- /*
- * valloc() does a malloc() on a page boundary. On some systems,
- * this can make large block I/O more efficient.
- */
- char *
- valloc (size)
- unsigned size;
- {
- extern char *malloc ();
- return (malloc (size));
- }
-
- /*
- * NMKDIR.C
- *
- * Written by Robert Rother, Mariah Corporation, August 1985.
- *
- * I wrote this out of shear disgust with myself because I couldn't
- * figure out how to do this in /bin/sh.
- *
- * If you want it, it's yours. All I ask in return is that if you
- * figure out how to do this in a Bourne Shell script you send me
- * a copy.
- * sdcsvax!rmr or rmr@uscd
- *
- * Severely hacked over by John Gilmore to make a 4.2BSD compatible
- * subroutine. 11Mar86; hoptoad!gnu
- *
- * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
- * subroutine didn't return EEXIST. It does now.
- */
-
- /*
- * Make a directory. Compatible with the mkdir() system call on 4.2BSD.
- */
- #ifndef MSDOS
- int
- mkdir(dpath, dmode)
- char *dpath;
- int dmode;
- {
- int cpid, status;
- struct stat statbuf;
- extern int errno;
-
- if (stat(dpath,&statbuf) == 0) {
- errno = EEXIST; /* Stat worked, so it already exists */
- return -1;
- }
-
- /* If stat fails for a reason other than non-existence, return error */
- if (errno != ENOENT) return -1;
-
- switch (cpid = fork()) {
-
- case -1: /* Error in fork() */
- return(-1); /* Errno is set already */
-
- case 0: /* Child process */
- /*
- * Cheap hack to set mode of new directory. Since this
- * child process is going away anyway, we zap its umask.
- * FIXME, this won't suffice to set SUID, SGID, etc. on this
- * directory. Does anybody care?
- */
- status = umask(0); /* Get current umask */
- status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
- execl("/bin/mkdir", "mkdir", dpath, (char *)0);
- _exit(-1); /* Can't exec /bin/mkdir */
-
- default: /* Parent process */
- while (cpid != wait(&status)) ; /* Wait for kid to finish */
- }
-
- if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
- errno = EIO; /* We don't know why, but */
- return -1; /* /bin/mkdir failed */
- }
-
- return 0;
- }
- #endif /* MSDOS */
- #endif
-
- /* This next bit is called "doing OR on Minix cpp", e.g. without defined(). */
- #undef WANTSTRING
- #ifdef USG
- #define WANTSTRING
- #endif
- #ifdef MSDOS
- #define WANTSTRING
- #endif
-
- #ifdef WANTSTRING
- /*
- * Translate V7 style into Sys V style.
- */
- #include <string.h>
- #include <memory.h>
-
- char *
- index (s, c)
- char *s;
- int c;
- {
- return (strchr (s, c));
- }
-
- void
- bcopy (s1, s2, n)
- char *s1, *s2;
- int n;
- {
- (void) memcpy (s2, s1, n);
- }
-
- void
- bzero (s1, n)
- char *s1;
- int n;
- {
- (void) memset(s1, 0, n);
- }
-
- int
- bcmp(s1, s2, n)
- char *s1, *s2;
- int n;
- {
- return memcmp(s1, s2, n);
- }
- #endif
-
- #ifdef MINIX
- /* Minix has bcopy but not bzero, and no memset. Thanks, Andy. */
- void
- bzero (s1, n)
- register char *s1;
- register int n;
- {
- while (n--) *s1++ = '\0';
- }
-
- /* It also has no bcmp() */
- int
- bcmp (s1, s2, n)
- register char *s1,*s2;
- register int n;
- {
- for ( ; n-- ; ++s1, ++s2) {
- if (*s1 != *s2) return *s1 - *s2;
- }
- return 0;
- }
-
- /*
- * Groan, Minix doesn't have execlp either!
- *
- * execlp(file,arg0,arg1...argn,(char *)NULL)
- * exec a program, automatically searching for the program through
- * all the directories on the PATH.
- *
- * This version is naive about variable argument lists, it assumes
- * a straightforward C calling sequence. If your system has odd stacks
- * *and* doesn't have execlp, YOU get to fix it.
- */
- int
- execlp(filename, arg0)
- char *filename, *arg0;
- {
- extern char *malloc(), *getenv(), *index();
- extern int errno;
- register char *p, *path;
- char **argstart = &arg0;
- register char *fnbuffer;
- struct stat statbuf;
-
- if ((p = getenv("PATH")) == NULL) {
- /* couldn't find path variable -- try to exec given filename */
- return execve(filename, argstart, environ);
- }
-
- /*
- * make a place to build the filename. We malloc larger than we
- * need, but we know it will fit in this.
- */
- fnbuffer = malloc( strlen(p) + 1 + strlen(filename) );
- if (fnbuffer == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- /*
- * try each component of the path to see if the file's there
- * and executable.
- */
- for (path = p ; path ; path = p) {
- /* construct full path name to try */
- if ((p = index(path,':')) == NULL) {
- strcpy(fnbuffer, path);
- } else {
- strncpy(fnbuffer, path, p-path);
- fnbuffer[p-path] = '\0';
- p++; /* Skip : for next time */
- }
- if (strlen(fnbuffer) != 0)
- strcat(fnbuffer,"/");
- strcat(fnbuffer,filename);
-
- /* check to see if file is there and is a normal file */
- if (stat(fnbuffer, &statbuf) < 0) {
- if (errno == ENOENT)
- continue; /* file not there,keep on looking */
- else
- goto fail; /* failed for some reason, return */
- }
- if ( (statbuf.st_mode & S_IFMT) != S_IFREG) continue;
-
- if (execve(fnbuffer, argstart, environ) < 0
- && errno != ENOENT
- && errno != ENOEXEC) {
- /* failed, for some other reason besides "file
- * not found" or "not a.out format"
- */
- goto fail;
- }
-
- /*
- * If we got error ENOEXEC, the file is executable but is
- * not an object file. Try to execute it as a shell script,
- * returning error if we can't execute /bin/sh.
- *
- * FIXME, this code is broken in several ways. Shell
- * scripts should not in general be executed by the user's
- * SHELL variable program. On more mature systems, the
- * script can specify with #!/bin/whatever. Also, this
- * code clobbers argstart[-1] if the exec of the shell
- * fails.
- */
- if (errno == ENOEXEC) {
- char *shell;
-
- /* Try to execute command "sh arg0 arg1 ..." */
- if ((shell = getenv("SHELL")) == NULL)
- shell = "/bin/sh";
- argstart[-1] = shell;
- argstart[0] = fnbuffer;
- execve(shell, &argstart[-1], environ);
- goto fail; /* Exec didn't work */
- }
-
- /*
- * If we succeeded, the execve() doesn't return, so we
- * can only be here is if the file hasn't been found yet.
- * Try the next place on the path.
- */
- }
-
- /* all attempts failed to locate the file. Give up. */
- errno = ENOENT;
-
- fail:
- free(fnbuffer);
- return -1;
- }
- #endif /* MINIX */
-
-
- #ifdef EMUL_OPEN3
- #include "open3.h"
- /*
- * open3 -- routine to emulate the 3-argument open system
- * call that is present in most modern Unix systems.
- * This version attempts to support all the flag bits except for O_NDELAY
- * and O_APPEND, which are silently ignored. The emulation is not as efficient
- * as the real thing (at worst, 4 system calls instead of one), but there's
- * not much I can do about that.
- *
- * Written 6/10/87 by rmtodd@uokmax
- *
- * open3(path, flag, mode)
- * Attempts to open the file specified by
- * the given pathname. The following flag bits (#defined in tar.h)
- * specify options to the routine:
- * O_RDONLY file open for read only
- * O_WRONLY file open for write only
- * O_RDWR file open for both read & write
- * (Needless to say, you should only specify one of the above).
- * O_CREAT file is created with specified mode if it needs to be.
- * O_TRUNC if file exists, it is truncated to 0 bytes
- * O_EXCL used with O_CREAT--routine returns error if file exists
- * Function returns file descriptor if successful, -1 and errno if not.
- */
-
- /*
- * array to give arguments to access for various modes
- * FIXME, this table depends on the specific integer values of O_XXX,
- * and also contains integers (args to 'access') that should be #define's.
- */
- static int modes[] =
- {
- 04, /* O_RDONLY */
- 02, /* O_WRONLY */
- 06, /* O_RDWR */
- 06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
- };
-
- /* Shut off the automatic emulation of open(), we'll need it. */
- #undef open
-
- int
- open3(path, flags, mode)
- char *path;
- int flags, mode;
- {
- extern int errno;
- int exists = 1;
- int call_creat = 0;
- int fd;
- /*
- * We actually do the work by calling the open() or creat() system
- * call, depending on the flags. Call_creat is true if we will use
- * creat(), false if we will use open().
- */
-
- /*
- * See if the file exists and is accessible in the requested mode.
- *
- * Strictly speaking we shouldn't be using access, since access checks
- * against real uid, and the open call should check against euid.
- * Most cases real uid == euid, so it won't matter. FIXME.
- * FIXME, the construction "flags & 3" and the modes table depends
- * on the specific integer values of the O_XXX #define's. Foo!
- */
- if (access(path,modes[flags & 3]) < 0) {
- if (errno == ENOENT) {
- /* the file does not exist */
- exists = 0;
- } else {
- /* probably permission violation */
- if (flags & O_EXCL) {
- /* Oops, the file exists, we didn't want it. */
- /* No matter what the error, claim EEXIST. */
- errno = EEXIST;
- }
- return -1;
- }
- }
-
- /* if we have the O_CREAT bit set, check for O_EXCL */
- if (flags & O_CREAT) {
- if ((flags & O_EXCL) && exists) {
- /* Oops, the file exists and we didn't want it to. */
- errno = EEXIST;
- return -1;
- }
- /*
- * If the file doesn't exist, be sure to call creat() so that
- * it will be created with the proper mode.
- */
- if (!exists) call_creat = 1;
- } else {
- /* If O_CREAT isn't set and the file doesn't exist, error. */
- if (!exists) {
- errno = ENOENT;
- return -1;
- }
- }
-
- /*
- * If the O_TRUNC flag is set and the file exists, we want to call
- * creat() anyway, since creat() guarantees that the file will be
- * truncated and open()-for-writing doesn't.
- * (If the file doesn't exist, we're calling creat() anyway and the
- * file will be created with zero length.)
- */
- if ((flags & O_TRUNC) && exists) call_creat = 1;
- /* actually do the call */
- if (call_creat) {
- /*
- * call creat. May have to close and reopen the file if we
- * want O_RDONLY or O_RDWR access -- creat() only gives
- * O_WRONLY.
- */
- fd = creat(path,mode);
- if (fd < 0 || (flags & O_WRONLY)) return fd;
- if (close(fd) < 0) return -1;
- /* Fall out to reopen the file we've created */
- }
-
- /*
- * calling old open, we strip most of the new flags just in case.
- */
- return open(path, flags & (O_RDONLY|O_WRONLY|O_RDWR|O_BINARY));
- }
- #endif
-
- #endif /* MASSCOMP mc700 */
- #endif /* MASSCOMP mc500 */
- #endif /* MASSCOMP mc300 */
-
-
-
- #ifdef MSDOS
- /* Fake mknod by complaining */
- int
- mknod(path, mode, dev)
- char *path;
- unsigned short mode;
- dev_t dev;
- {
- extern int errno;
- int fd;
-
- errno = ENXIO; /* No such device or address */
- return -1; /* Just give an error */
- }
-
- /* Fake links by copying */
- int
- link(path1, path2)
- char *path1;
- char *path2;
- {
- char buf[256];
- int ifd, ofd;
- int nrbytes;
- int nwbytes;
-
- fprintf(stderr, "%s: %s: cannot link to %s, copying instead\n",
- tar, path1, path2);
- if ((ifd = open(path1, O_RDONLY|O_BINARY)) < 0)
- return -1;
- if ((ofd = creat(path2, 0666)) < 0)
- return -1;
- setmode(ofd, O_BINARY);
- while ((nrbytes = read(ifd, buf, sizeof(buf))) > 0) {
- if ((nwbytes = write(ofd, buf, nrbytes)) != nrbytes) {
- nrbytes = -1;
- break;
- }
- }
- /* Note use of "|" rather than "||" below: we want to close
- * the files even if an error occurs.
- */
- if ((nrbytes < 0) | (0 != close(ifd)) | (0 != close(ofd))) {
- unlink(path2);
- return -1;
- }
- return 0;
- }
-
- /* everyone owns everything on MS-DOS (or is it no one owns anything?) */
- int
- chown(path, uid, gid)
- char *path;
- int uid;
- int gid;
- {
- return 0;
- }
-
- int
- geteuid()
- {
- return 0;
- }
- #endif /* MSDOS */
- @@@ Fin de port.c
- echo wildmat.c
- cat >wildmat.c <<'@@@ Fin de wildmat.c'
- /*
- * @(#)wildmat.c 1.3 87/11/06 Public Domain.
- *
- From: rs@mirror.TMC.COM (Rich Salz)
- Newsgroups: net.sources
- Subject: Small shell-style pattern matcher
- Message-ID: <596@mirror.TMC.COM>
- Date: 27 Nov 86 00:06:40 GMT
-
- There have been several regular-expression subroutines and one or two
- filename-globbing routines in mod.sources. They handle lots of
- complicated patterns. This small piece of code handles the *?[]\
- wildcard characters the way the standard Unix(tm) shells do, with the
- addition that "[^.....]" is an inverse character class -- it matches
- any character not in the range ".....". Read the comments for more
- info.
-
- For my application, I had first ripped off a copy of the "glob" routine
- from within the find(1) source, but that code is bad news: it recurses
- on every character in the pattern. I'm putting this replacement in the
- public domain. It's small, tight, and iterative. Compile with -DTEST
- to get a test driver. After you're convinced it works, install in
- whatever way is appropriate for you.
-
- I would like to hear of bugs, but am not interested in additions; if I
- were, I'd use the code I mentioned above.
- */
- /*
- ** Do shell-style pattern matching for ?, \, [], and * characters.
- ** Might not be robust in face of malformed patterns; e.g., "foo[a-"
- ** could cause a segmentation violation.
- **
- ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
- */
-
- /*
- * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
- * if the pattern is immediately followed by a "/", as well as \0.
- * This matches what "tar" does for matching whole subdirectories.
- *
- * The "*" code could be sped up by only recursing one level instead
- * of two for each trial pattern, perhaps, and not recursing at all
- * if a literal match of the next 2 chars would fail.
- */
- #define TRUE 1
- #define FALSE 0
-
-
- static int
- Star(s, p)
- register char *s;
- register char *p;
- {
- while (wildmat(s, p) == FALSE)
- if (*++s == '\0')
- return(FALSE);
- return(TRUE);
- }
-
-
- int
- wildmat(s, p)
- register char *s;
- register char *p;
- {
- register int last;
- register int matched;
- register int reverse;
-
- for ( ; *p; s++, p++)
- switch (*p) {
- case '\\':
- /* Literal match with following character; fall through. */
- p++;
- default:
- if (*s != *p)
- return(FALSE);
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return(FALSE);
- continue;
- case '*':
- /* Trailing star matches everything. */
- return(*++p ? Star(s, p) : TRUE);
- case '[':
- /* [^....] means inverse character class. */
- if (reverse = p[1] == '^')
- p++;
- for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = TRUE;
- if (matched == reverse)
- return(FALSE);
- continue;
- }
-
- /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
- return(*s == '\0' || *s == '/');
- }
-
-
- #ifdef TEST
- #include <stdio.h>
-
- extern char *gets();
-
-
- main()
- {
- char pattern[80];
- char text[80];
-
- while (TRUE) {
- printf("Enter pattern: ");
- if (gets(pattern) == NULL)
- break;
- while (TRUE) {
- printf("Enter text: ");
- if (gets(text) == NULL)
- exit(0);
- if (text[0] == '\0')
- /* Blank line; go back and get a new pattern. */
- break;
- printf(" %d\n", wildmat(text, pattern));
- }
- }
- exit(0);
- }
- #endif /* TEST */
- @@@ Fin de wildmat.c
- exit 0
-