v17i076: Usenix/IEEE POSIX replacement for TAR and CPIO, Part03/06
Rich Salz
rsalz at uunet.uu.net
Sat Feb 4 07:34:38 AEST 1989
Submitted-by: Mark H. Colburn <mark at jhereg.jhereg.mn.org>
Posting-number: Volume 17, Issue 76
Archive-name: pax/part03
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 6)."
# Contents: fileio.c namelist.c pax.c pax.h tar.c
# Wrapped by mark at jhereg on Tue Dec 27 19:37:45 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f fileio.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"fileio.c\"
else
echo shar: Extracting \"fileio.c\" \(10596 characters\)
sed "s/^X//" >fileio.c <<'END_OF_fileio.c'
X/* $Source: /u/mark/src/pax/RCS/fileio.c,v $
X *
X * $Revision: 1.1 $
X *
X * fileio.c - file I/O functions for all archive interfaces
X *
X * DESCRIPTION
X *
X * These function all do I/O of some form or another. They are
X * grouped here mainly for convienence.
X *
X * AUTHOR
X *
X * Mark H. Colburn, NAPS International (mark at jhereg.mn.org)
X *
X * Sponsored by The USENIX Association for public distribution.
X *
X * Copyright (c) 1989 Mark H. Colburn.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in all such
X * forms and that any documentation, advertising materials, and other
X * materials related to such distribution and use acknowledge that the
X * software was developed * by Mark H. Colburn and sponsored by The
X * USENIX Association.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * $Log: fileio.c,v $
X * Revision 1.1 88/12/23 18:02:09 mark
X * Initial revision
X *
X */
X
X#ifndef lint
Xstatic char *ident = "$Id: fileio.c,v 1.1 88/12/23 18:02:09 mark Rel $";
Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
X#endif /* ! lint */
X
X
X/* Headers */
X
X#include "pax.h"
X
X
X/* open_archive - open an archive file.
X *
X * DESCRIPTION
X *
X * Open_archive will open an archive file for reading or writing,
X * setting the proper file mode, depending on the "mode" passed to
X * it. All buffer pointers are reset according to the mode
X * specified.
X *
X * PARAMETERS
X *
X * int mode - specifies whether we are reading or writing.
X *
X * RETURNS
X *
X * Returns a zero if successfull, or -1 if an error occured during
X * the open.
X */
X
X#ifdef __STDC__
X
Xint open_archive(int mode)
X
X#else
X
Xint open_archive(mode)
Xint mode;
X
X#endif
X{
X if (ar_file[0] == '-' && ar_file[1] == '\0') {
X if (mode == AR_READ) {
X archivefd = STDIN;
X bufend = bufidx = bufstart;
X } else {
X archivefd = STDOUT;
X }
X } else if (mode == AR_READ) {
X archivefd = open(ar_file, O_RDONLY | O_BINARY);
X bufend = bufidx = bufstart; /* set up for initial read */
X } else if (mode == AR_WRITE) {
X archivefd = open(ar_file, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0666);
X } else if (mode == AR_APPEND) {
X archivefd = open(ar_file, O_RDWR | O_BINARY, 0666);
X bufend = bufidx = bufstart; /* set up for initial read */
X }
X
X if (archivefd < 0) {
X warnarch(syserr(), (OFFSET) 0);
X return (-1);
X }
X ++arvolume;
X return (0);
X}
X
X
X/* close_archive - close the archive file
X *
X * DESCRIPTION
X *
X * Closes the current archive and resets the archive end of file
X * marker.
X */
X
X#ifdef __STDC__
X
Xvoid close_archive(void)
X
X#else
X
Xvoid close_archive()
X
X#endif
X{
X if (archivefd != STDIN && archivefd != STDOUT) {
X close(archivefd);
X }
X areof = 0;
X}
X
X
X/* openo - open an output file
X *
X * DESCRIPTION
X *
X * Openo opens the named file for output. The file mode and type are
X * set based on the values stored in the stat structure for the file.
X * If the file is a special file, then no data will be written, the
X * file/directory/Fifo, etc., will just be created. Appropriate
X * permission may be required to create special files.
X *
X * PARAMETERS
X *
X * char *name - The name of the file to create
X * Stat *asb - Stat structure for the file
X * Link *linkp; - pointer to link chain for this file
X * int ispass - true if we are operating in "pass" mode
X *
X * RETURNS
X *
X * Returns the output file descriptor, 0 if no data is required or -1
X * if unsuccessful. Note that UNIX open() will never return 0 because
X * the standard input is in use.
X */
X
X#ifdef __STDC__
X
Xint openo(char *name, Stat *asb, Link *linkp, int ispass)
X
X#else
X
Xint openo(name, asb, linkp, ispass)
Xchar *name;
XStat *asb;
XLink *linkp;
Xint ispass;
X
X#endif
X{
X int exists;
X int fd;
X ushort perm;
X ushort operm = 0;
X Stat osb;
X#ifdef S_IFLNK
X int ssize;
X char sname[PATH_MAX + 1];
X#endif /* S_IFLNK */
X
X if (exists = (LSTAT(name, &osb) == 0)) {
X if (ispass && osb.sb_ino == asb->sb_ino && osb.sb_dev == asb->sb_dev) {
X warn(name, "Same file");
X return (-1);
X } else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT)) {
X operm = osb.sb_mode & S_IPERM;
X } else if (REMOVE(name, &osb) < 0) {
X warn(name, syserr());
X return (-1);
X } else {
X exists = 0;
X }
X }
X if (linkp) {
X if (exists) {
X if (asb->sb_ino == osb.sb_ino && asb->sb_dev == osb.sb_dev) {
X return (0);
X } else if (unlink(name) < 0) {
X warn(name, syserr());
X return (-1);
X } else {
X exists = 0;
X }
X }
X if (link(linkp->l_name, name) != 0) {
X if (errno == ENOENT) {
X if (f_create_dirs) {
X if (dirneed(name) != 0 ||
X link(linkp->l_name, name) != 0) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X warn(name,
X "Directories are not being created (-d option)");
X }
X return(0);
X } else if (errno != EXDEV) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X return(0);
X }
X }
X perm = asb->sb_mode & S_IPERM;
X switch (asb->sb_mode & S_IFMT) {
X case S_IFBLK:
X case S_IFCHR:
X fd = 0;
X if (exists) {
X if (asb->sb_rdev == osb.sb_rdev) {
X if (perm != operm && chmod(name, (int) perm) < 0) {
X warn(name, syserr());
X return (-1);
X } else {
X break;
X }
X } else if (REMOVE(name, &osb) < 0) {
X warn(name, syserr());
X return (-1);
X } else {
X exists = 0;
X }
X }
X if (mknod(name, (int) asb->sb_mode, (int) asb->sb_rdev) < 0) {
X if (errno == ENOENT) {
X if (f_create_dirs) {
X if (dirneed(name) < 0 || mknod(name, (int) asb->sb_mode,
X (int) asb->sb_rdev) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X warn(name, "Directories are not being created (-d option)");
X }
X } else {
X warn(name, syserr());
X return (-1);
X }
X }
X return(0);
X break;
X case S_IFDIR:
X if (exists) {
X if (perm != operm && chmod(name, (int) perm) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else if (f_create_dirs) {
X if (dirmake(name, asb) < 0 || dirneed(name) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X warn(name, "Directories are not being created (-d option)");
X }
X return (0);
X#ifdef S_IFIFO
X case S_IFIFO:
X fd = 0;
X if (exists) {
X if (perm != operm && chmod(name, (int) perm) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else if (mknod(name, (int) asb->sb_mode, 0) < 0) {
X if (errno == ENOENT) {
X if (f_create_dirs) {
X if (dirneed(name) < 0
X || mknod(name, (int) asb->sb_mode, 0) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X warn(name, "Directories are not being created (-d option)");
X }
X } else {
X warn(name, syserr());
X return (-1);
X }
X }
X return(0);
X break;
X#endif /* S_IFIFO */
X#ifdef S_IFLNK
X case S_IFLNK:
X if (exists) {
X if ((ssize = readlink(name, sname, sizeof(sname))) < 0) {
X warn(name, syserr());
X return (-1);
X } else if (strncmp(sname, asb->sb_link, ssize) == 0) {
X return (0);
X } else if (REMOVE(name, &osb) < 0) {
X warn(name, syserr());
X return (-1);
X } else {
X exists = 0;
X }
X }
X if (symlink(asb->sb_link, name) < 0) {
X if (errno == ENOENT) {
X if (f_create_dirs) {
X if (dirneed(name) < 0 || symlink(asb->sb_link, name) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X warn(name, "Directories are not being created (-d option)");
X }
X } else {
X warn(name, syserr());
X return (-1);
X }
X }
X return (0); /* Can't chown()/chmod() a symbolic link */
X#endif /* S_IFLNK */
X case S_IFREG:
X if (exists) {
X if (!f_unconditional && osb.sb_mtime > asb->sb_mtime) {
X warn(name, "Newer file exists");
X return (-1);
X } else if (unlink(name) < 0) {
X warn(name, syserr());
X return (-1);
X } else {
X exists = 0;
X }
X }
X if ((fd = creat(name, (int) perm)) < 0) {
X if (errno == ENOENT) {
X if (f_create_dirs) {
X if (dirneed(name) < 0 ||
X (fd = creat(name, (int) perm)) < 0) {
X warn(name, syserr());
X return (-1);
X }
X } else {
X /*
X * the file requires a directory which does not exist
X * and which the user does not want created, so skip
X * the file...
X */
X warn(name, "Directories are not being created (-d option)");
X return(0);
X }
X } else {
X warn(name, syserr());
X return (-1);
X }
X }
X break;
X default:
X warn(name, "Unknown filetype");
X return (-1);
X }
X if (f_owner) {
X if (!exists || asb->sb_uid != osb.sb_uid || asb->sb_gid != osb.sb_gid) {
X chown(name, (int) asb->sb_uid, (int) asb->sb_gid);
X }
X }
X return (fd);
X}
X
X
X/* openi - open the next input file
X *
X * DESCRIPTION
X *
X * Openi will attempt to open the next file for input. If the file is
X * a special file, such as a directory, FIFO, link, character- or
X * block-special file, then the file size field of the stat structure
X * is zeroed to make sure that no data is written out for the file.
X * If the file is a special file, then a file descriptor of 0 is
X * returned to the caller, which is handled specially. If the file
X * is a regular file, then the file is opened and a file descriptor
X * to the open file is returned to the caller.
X *
X * PARAMETERS
X *
X * char *name - pointer to the name of the file to open
X * Stat *asb - pointer to the stat block for the file to open
X *
X * RETURNS
X *
X * Returns a file descriptor, 0 if no data exists, or -1 at EOF. This
X * kludge works because standard input is in use, preventing open() from
X * returning zero.
X */
X
X#ifdef __STDC__
X
Xint openi(char *name, Stat *asb)
X
X#else
X
Xint openi(name, asb)
Xchar *name; /* name of file to open */
XStat *asb; /* pointer to stat structure for file */
X
X#endif
X{
X int fd;
X
X switch (asb->sb_mode & S_IFMT) {
X case S_IFDIR:
X asb->sb_nlink = 1;
X asb->sb_size = 0;
X return (0);
X#ifdef S_IFLNK
X case S_IFLNK:
X if ((asb->sb_size = readlink(name,
X asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
X warn(name, syserr());
X return(0);
X }
X asb->sb_link[asb->sb_size] = '\0';
X return (0);
X#endif /* S_IFLNK */
X case S_IFREG:
X if (asb->sb_size == 0) {
X return (0);
X }
X if ((fd = open(name, O_RDONLY | O_BINARY)) < 0) {
X warn(name, syserr());
X }
X return (fd);
X default:
X asb->sb_size = 0;
X return (0);
X }
X}
END_OF_fileio.c
if test 10596 -ne `wc -c <fileio.c`; then
echo shar: \"fileio.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f namelist.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"namelist.c\"
else
echo shar: Extracting \"namelist.c\" \(11056 characters\)
sed "s/^X//" >namelist.c <<'END_OF_namelist.c'
X/* $Source: /u/mark/src/pax/RCS/namelist.c,v $
X *
X * $Revision: 1.1 $
X *
X * namelist.c - track filenames given as arguments to tar/cpio/pax
X *
X * DESCRIPTION
X *
X * Arguments may be regular expressions, therefore all agurments will
X * be treated as if they were regular expressions, even if they are
X * not.
X *
X * AUTHOR
X *
X * Mark H. Colburn, NAPS International (mark at jhereg.mn.org)
X *
X * Sponsored by The USENIX Association for public distribution.
X *
X * Copyright (c) 1989 Mark H. Colburn.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in all such
X * forms and that any documentation, advertising materials, and other
X * materials related to such distribution and use acknowledge that the
X * software was developed * by Mark H. Colburn and sponsored by The
X * USENIX Association.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * $Log: namelist.c,v $
X * Revision 1.1 88/12/23 18:02:17 mark
X * Initial revision
X *
X */
X
X#ifndef lint
Xstatic char *ident = "$Id: namelist.c,v 1.1 88/12/23 18:02:17 mark Rel $";
Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
X#endif /* ! lint */
X
X
X/* Headers */
X
X#include "pax.h"
X
X
X/* Type Definitions */
X
X/*
X * Structure for keeping track of filenames and lists thereof.
X */
Xstruct nm_list {
X struct nm_list *next;
X short length; /* cached strlen(name) */
X char found; /* A matching file has been found */
X char firstch; /* First char is literally matched */
X char regexp; /* regexp pattern for item */
X char name[1]; /* name of file or rexexp */
X};
X
Xstruct dirinfo {
X char dirname[PATH_MAX + 1]; /* name of directory */
X OFFSET where; /* current location in directory */
X struct dirinfo *next;
X};
X
X
X/* Function Prototypes */
X
X#ifndef __STDC__
X
Xstatic void pushdir();
Xstatic struct dirinfo *popdir();
X
X#else
X
Xstatic void pushdir(struct dirinfo *info);
Xstatic struct dirinfo *popdir(void);
X
X#endif
X
X
X/* Internal Identifiers */
X
Xstatic struct nm_list *namelast; /* Points to last name in list */
Xstatic struct nm_list *namelist; /* Points to first name in list */
X
X
X/* addname - add a name to the namelist.
X *
X * DESCRIPTION
X *
X * Addname adds the name given to the name list. Memory for the
X * namelist structure is dynamically allocated. If the space for
X * the structure cannot be allocated, then the program will exit
X * the an out of memory error message and a non-zero return code
X * will be returned to the caller.
X *
X * PARAMETERS
X *
X * char *name - A pointer to the name to add to the list
X */
X
X#ifdef __STDC__
X
Xvoid add_name(char *name)
X
X#else
X
Xvoid add_name(name)
Xchar *name; /* pointer to name */
X
X#endif
X{
X int i; /* Length of string */
X struct nm_list *p; /* Current struct pointer */
X
X i = strlen(name);
X p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
X if (!p) {
X fatal("cannot allocate memory for namelist entry\n");
X }
X p->next = (struct nm_list *) NULL;
X p->length = i;
X strncpy(p->name, name, i);
X p->name[i] = '\0'; /* Null term */
X p->found = 0;
X p->firstch = isalpha(name[0]);
X if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
X p->regexp = 1;
X }
X if (namelast) {
X namelast->next = p;
X }
X namelast = p;
X if (!namelist) {
X namelist = p;
X }
X}
X
X
X/* name_match - match a name from an archive with a name from the namelist
X *
X * DESCRIPTION
X *
X * Name_match attempts to find a name pointed at by p in the namelist.
X * If no namelist is available, then all filenames passed in are
X * assumed to match the filename criteria. Name_match knows how to
X * match names with regular expressions, etc.
X *
X * PARAMETERS
X *
X * char *p - the name to match
X *
X * RETURNS
X *
X * Returns 1 if the name is in the namelist, or no name list is
X * available, otherwise returns 0
X *
X */
X
X#ifdef __STDC__
X
Xint name_match(char *p)
X
X#else
X
Xint name_match(p)
Xchar *p;
X
X#endif
X{
X struct nm_list *nlp;
X int len;
X
X if ((nlp = namelist) == 0) {/* Empty namelist is easy */
X return (1);
X }
X len = strlen(p);
X for (; nlp != 0; nlp = nlp->next) {
X /* If first chars don't match, quick skip */
X if (nlp->firstch && nlp->name[0] != p[0]) {
X continue;
X }
X /* Regular expressions */
X if (nlp->regexp) {
X if (wildmat(nlp->name, p)) {
X nlp->found = 1; /* Remember it matched */
X return (1); /* We got a match */
X }
X continue;
X }
X /* Plain Old Strings */
X if (nlp->length <= len /* Archive len >= specified */
X && (p[nlp->length] == '\0' || p[nlp->length] == '/')
X && strncmp(p, nlp->name, nlp->length) == 0) {
X /* Name compare */
X nlp->found = 1; /* Remember it matched */
X return (1); /* We got a match */
X }
X }
X return (0);
X}
X
X
X/* names_notfound - print names of files in namelist that were not found
X *
X * DESCRIPTION
X *
X * Names_notfound scans through the namelist for any files which were
X * named, but for which a matching file was not processed by the
X * archive. Each of the files is listed on the standard error.
X *
X */
X
X#ifdef __STDC__
X
Xvoid names_notfound(void)
X
X#else
X
Xvoid names_notfound()
X
X#endif
X{
X struct nm_list *nlp;
X
X for (nlp = namelist; nlp != 0; nlp = nlp->next) {
X if (!nlp->found) {
X fprintf(stderr, "%s: %s not found in archive\n",
X myname, nlp->name);
X }
X free(nlp);
X }
X namelist = (struct nm_list *) NULL;
X namelast = (struct nm_list *) NULL;
X}
X
X
X/* name_init - set up to gather file names
X *
X * DESCRIPTION
X *
X * Name_init sets up the namelist pointers so that we may access the
X * command line arguments. At least the first item of the command
X * line (argv[0]) is assumed to be stripped off, prior to the
X * name_init call.
X *
X * PARAMETERS
X *
X * int argc - number of items in argc
X * char **argv - pointer to the command line arguments
X */
X
X#ifdef __STDC__
X
Xvoid name_init(int argc, char **argv)
X
X#else
X
Xvoid name_init(argc, argv)
Xint argc;
Xchar **argv;
X
X#endif
X{
X /* Get file names from argv, after options. */
X n_argc = argc;
X n_argv = argv;
X}
X
X
X/* name_next - get the next name from argv or the name file.
X *
X * DESCRIPTION
X *
X * Name next finds the next name which is to be processed in the
X * archive. If the named file is a directory, then the directory
X * is recursively traversed for additional file names. Directory
X * names and locations within the directory are kept track of by
X * using a directory stack. See the pushdir/popdir function for
X * more details.
X *
X * The names come from argv, after options or from the standard input.
X *
X * PARAMETERS
X *
X * name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
X * statbuf - a pointer to a stat structure
X *
X * RETURNS
X *
X * Returns -1 if there are no names left, (e.g. EOF), otherwise returns
X * 0
X */
X
X#ifdef __STDC__
X
Xint name_next(char *name, Stat *statbuf)
X
X#else
X
Xint name_next(name, statbuf)
Xchar *name;
XStat *statbuf;
X
X#endif
X{
X int err = -1;
X static int in_subdir = 0;
X static DIR *dirp;
X struct dirent *d;
X static struct dirinfo *curr_dir;
X int len;
X
X do {
X if (names_from_stdin) {
X if (lineget(stdin, name) < 0) {
X return (-1);
X }
X if (nameopt(name) < 0) {
X continue;
X }
X } else {
X if (in_subdir) {
X if ((d = readdir(dirp)) != NULL) {
X /* Skip . and .. */
X if (strcmp(d->d_name, ".") == 0 ||
X strcmp(d->d_name, "..") == 0) {
X continue;
X }
X if (strlen(d->d_name) +
X strlen(curr_dir->dirname) >= PATH_MAX) {
X warn("name too long", d->d_name);
X continue;
X }
X strcpy(name, curr_dir->dirname);
X strcat(name, d->d_name);
X } else {
X closedir(dirp);
X in_subdir--;
X curr_dir = popdir();
X if (in_subdir) {
X errno = 0;
X if ((dirp = opendir(curr_dir->dirname)) == NULL) {
X warn(curr_dir->dirname, "error opening directory (1)");
X in_subdir--;
X }
X seekdir(dirp, curr_dir->where);
X }
X continue;
X }
X } else if (optind >= n_argc) {
X return (-1);
X } else {
X strcpy(name, n_argv[optind++]);
X }
X }
X if ((err = LSTAT(name, statbuf)) < 0) {
X warn(name, syserr());
X continue;
X }
X if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
X if (in_subdir) {
X curr_dir->where = telldir(dirp);
X pushdir(curr_dir);
X close(dirp);
X }
X in_subdir++;
X
X /* Build new prototype name */
X if ((curr_dir = (struct dirinfo *)
X mem_get(sizeof(struct dirinfo))) == NULL) {
X exit(2);
X }
X strcpy(curr_dir->dirname, name);
X len = strlen(curr_dir->dirname);
X while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
X len--; /* Delete trailing slashes */
X }
X curr_dir->dirname[len++] = '/'; /* Now add exactly one back */
X curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
X
X errno = 0;
X if ((dirp = opendir(curr_dir->dirname)) == NULL) {
X warn(curr_dir->dirname, "error opening directory (2)");
X }
X }
X } while (err < 0);
X return (0);
X}
X
X
X/* name_gather - gather names in a list for scanning.
X *
X * DESCRIPTION
X *
X * Name_gather takes names from the command line and adds them to
X * the name list.
X *
X * FIXME
X *
X * We could hash the names if we really care about speed here.
X */
X
X#ifdef __STDC__
X
Xvoid name_gather(void)
X
X#else
X
Xvoid name_gather()
X
X#endif
X{
X while (optind < n_argc) {
X add_name(n_argv[optind++]);
X }
X}
X
X
Xstatic struct dirinfo *stack_head = NULL;
X
X
X/* pushdir - pushes a directory name on the directory stack
X *
X * DESCRIPTION
X *
X * The pushdir function puses the directory structure which is pointed
X * to by "info" onto a stack for later processing. The information
X * may be retrieved later with a call to popdir().
X *
X * PARAMETERS
X *
X * dirinfo *info - pointer to directory structure to save
X */
X
X#ifdef __STDC__
X
Xstatic void pushdir(struct dirinfo *info)
X
X#else
X
Xstatic void pushdir(info)
Xstruct dirinfo *info;
X
X#endif
X{
X if (stack_head == NULL) {
X stack_head = info;
X stack_head->next = NULL;
X } else {
X info->next = stack_head;
X stack_head = info;
X }
X}
X
X
X/* popdir - pop a directory structure off the directory stack.
X *
X * DESCRIPTION
X *
X * The popdir function pops the most recently pushed directory
X * structure off of the directory stack and returns it to the calling
X * function.
X *
X * RETURNS
X *
X * Returns a pointer to the most recently pushed directory structure
X * or NULL if the stack is empty.
X */
X
X#ifdef __STDC__
X
Xstatic struct dirinfo *popdir(void)
X
X#else
X
Xstatic struct dirinfo *popdir()
X
X#endif
X{
X struct dirinfo *tmp;
X
X if (stack_head == NULL) {
X return(NULL);
X } else {
X tmp = stack_head;
X stack_head = stack_head->next;
X }
X return(tmp);
X}
END_OF_namelist.c
if test 11056 -ne `wc -c <namelist.c`; then
echo shar: \"namelist.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pax.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"pax.c\"
else
echo shar: Extracting \"pax.c\" \(13026 characters\)
sed "s/^X//" >pax.c <<'END_OF_pax.c'
X/* $Source: /u/mark/src/pax/RCS/pax.c,v $
X *
X * $Revision: 1.1 $
X *
X * DESCRIPTION
X *
X * Pax is the archiver described in IEEE P1003.2. It is an archiver
X * which understands both tar and cpio archives and has a new interface.
X *
X * SYNOPSIS
X *
X * pax -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
X * pax -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
X * pax -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]...]
X * [-t device][-x format][pathname...]
X * pax -r -w [-ilmopuvy][-s replstr][pathname...] directory
X *
X * DESCRIPTION
X *
X * PAX - POSIX conforming tar and cpio archive handler. This
X * program implements POSIX conformant versions of tar, cpio and pax
X * archive handlers for UNIX. These handlers have defined befined
X * by the IEEE P1003.2 commitee.
X *
X * COMPILATION
X *
X * A number of different compile time configuration options are
X * available, please see the Makefile and config.h for more details.
X *
X * AUTHOR
X *
X * Mark H. Colburn, NAPS International (mark at jhereg.mn.org)
X *
X *
X * Sponsored by The USENIX Association for public distribution.
X *
X * Copyright (c) 1989 Mark H. Colburn.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in all such
X * forms and that any documentation, advertising materials, and other
X * materials related to such distribution and use acknowledge that the
X * software was developed * by Mark H. Colburn and sponsored by The
X * USENIX Association.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * $Log: pax.c,v $
X * Revision 1.1 88/12/23 18:02:23 mark
X * Initial revision
X *
X */
X
X#ifndef lint
Xstatic char *ident = "$Id: pax.c,v 1.1 88/12/23 18:02:23 mark Rel $";
Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
X#endif /* ! lint */
X
X
X/* Headers */
X
X#define NO_EXTERN
X#include "pax.h"
X
X
X/* Globally Available Identifiers */
X
Xchar *ar_file; /* File containing name of archive */
Xchar *bufend; /* End of data within archive buffer */
Xchar *bufstart; /* Archive buffer */
Xchar *bufidx; /* Archive buffer index */
Xchar *myname; /* name of executable (argv[0]) */
Xchar **n_argv; /* Argv used by name routines */
Xint n_argc; /* Argc used by name routines */
Xint archivefd; /* Archive file descriptor */
Xint blocking; /* Size of each block, in records */
Xint gid; /* Group ID */
Xint head_standard; /* true if archive is POSIX format */
Xint ar_interface; /* defines interface we are using */
Xint ar_format; /* defines current archve format */
Xint mask; /* File creation mask */
Xint ttyf; /* For interactive queries */
Xint uid; /* User ID */
Xint names_from_stdin; /* names for files are from stdin */
XOFFSET total; /* Total number of bytes transferred */
Xshort f_access_time; /* Reset access times of input files */
Xshort areof; /* End of input volume reached */
Xshort f_create_dirs; /* Create missing directories */
Xshort f_append; /* Add named files to end of archive */
Xshort f_create; /* create a new archive */
Xshort f_extract; /* Extract named files from archive */
Xshort f_follow_links; /* follow symbolic links */
Xshort f_interactive; /* Interactivly extract files */
Xshort f_linksleft; /* Report on unresolved links */
Xshort f_list; /* List files on the archive */
Xshort f_modified; /* Don't restore modification times */
Xshort f_verbose; /* Turn on verbose mode */
Xshort f_link; /* link files where possible */
Xshort f_owner; /* extract files as the user */
Xshort f_pass; /* pass files between directories */
Xshort f_newer; /* append files to archive if newer */
Xshort f_disposition; /* ask for file disposition */
Xshort f_reverse_match; /* Reverse sense of pattern match */
Xshort f_modification_time; /* Retain file modification time */
Xshort f_unconditional; /* Copy unconditionally */
Xtime_t now = 0; /* Current time */
Xuint arvolume; /* Volume number */
Xuint blocksize = BLOCKSIZE; /* Archive block size */
XFILE *msgfile; /* message outpu file stdout/stderr */
XReplstr *rplhead = NULL; /* pointer to head of replstr list */
XReplstr *rpltail; /* pointer to tail of replstr list */
X
X
X/* Function Prototypes */
X
X#ifdef __STDC__
X
Xstatic void usage(void);
Xstatic OFFSET pax_optsize(char *);
X
X#else /* !__STDC__ */
X
Xstatic void usage();
Xstatic OFFSET pax_optsize();
X
X#endif /* __STDC__ */
X
X
X/* main - main routine for handling all archive formats.
X *
X * DESCRIPTION
X *
X * Set up globals and call the proper interface as specified by the user.
X *
X * PARAMETERS
X *
X * int argc - count of user supplied arguments
X * char **argv - user supplied arguments
X *
X * RETURNS
X *
X * Returns an exit code of 0 to the parent process.
X */
X
X#ifdef __STDC__
X
Xint main(int argc, char **argv)
X
X#else
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X
X#endif
X{
X /* strip the pathname off of the name of the executable */
X if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
X myname++;
X } else {
X myname = argv[0];
X }
X
X /* set upt for collecting other command line arguments */
X name_init(argc, argv);
X
X /* get all our necessary information */
X mask = umask(0);
X uid = getuid();
X gid = getgid();
X now = time((time_t *) 0);
X
X /* open terminal for interactive queries */
X ttyf = open_tty();
X
X if (strcmp(myname, "tar")==0) {
X do_tar(argc, argv);
X } else if (strcmp(myname, "cpio")==0) {
X do_cpio(argc, argv);
X } else {
X do_pax(argc, argv);
X }
X exit(0);
X /* NOTREACHED */
X}
X
X
X/* do_pax - provide a PAX conformant user interface for archive handling
X *
X * DESCRIPTION
X *
X * Process the command line parameters given, doing some minimal sanity
X * checking, and then launch the specified archiving functions.
X *
X * PARAMETERS
X *
X * int ac - A count of arguments in av. Should be passed argc
X * from main
X * char **av - A pointer to an argument list. Should be passed
X * argv from main
X *
X * RETURNS
X *
X * Normally returns 0. If an error occurs, -1 is returned
X * and state is set to reflect the error.
X *
X */
X
X#ifdef __STDC__
X
Xint do_pax(int ac, char **av)
X
X#else
X
Xint do_pax(ac, av)
Xint ac; /* argument counter */
Xchar **av; /* arguments */
X
X#endif
X{
X int c;
X char *dirname;
X Stat st;
X
X /* default input/output file for PAX is STDIN/STDOUT */
X ar_file = "-";
X
X /*
X * set up the flags to reflect the default pax inteface. Unfortunately
X * the pax interface has several options which are completely opposite
X * of the tar and/or cpio interfaces...
X */
X f_unconditional = 1;
X f_modification_time = 1;
X f_create_dirs = 1;
X f_list = 1;
X blocksize = 0;
X blocking = 0;
X ar_interface = PAX;
X ar_format = TAR; /* default interface if none given for -w */
X msgfile=stdout;
X
X while ((c = getopt(ac, av, "ab:cdf:ilmoprs:t:uvwx:y")) != EOF) {
X switch (c) {
X case 'a':
X f_append = 1;
X f_list = 0;
X break;
X case 'b':
X if ((blocksize = pax_optsize(optarg)) == 0) {
X fatal("Bad block size");
X }
X break;
X case 'c':
X f_reverse_match = 1;
X break;
X case 'd':
X f_create_dirs = 0;
X break;
X case 'f':
X if (blocksize == 0) {
X blocking = 1;
X blocksize = 1 * BLOCKSIZE;
X }
X ar_file = optarg;
X break;
X case 'i':
X f_interactive = 1;
X break;
X case 'l':
X f_link = 1;
X break;
X case 'm':
X f_modification_time = 0;
X break;
X case 'o':
X f_owner = 1;
X break;
X case 'p':
X f_access_time = 1;
X break;
X case 'r':
X if (f_create) {
X f_create = 0;
X f_pass = 1;
X } else {
X f_list = 0;
X f_extract = 1;
X }
X msgfile=stderr;
X break;
X case 's':
X add_replstr(optarg);
X break;
X case 't':
X if (blocksize == 0) {
X blocking = 1;
X blocksize = 10 * BLOCKSIZE;
X }
X ar_file = optarg;
X break;
X case 'u':
X f_unconditional = 1;
X break;
X case 'v':
X f_verbose = 1;
X break;
X case 'w':
X if (f_extract) {
X f_extract = 0;
X f_pass = 1;
X } else {
X f_list = 0;
X f_create = 1;
X }
X msgfile=stderr;
X break;
X case 'x':
X if (strcmp(optarg, "ustar") == 0) {
X ar_format = TAR;
X } else if (strcmp(optarg, "cpio") == 0) {
X ar_format = CPIO;
X } else {
X usage();
X }
X break;
X case 'y':
X f_disposition = 1;
X break;
X default:
X usage();
X }
X }
X
X if (blocksize == 0) {
X blocking = 1;
X blocksize = blocking * BLOCKSIZE;
X }
X buf_allocate((OFFSET) blocksize);
X
X if (f_extract || f_list) {
X open_archive(AR_READ);
X get_archive_type();
X read_archive();
X } else if (f_create) {
X if (optind >= n_argc) {
X names_from_stdin++; /* args from stdin */
X }
X open_archive(AR_WRITE);
X create_archive();
X } else if (f_append) {
X open_archive(AR_APPEND);
X get_archive_type();
X append_archive();
X } else if (f_pass && optind < n_argc) {
X dirname = n_argv[--n_argc];
X if (LSTAT(dirname, &st) < 0) {
X fatal(syserr());
X }
X if ((st.sb_mode & S_IFMT) != S_IFDIR) {
X fatal("Not a directory");
X }
X if (optind >= n_argc) {
X names_from_stdin++; /* args from stdin */
X }
X pass(dirname);
X } else {
X usage();
X }
X
X return (0);
X}
X
X
X/* get_archive_type - determine input archive type from archive header
X *
X * DESCRIPTION
X *
X * reads the first block of the archive and determines the archive
X * type from the data. If the archive type cannot be determined,
X * processing stops, and a 1 is returned to the caller. If verbose
X * mode is on, then the archive type will be printed on the standard
X * error device as it is determined.
X *
X * FIXME
X *
X * be able to understand TAR and CPIO magic numbers
X */
X
X#ifdef __STDC__
X
Xvoid get_archive_type(void)
X
X#else
X
Xvoid get_archive_type()
X
X#endif
X{
X if (ar_read() != 0) {
X fatal("Unable to determine archive type.");
X }
X if (strncmp(bufstart, "070707", 6) == 0) {
X ar_format = CPIO;
X if (f_verbose) {
X fputs("CPIO format archive\n", stderr);
X }
X } else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
X ar_format = TAR;
X if (f_verbose) {
X fputs("USTAR format archive\n", stderr);
X }
X } else {
X ar_format = TAR;
X }
X}
X
X
X/* pax_optsize - interpret a size argument
X *
X * DESCRIPTION
X *
X * Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.
X * Also handles simple expressions containing '+' for addition.
X *
X * PARAMETERS
X *
X * char *str - A pointer to the string to interpret
X *
X * RETURNS
X *
X * Normally returns the value represented by the expression in the
X * the string.
X *
X * ERRORS
X *
X * If the string cannot be interpretted, the program will fail, since
X * the buffering will be incorrect.
X *
X */
X
X#ifdef __STDC__
X
Xstatic OFFSET pax_optsize(char *str)
X
X#else
X
Xstatic OFFSET pax_optsize(str)
Xchar *str; /* pointer to string to interpret */
X
X#endif
X{
X char *idx;
X OFFSET number; /* temporary storage for current number */
X OFFSET result; /* cumulative total to be returned to caller */
X
X result = 0;
X idx = str;
X for (;;) {
X number = 0;
X while (*idx >= '0' && *idx <= '9')
X number = number * 10 + *idx++ - '0';
X switch (*idx++) {
X case 'b':
X result += number * 512;
X continue;
X case 'k':
X result += number * 1024;
X continue;
X case 'm':
X result += number * 1024 * 1024;
X continue;
X case '+':
X result += number;
X continue;
X case '\0':
X result += number;
X break;
X default:
X break;
X }
X break;
X }
X if (*--idx) {
X fatal("Unrecognizable value");
X }
X return (result);
X}
X
X
X/* usage - print a helpful message and exit
X *
X * DESCRIPTION
X *
X * Usage prints out the usage message for the PAX interface and then
X * exits with a non-zero termination status. This is used when a user
X * has provided non-existant or incompatible command line arguments.
X *
X * RETURNS
X *
X * Returns an exit status of 1 to the parent process.
X *
X */
X
X#ifdef __STDC__
X
Xstatic void usage(void)
X
X#else
X
Xstatic void usage()
X
X#endif
X{
X fprintf(stderr, "\
XUsage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
X myname);
X fprintf(stderr, "\
X %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
X myname);
X fprintf(stderr, "\
X %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n\
X [-t device] [-x format] [pathname...]\n",
X myname);
X fprintf(stderr, "\
X %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
X myname);
X exit(1);
X}
END_OF_pax.c
if test 13026 -ne `wc -c <pax.c`; then
echo shar: \"pax.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pax.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"pax.h\"
else
echo shar: Extracting \"pax.h\" \(9317 characters\)
sed "s/^X//" >pax.h <<'END_OF_pax.h'
X/* $Source: /u/mark/src/pax/RCS/pax.h,v $
X *
X * $Revision: 1.1 $
X *
X * pax.h - defnitions for entire program
X *
X * DESCRIPTION
X *
X * This file contains most all of the definitions required by the PAX
X * software. This header is included in every source file.
X *
X * AUTHOR
X *
X * Mark H. Colburn, NAPS International (mark at jhereg.mn.org)
X *
X * Sponsored by The USENIX Association for public distribution.
X *
X * Copyright (c) 1989 Mark H. Colburn.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Mark H. Colburn and sponsored by The USENIX Association.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef _PAX_H
X#define _PAX_H
X
X/* Headers */
X
X#include "config.h"
X#include "limits.h"
X#include <stdio.h>
X#include <errno.h>
X#include <signal.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/ioctl.h>
X#include <sys/stat.h>
X#include "regexp.h"
X
X#if defined(DIRENT) || defined(_POSIX_SOURCE)
X# ifdef PAXDIR
X# include "paxdir.h"
X# else
X# include <dirent.h>
X# endif
X#else
X# include <sys/dir.h>
X# define dirent direct
X#endif
X
X#ifndef major
X# include <sys/sysmacros.h>
X#endif /* major */
X
X#ifdef SYSTIME
X# include <sys/time.h>
X#else /* SYSTIME */
X# include <time.h>
X#endif /* SYSTIME */
X
X#ifndef V7
X# include <fcntl.h>
X#endif
X
X#ifdef XENIX
X# include <sys/inode.h>
X#endif
X
X#include <pwd.h>
X#include <grp.h>
X#include <sys/file.h>
X
X/* Defines */
X
X#define STDIN 0 /* Standard input file descriptor */
X#define STDOUT 1 /* Standard output file descriptor */
X
X/*
X * Open modes; there is no <fcntl.h> with v7 UNIX and other versions of
X * UNIX may not have all of these defined...
X */
X
X#ifndef O_RDONLY
X# define O_RDONLY 0
X#endif
X
X#ifndef O_WRONLY
X# define O_WRONLY 1
X#endif
X
X#ifndef O_RDWR
X# define O_WRONLY 2
X#endif
X
X#ifndef O_BINARY
X# define O_BINARY 0
X#endif
X
X#ifndef NULL
X# define NULL 0
X#endif
X
X#define TMAGIC "ustar" /* ustar and a null */
X#define TMAGLEN 6
X#define TVERSION "00" /* 00 and no null */
X#define TVERSLEN 2
X
X/* Values used in typeflag field */
X#define REGTYPE '0' /* Regular File */
X#define AREGTYPE '\0' /* Regular File */
X#define LNKTYPE '1' /* Link */
X#define SYMTYPE '2' /* Reserved */
X#define CHRTYPE '3' /* Character Special File */
X#define BLKTYPE '4' /* Block Special File */
X#define DIRTYPE '5' /* Directory */
X#define FIFOTYPE '6' /* FIFO */
X#define CONTTYPE '7' /* Reserved */
X
X#define BLOCKSIZE 512 /* all output is padded to 512 bytes */
X#define uint unsigned int /* Not always in types.h */
X#define ushort unsigned short /* Not always in types.h */
X#define BLOCK 5120 /* Default archive block size */
X#define H_COUNT 10 /* Number of items in ASCII header */
X#define H_PRINT "%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo"
X#define H_SCAN "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6o%11lo"
X#define H_STRLEN 70 /* ASCII header string length */
X#define M_ASCII "070707" /* ASCII magic number */
X#define M_BINARY 070707 /* Binary magic number */
X#define M_STRLEN 6 /* ASCII magic number length */
X#define PATHELEM 256 /* Pathname element count limit */
X#define S_IFSHF 12 /* File type shift (shb in stat.h) */
X#define S_IPERM 07777 /* File permission bits (shb in stat.h) */
X#define S_IPEXE 07000 /* Special execution bits (shb in stat.h) */
X#define S_IPOPN 0777 /* Open access bits (shb in stat.h) */
X
X/*
X * Trailer pathnames. All must be of the same length.
X */
X#define TRAILER "TRAILER!!!" /* Archive trailer (cpio compatible) */
X#define TRAILZ 11 /* Trailer pathname length (including null) */
X
X#include "port.h"
X
X
X#define TAR 1
X#define CPIO 2
X#define PAX 3
X
X#define AR_READ 0
X#define AR_WRITE 1
X#define AR_EXTRACT 2
X#define AR_APPEND 4
X
X/*
X * Header block on tape.
X */
X#define NAMSIZ 100
X#define PFIXSIZ 155
X#define TUNMLEN 32
X#define TGNMLEN 32
X
X/* The checksum field is filled with this while the checksum is computed. */
X#define CHKBLANKS " " /* 8 blanks, no null */
X
X/*
X * Exit codes from the "tar" program
X */
X#define EX_SUCCESS 0 /* success! */
X#define EX_ARGSBAD 1 /* invalid args */
X#define EX_BADFILE 2 /* invalid filename */
X#define EX_BADARCH 3 /* bad archive */
X#define EX_SYSTEM 4 /* system gave unexpected error */
X
X#define ROUNDUP(a,b) (((a) % (b)) == 0 ? (a) : ((a) + ((b) - ((a) % (b)))))
X
X/*
X * Mininum value.
X */
X#define MIN(a, b) (((a) < (b)) ? (a) : (b))
X
X/*
X * Remove a file or directory.
X */
X#define REMOVE(name, asb) \
X (((asb)->sb_mode & S_IFMT) == S_IFDIR ? rmdir(name) : unlink(name))
X
X/*
X * Cast and reduce to unsigned short.
X */
X#define USH(n) (((ushort) (n)) & 0177777)
X
X
X/* Type Definitions */
X
X/*
X * Binary archive header (obsolete).
X */
Xtypedef struct {
X short b_dev; /* Device code */
X ushort b_ino; /* Inode number */
X ushort b_mode; /* Type and permissions */
X ushort b_uid; /* Owner */
X ushort b_gid; /* Group */
X short b_nlink; /* Number of links */
X short b_rdev; /* Real device */
X ushort b_mtime[2]; /* Modification time (hi/lo) */
X ushort b_name; /* Length of pathname (with null) */
X ushort b_size[2]; /* Length of data */
X} Binary;
X
X/*
X * File status with symbolic links. Kludged to hold symbolic link pathname
X * within structure.
X */
Xtypedef struct {
X struct stat sb_stat;
X char sb_link[PATH_MAX + 1];
X} Stat;
X
X#define STAT(name, asb) stat(name, &(asb)->sb_stat)
X#define FSTAT(fd, asb) fstat(fd, &(asb)->sb_stat)
X
X#define sb_dev sb_stat.st_dev
X#define sb_ino sb_stat.st_ino
X#define sb_mode sb_stat.st_mode
X#define sb_nlink sb_stat.st_nlink
X#define sb_uid sb_stat.st_uid
X#define sb_gid sb_stat.st_gid
X#define sb_rdev sb_stat.st_rdev
X#define sb_size sb_stat.st_size
X#define sb_atime sb_stat.st_atime
X#define sb_mtime sb_stat.st_mtime
X#define sb_ctime sb_stat.st_ctime
X
X#ifdef S_IFLNK
X# define LSTAT(name, asb) lstat(name, &(asb)->sb_stat)
X# define sb_blksize sb_stat.st_blksize
X# define sb_blocks sb_stat.st_blocks
X#else /* S_IFLNK */
X/*
X * File status without symbolic links.
X */
X# define LSTAT(name, asb) stat(name, &(asb)->sb_stat)
X#endif /* S_IFLNK */
X
X/*
X * Hard link sources. One or more are chained from each link structure.
X */
Xtypedef struct name {
X struct name *p_forw; /* Forward chain (terminated) */
X struct name *p_back; /* Backward chain (circular) */
X char *p_name; /* Pathname to link from */
X} Path;
X
X/*
X * File linking information. One entry exists for each unique file with with
X * outstanding hard links.
X */
Xtypedef struct link {
X struct link *l_forw; /* Forward chain (terminated) */
X struct link *l_back; /* Backward chain (terminated) */
X dev_t l_dev; /* Device */
X ino_t l_ino; /* Inode */
X ushort l_nlink; /* Unresolved link count */
X OFFSET l_size; /* Length */
X char *l_name; /* pathname to link from */
X Path *l_path; /* Pathname which link to l_name */
X} Link;
X
X/*
X * Structure for ed-style replacement strings (-s option).
X*/
Xtypedef struct replstr {
X regexp *comp; /* compiled regular expression */
X char *replace; /* replacement string */
X char print; /* >0 if we are to print replacement */
X char global; /* >0 if we are to replace globally */
X struct replstr *next; /* pointer to next record */
X} Replstr;
X
X
X/*
X * This has to be included here to insure that all of the type
X * delcarations are declared for the prototypes.
X */
X#include "func.h"
X
X
X#ifndef NO_EXTERN
X/* Globally Available Identifiers */
X
Xextern char *ar_file;
Xextern char *bufend;
Xextern char *bufstart;
Xextern char *bufidx;
Xextern char *myname;
Xextern int archivefd;
Xextern int blocking;
Xextern uint blocksize;
Xextern int gid;
Xextern int head_standard;
Xextern int ar_interface;
Xextern int ar_format;
Xextern int mask;
Xextern int ttyf;
Xextern int uid;
Xextern OFFSET total;
Xextern short areof;
Xextern short f_append;
Xextern short f_create;
Xextern short f_extract;
Xextern short f_follow_links;
Xextern short f_interactive;
Xextern short f_linksleft;
Xextern short f_list;
Xextern short f_modified;
Xextern short f_verbose;
Xextern short f_link;
Xextern short f_owner;
Xextern short f_access_time;
Xextern short f_pass;
Xextern short f_pass;
Xextern short f_disposition;
Xextern short f_reverse_match;
Xextern short f_modification_time;
Xextern short f_create_dirs;
Xextern short f_unconditional;
Xextern short f_newer;
Xextern time_t now;
Xextern uint arvolume;
Xextern int names_from_stdin;
Xextern Replstr *rplhead;
Xextern Replstr *rpltail;
Xextern char **n_argv;
Xextern int n_argc;
Xextern FILE *msgfile;
X#endif /* NO_EXTERN */
X
Xextern char *optarg;
Xextern int optind;
Xextern int sys_nerr;
Xextern char *sys_errlist[];
Xextern int errno;
X
X#endif /* _PAX_H */
END_OF_pax.h
if test 9317 -ne `wc -c <pax.h`; then
echo shar: \"pax.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f tar.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"tar.c\"
else
echo shar: Extracting \"tar.c\" \(7881 characters\)
sed "s/^X//" >tar.c <<'END_OF_tar.c'
X/* $Source: /u/mark/src/pax/RCS/tar.c,v $
X *
X * $Revision: 1.1 $
X *
X * tar.c - tar specific functions for archive handling
X *
X * DESCRIPTION
X *
X * These routines provide a tar conforming interface to the pax
X * program.
X *
X * AUTHOR
X *
X * Mark H. Colburn, NAPS International (mark at jhereg.mn.org)
X *
X * Sponsored by The USENIX Association for public distribution.
X *
X * Copyright (c) 1989 Mark H. Colburn.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in all such
X * forms and that any documentation, advertising materials, and other
X * materials related to such distribution and use acknowledge that the
X * software was developed by Mark H. Colburn and sponsored by The
X * USENIX Association.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * $Log: tar.c,v $
X * Revision 1.1 88/12/23 18:02:38 mark
X * Initial revision
X *
X */
X
X#ifndef lint
Xstatic char *ident = "$Id: tar.c,v 1.1 88/12/23 18:02:38 mark Rel $";
Xstatic char *copyright ="Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.";
X#endif /* not lint */
X
X/* Headers */
X
X#include "pax.h"
X
X
X/* Defines */
X
X#define DEF_BLOCKING 20 /* default blocking factor for extract */
X
X
X/* Function Prototypes */
X
X#ifdef __STDC__
X
Xstatic int taropt(int , char **, char *);
Xstatic void usage(void);
X
X#else /* !__STDC__ */
X
Xstatic int taropt();
Xstatic void usage();
X
X#endif /* __STDC__ */
X
X
X/* do_tar - main routine for tar.
X *
X * DESCRIPTION
X *
X * Provides a tar interface to the PAX program. All tar standard
X * command line options are supported.
X *
X * PARAMETERS
X *
X * int argc - argument count (argc from main)
X * char **argv - argument list (argv from main)
X *
X * RETURNS
X *
X * zero
X */
X
X#ifdef __STDC__
X
Xint do_tar(int argc, char **argv)
X
X#else
X
Xint do_tar(argc, argv)
Xint argc; /* argument count (argc from main) */
Xchar **argv; /* argument list (argv from main) */
X
X#endif
X{
X int c; /* Option letter */
X
X /* Set default option values */
X names_from_stdin = 0;
X ar_file = getenv("TAPE"); /* From environment, or */
X if (ar_file == 0) {
X ar_file = DEF_AR_FILE; /* From Makefile */
X }
X
X /*
X * set up the flags to reflect the default pax inteface. Unfortunately
X * the pax interface has several options which are completely opposite
X * of the tar and/or cpio interfaces...
X */
X f_unconditional = 1;
X f_modification_time = 1;
X f_create_dirs = 1;
X blocking = 0;
X ar_interface = TAR;
X ar_format = TAR;
X msgfile=stdout;
X
X /* Parse options */
X while ((c = taropt(argc, argv, "b:cf:hlmortuvwx")) != EOF) {
X switch (c) {
X case 'b': /* specify blocking factor */
X /*
X * FIXME - we should use a conversion routine that does
X * some kind of reasonable error checking, but...
X */
X blocking = atoi(optarg);
X break;
X case 'c': /* create a new archive */
X f_create = 1;
X break;
X case 'f': /* specify input/output file */
X ar_file = optarg;
X break;
X case 'h':
X f_follow_links = 1; /* follow symbolic links */
X break;
X case 'l': /* report unresolved links */
X f_linksleft = 1;
X break;
X case 'm': /* don't restore modification times */
X f_modified = 1;
X break;
X case 'o': /* take on user's group rather than
X * archives */
X break;
X case 'r': /* named files are appended to archive */
X f_append = 1;
X break;
X case 't':
X f_list = 1; /* list files in archive */
X break;
X case 'u': /* named files are added to archive */
X f_newer = 1;
X break;
X case 'v': /* verbose mode */
X f_verbose = 1;
X break;
X case 'w': /* user interactive mode */
X f_disposition = 1;
X break;
X case 'x': /* named files are extracted from archive */
X f_extract = 1;
X break;
X case '?':
X usage();
X exit(EX_ARGSBAD);
X }
X }
X
X /* check command line argument sanity */
X if (f_create + f_extract + f_list + f_append + f_newer != 1) {
X (void) fprintf(stderr,
X "%s: you must specify exactly one of the c, t, r, u or x options\n",
X myname);
X usage();
X exit(EX_ARGSBAD);
X }
X
X /* set the blocking factor, if not set by the user */
X if (blocking == 0) {
X#ifdef USG
X if (f_extract || f_list) {
X blocking = DEF_BLOCKING;
X fprintf(stderr, "Tar: blocksize = %d\n", blocking);
X } else {
X blocking = 1;
X }
X#else /* !USG */
X blocking = 20;
X#endif /* USG */
X }
X blocksize = blocking * BLOCKSIZE;
X buf_allocate((OFFSET) blocksize);
X
X if (f_create) {
X open_archive(AR_WRITE);
X create_archive(); /* create the archive */
X } else if (f_extract) {
X open_archive(AR_READ);
X read_archive(); /* extract files from archive */
X } else if (f_list) {
X open_archive(AR_READ);
X read_archive(); /* read and list contents of archive */
X } else if (f_append) {
X open_archive(AR_APPEND);
X append_archive(); /* append files to archive */
X }
X
X if (f_linksleft) {
X linkleft(); /* report any unresolved links */
X }
X
X return (0);
X}
X
X
X/* taropt - tar specific getopt
X *
X * DESCRIPTION
X *
X * Plug-compatible replacement for getopt() for parsing tar-like
X * arguments. If the first argument begins with "-", it uses getopt;
X * otherwise, it uses the old rules used by tar, dump, and ps.
X *
X * PARAMETERS
X *
X * int argc - argument count (argc from main)
X * char **argv - argument list (argv from main)
X * char *optstring - sring which describes allowable options
X *
X * RETURNS
X *
X * Returns the next option character in the option string(s). If the
X * option requires an argument and an argument was given, the argument
X * is pointed to by "optarg". If no option character was found,
X * returns an EOF.
X *
X */
X
X#ifdef __STDC__
X
Xstatic int taropt(int argc, char **argv, char *optstring)
X
X#else
X
Xstatic int taropt(argc, argv, optstring)
Xint argc;
Xchar **argv;
Xchar *optstring;
X
X#endif
X{
X extern char *optarg; /* Points to next arg */
X extern int optind; /* Global argv index */
X static char *key; /* Points to next keyletter */
X static char use_getopt; /* !=0 if argv[1][0] was '-' */
X char c;
X char *place;
X
X optarg = NULL;
X
X if (key == NULL) { /* First time */
X if (argc < 2)
X return EOF;
X key = argv[1];
X if (*key == '-')
X use_getopt++;
X else
X optind = 2;
X }
X if (use_getopt) {
X return getopt(argc, argv, optstring);
X }
X
X c = *key++;
X if (c == '\0') {
X key--;
X return EOF;
X }
X place = strchr(optstring, c);
X
X if (place == NULL || c == ':') {
X fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
X return ('?');
X }
X place++;
X if (*place == ':') {
X if (optind < argc) {
X optarg = argv[optind];
X optind++;
X } else {
X fprintf(stderr, "%s: %c argument missing\n",
X argv[0], c);
X return ('?');
X }
X }
X return (c);
X}
X
X
X/* usage - print a helpful message and exit
X *
X * DESCRIPTION
X *
X * Usage prints out the usage message for the TAR interface and then
X * exits with a non-zero termination status. This is used when a user
X * has provided non-existant or incompatible command line arguments.
X *
X * RETURNS
X *
X * Returns an exit status of 1 to the parent process.
X *
X */
X
X#ifdef __STDC__
X
Xstatic void usage(void)
X
X#else
X
Xstatic void usage()
X
X#endif
X{
X fprintf(stderr, "\
XUsage: %s -c[bfvw] device block filename..\n", myname);
X fprintf(stderr, "\
X %s -r[bvw] device block [filename...]\n", myname);
X fprintf(stderr, "\
X %s -t[vf] device\n", myname);
X fprintf(stderr, "\
X %s -u[bvw] device block [filename...]\n", myname);
X fprintf(stderr, "\
X %s -x[flmovw] device [filename...]\n", myname);
X exit(1);
X}
END_OF_tar.c
if test 7881 -ne `wc -c <tar.c`; then
echo shar: \"tar.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list