commit 5a249df788a06ab81c01284db84b035dd51c5dc4
parent 6f12643d9b8d41a1f0fe45268ae4e724ccc824b8
Author: Daniel Bainton <dpb@driftaway.org>
Date: Tue, 27 May 2014 14:22:23 +0300
Remove pax, was quite buggy
Diffstat:
M | mkfile | | | 2 | +- |
D | pax/ar_io.c | | | 1282 | ------------------------------------------------------------------------------- |
D | pax/ar_subs.c | | | 1262 | ------------------------------------------------------------------------------- |
D | pax/buf_subs.c | | | 985 | ------------------------------------------------------------------------------- |
D | pax/cache.c | | | 417 | ------------------------------------------------------------------------------- |
D | pax/cache.h | | | 73 | ------------------------------------------------------------------------- |
D | pax/cpio.1 | | | 308 | ------------------------------------------------------------------------------- |
D | pax/cpio.c | | | 1140 | ------------------------------------------------------------------------------- |
D | pax/cpio.h | | | 150 | ------------------------------------------------------------------------------- |
D | pax/extern.h | | | 308 | ------------------------------------------------------------------------------- |
D | pax/file_subs.c | | | 1077 | ------------------------------------------------------------------------------- |
D | pax/ftree.c | | | 557 | ------------------------------------------------------------------------------- |
D | pax/ftree.h | | | 51 | --------------------------------------------------- |
D | pax/gen_subs.c | | | 425 | ------------------------------------------------------------------------------- |
D | pax/getoldopt.c | | | 69 | --------------------------------------------------------------------- |
D | pax/mkfile | | | 12 | ------------ |
D | pax/options.c | | | 1609 | ------------------------------------------------------------------------------- |
D | pax/options.h | | | 113 | ------------------------------------------------------------------------------- |
D | pax/pat_rep.c | | | 1053 | ------------------------------------------------------------------------------- |
D | pax/pat_rep.h | | | 49 | ------------------------------------------------- |
D | pax/pax.1 | | | 1165 | ------------------------------------------------------------------------------- |
D | pax/pax.c | | | 429 | ------------------------------------------------------------------------------- |
D | pax/pax.h | | | 244 | ------------------------------------------------------------------------------- |
D | pax/sel_subs.c | | | 606 | ------------------------------------------------------------------------------- |
D | pax/sel_subs.h | | | 72 | ------------------------------------------------------------------------ |
D | pax/tables.c | | | 1269 | ------------------------------------------------------------------------------- |
D | pax/tables.h | | | 170 | ------------------------------------------------------------------------------- |
D | pax/tar.1 | | | 392 | ------------------------------------------------------------------------------- |
D | pax/tar.c | | | 1173 | ------------------------------------------------------------------------------- |
D | pax/tar.h | | | 153 | ------------------------------------------------------------------------------- |
D | pax/tty_subs.c | | | 190 | ------------------------------------------------------------------------------- |
31 files changed, 1 insertion(+), 16804 deletions(-)
diff --git a/mkfile b/mkfile
@@ -1,5 +1,5 @@
TARG = _install find sed ed grep expr od stty awk \
- patch diff printf dc dd fmt hd bc ps pgrep pax cp mk \
+ patch diff printf dc dd fmt hd bc ps pgrep cp mk \
libcommon libuxre lex yacc
<$mkbuild/mk.parent
diff --git a/pax/ar_io.c b/pax/ar_io.c
@@ -1,1282 +0,0 @@
-/* $OpenBSD: ar_io.c,v 1.39 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: ar_io.c,v 1.5 1996/03/26 23:54:13 mrg Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-#include <sys/param.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <err.h>
-#include "pax.h"
-#include "options.h"
-#include "extern.h"
-
-/*
- * Routines which deal directly with the archive I/O device/file.
- */
-
-#define DMOD 0666 /* default mode of created archives */
-#define EXT_MODE O_RDONLY /* open mode for list/extract */
-#define AR_MODE (O_WRONLY | O_CREAT | O_TRUNC) /* mode for archive */
-#define APP_MODE O_RDWR /* mode for append */
-#define STDO "<STDOUT>" /* pseudo name for stdout */
-#define STDN "<STDIN>" /* pseudo name for stdin */
-static int arfd = -1; /* archive file descriptor */
-static int artyp = ISREG; /* archive type: file/FIFO/tape */
-static int arvol = 1; /* archive volume number */
-static int lstrval = -1; /* return value from last i/o */
-static int io_ok; /* i/o worked on volume after resync */
-static int did_io; /* did i/o ever occur on volume? */
-static int done; /* set via tty termination */
-static struct stat arsb; /* stat of archive device at open */
-static int invld_rec; /* tape has out of spec record size */
-static int wr_trail = 1; /* trailer was rewritten in append */
-static int can_unlnk = 0; /* do we unlink null archives? */
-const char *arcname; /* printable name of archive */
-const char *gzip_program; /* name of gzip program */
-static pid_t zpid = -1; /* pid of child process */
-int force_one_volume; /* 1 if we ignore volume changes */
-
-static int get_phys(void);
-extern sigset_t s_mask;
-static void ar_start_gzip(int, const char *, int);
-
-/*
- * ar_open()
- * Opens the next archive volume. Determines the type of the device and
- * sets up block sizes as required by the archive device and the format.
- * Note: we may be called with name == NULL on the first open only.
- * Return:
- * -1 on failure, 0 otherwise
- */
-
-int
-ar_open(const char *name)
-{
- struct mtget mb;
-
- if (arfd != -1)
- (void)close(arfd);
- arfd = -1;
- can_unlnk = did_io = io_ok = invld_rec = 0;
- artyp = ISREG;
- flcnt = 0;
-
- /*
- * open based on overall operation mode
- */
- switch (act) {
- case LIST:
- case EXTRACT:
- if (name == NULL) {
- arfd = STDIN_FILENO;
- arcname = STDN;
- } else if ((arfd = open(name, EXT_MODE, DMOD)) < 0)
- syswarn(1, errno, "Failed open to read on %s", name);
- if (arfd != -1 && gzip_program != NULL)
- ar_start_gzip(arfd, gzip_program, 0);
- break;
- case ARCHIVE:
- if (name == NULL) {
- arfd = STDOUT_FILENO;
- arcname = STDO;
- } else if ((arfd = open(name, AR_MODE, DMOD)) < 0)
- syswarn(1, errno, "Failed open to write on %s", name);
- else
- can_unlnk = 1;
- if (arfd != -1 && gzip_program != NULL)
- ar_start_gzip(arfd, gzip_program, 1);
- break;
- case APPND:
- if (name == NULL) {
- arfd = STDOUT_FILENO;
- arcname = STDO;
- } else if ((arfd = open(name, APP_MODE, DMOD)) < 0)
- syswarn(1, errno, "Failed open to read/write on %s",
- name);
- break;
- case COPY:
- /*
- * arfd not used in COPY mode
- */
- arcname = "<NONE>";
- lstrval = 1;
- return(0);
- }
- if (arfd < 0)
- return(-1);
-
- if (chdname != NULL)
- if (chdir(chdname) != 0) {
- syswarn(1, errno, "Failed chdir to %s", chdname);
- return(-1);
- }
- /*
- * set up is based on device type
- */
- if (fstat(arfd, &arsb) < 0) {
- syswarn(1, errno, "Failed stat on %s", arcname);
- (void)close(arfd);
- arfd = -1;
- can_unlnk = 0;
- return(-1);
- }
- if (S_ISDIR(arsb.st_mode)) {
- paxwarn(0, "Cannot write an archive on top of a directory %s",
- arcname);
- (void)close(arfd);
- arfd = -1;
- can_unlnk = 0;
- return(-1);
- }
-
- if (S_ISCHR(arsb.st_mode))
- artyp = ioctl(arfd, MTIOCGET, &mb) ? ISCHR : ISTAPE;
- else if (S_ISBLK(arsb.st_mode))
- artyp = ISBLK;
- else if ((lseek(arfd, (off_t)0L, SEEK_CUR) == -1) && (errno == ESPIPE))
- artyp = ISPIPE;
- else
- artyp = ISREG;
-
- /*
- * make sure we beyond any doubt that we only can unlink regular files
- * we created
- */
- if (artyp != ISREG)
- can_unlnk = 0;
- /*
- * if we are writing, we are done
- */
- if (act == ARCHIVE) {
- blksz = rdblksz = wrblksz;
- lstrval = 1;
- return(0);
- }
-
- /*
- * set default blksz on read. APPNDs writes rdblksz on the last volume
- * On all new archive volumes, we shift to wrblksz (if the user
- * specified one, otherwise we will continue to use rdblksz). We
- * must set blocksize based on what kind of device the archive is
- * stored.
- */
- switch (artyp) {
- case ISTAPE:
- /*
- * Tape drives come in at least two flavors. Those that support
- * variable sized records and those that have fixed sized
- * records. They must be treated differently. For tape drives
- * that support variable sized records, we must make large
- * reads to make sure we get the entire record, otherwise we
- * will just get the first part of the record (up to size we
- * asked). Tapes with fixed sized records may or may not return
- * multiple records in a single read. We really do not care
- * what the physical record size is UNLESS we are going to
- * append. (We will need the physical block size to rewrite
- * the trailer). Only when we are appending do we go to the
- * effort to figure out the true PHYSICAL record size.
- */
- blksz = rdblksz = MAXBLK;
- break;
- case ISPIPE:
- case ISBLK:
- case ISCHR:
- /*
- * Blocksize is not a major issue with these devices (but must
- * be kept a multiple of 512). If the user specified a write
- * block size, we use that to read. Under append, we must
- * always keep blksz == rdblksz. Otherwise we go ahead and use
- * the device optimal blocksize as (and if) returned by stat
- * and if it is within pax specs.
- */
- if ((act == APPND) && wrblksz) {
- blksz = rdblksz = wrblksz;
- break;
- }
-
- if ((arsb.st_blksize > 0) && (arsb.st_blksize < MAXBLK) &&
- ((arsb.st_blksize % BLKMULT) == 0))
- rdblksz = arsb.st_blksize;
- else
- rdblksz = DEVBLK;
- /*
- * For performance go for large reads when we can without harm
- */
- if ((act == APPND) || (artyp == ISCHR))
- blksz = rdblksz;
- else
- blksz = MAXBLK;
- break;
- case ISREG:
- /*
- * if the user specified wrblksz works, use it. Under appends
- * we must always keep blksz == rdblksz
- */
- if ((act == APPND) && wrblksz && ((arsb.st_size%wrblksz)==0)){
- blksz = rdblksz = wrblksz;
- break;
- }
- /*
- * See if we can find the blocking factor from the file size
- */
- for (rdblksz = MAXBLK; rdblksz > 0; rdblksz -= BLKMULT)
- if ((arsb.st_size % rdblksz) == 0)
- break;
- /*
- * When we cannot find a match, we may have a flawed archive.
- */
- if (rdblksz <= 0)
- rdblksz = FILEBLK;
- /*
- * for performance go for large reads when we can
- */
- if (act == APPND)
- blksz = rdblksz;
- else
- blksz = MAXBLK;
- break;
- default:
- /*
- * should never happen, worst case, slow...
- */
- blksz = rdblksz = BLKMULT;
- break;
- }
- lstrval = 1;
- return(0);
-}
-
-/*
- * ar_close()
- * closes archive device, increments volume number, and prints i/o summary
- */
-void
-ar_close(void)
-{
- int status;
-
- if (arfd < 0) {
- did_io = io_ok = flcnt = 0;
- return;
- }
-
- /*
- * Close archive file. This may take a LONG while on tapes (we may be
- * forced to wait for the rewind to complete) so tell the user what is
- * going on (this avoids the user hitting control-c thinking pax is
- * broken).
- */
- if (vflag && (artyp == ISTAPE)) {
- if (vfpart)
- (void)putc('\n', listf);
- (void)fprintf(listf,
- "%s: Waiting for tape drive close to complete...",
- argv0);
- (void)fflush(listf);
- }
-
- /*
- * if nothing was written to the archive (and we created it), we remove
- * it
- */
- if (can_unlnk && (fstat(arfd, &arsb) == 0) && (S_ISREG(arsb.st_mode)) &&
- (arsb.st_size == 0)) {
- (void)unlink(arcname);
- can_unlnk = 0;
- }
-
- /*
- * for a quick extract/list, pax frequently exits before the child
- * process is done
- */
- if ((act == LIST || act == EXTRACT) && nflag && zpid > 0)
- kill(zpid, SIGINT);
-
- (void)close(arfd);
-
- /* Do not exit before child to ensure data integrity */
- if (zpid > 0)
- waitpid(zpid, &status, 0);
-
- if (vflag && (artyp == ISTAPE)) {
- (void)fputs("done.\n", listf);
- vfpart = 0;
- (void)fflush(listf);
- }
- arfd = -1;
-
- if (!io_ok && !did_io) {
- flcnt = 0;
- return;
- }
- did_io = io_ok = 0;
-
- /*
- * The volume number is only increased when the last device has data
- * and we have already determined the archive format.
- */
- if (frmt != NULL)
- ++arvol;
-
- if (!vflag) {
- flcnt = 0;
- return;
- }
-
- /*
- * Print out a summary of I/O for this archive volume.
- */
- if (vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
-
- /*
- * If we have not determined the format yet, we just say how many bytes
- * we have skipped over looking for a header to id. there is no way we
- * could have written anything yet.
- */
- if (frmt == NULL) {
-# ifdef LONG_OFF_T
- (void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n",
-# else
- (void)fprintf(listf, "%s: unknown format, %qu bytes skipped.\n",
-# endif
- argv0, rdcnt);
- (void)fflush(listf);
- flcnt = 0;
- return;
- }
-
- if (strcmp(NM_CPIO, argv0) == 0)
- (void)fprintf(listf, "%qu blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120);
- else if (strcmp(NM_TAR, argv0) != 0)
- (void)fprintf(listf,
-# ifdef LONG_OFF_T
- "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n",
-# else
- "%s: %s vol %d, %lu files, %qu bytes read, %qu bytes written.\n",
-# endif
- argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt);
- (void)fflush(listf);
- flcnt = 0;
-}
-
-/*
- * ar_drain()
- * drain any archive format independent padding from an archive read
- * from a socket or a pipe. This is to prevent the process on the
- * other side of the pipe from getting a SIGPIPE (pax will stop
- * reading an archive once a format dependent trailer is detected).
- */
-void
-ar_drain(void)
-{
- int res;
- char drbuf[MAXBLK];
-
- /*
- * we only drain from a pipe/socket. Other devices can be closed
- * without reading up to end of file. We sure hope that pipe is closed
- * on the other side so we will get an EOF.
- */
- if ((artyp != ISPIPE) || (lstrval <= 0))
- return;
-
- /*
- * keep reading until pipe is drained
- */
- while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0)
- ;
- lstrval = res;
-}
-
-/*
- * ar_set_wr()
- * Set up device right before switching from read to write in an append.
- * device dependent code (if required) to do this should be added here.
- * For all archive devices we are already positioned at the place we want
- * to start writing when this routine is called.
- * Return:
- * 0 if all ready to write, -1 otherwise
- */
-
-int
-ar_set_wr(void)
-{
- off_t cpos;
-
- /*
- * we must make sure the trailer is rewritten on append, ar_next()
- * will stop us if the archive containing the trailer was not written
- */
- wr_trail = 0;
-
- /*
- * Add any device dependent code as required here
- */
- if (artyp != ISREG)
- return(0);
- /*
- * Ok we have an archive in a regular file. If we were rewriting a
- * file, we must get rid of all the stuff after the current offset
- * (it was not written by pax).
- */
- if (((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) ||
- (ftruncate(arfd, cpos) < 0)) {
- syswarn(1, errno, "Unable to truncate archive file");
- return(-1);
- }
- return(0);
-}
-
-/*
- * ar_app_ok()
- * check if the last volume in the archive allows appends. We cannot check
- * this until we are ready to write since there is no spec that says all
- * volumes in a single archive have to be of the same type...
- * Return:
- * 0 if we can append, -1 otherwise.
- */
-
-int
-ar_app_ok(void)
-{
- if (artyp == ISPIPE) {
- paxwarn(1, "Cannot append to an archive obtained from a pipe.");
- return(-1);
- }
-
- if (!invld_rec)
- return(0);
- paxwarn(1,"Cannot append, device record size %d does not support %s spec",
- rdblksz, argv0);
- return(-1);
-}
-
-/*
- * ar_read()
- * read up to a specified number of bytes from the archive into the
- * supplied buffer. When dealing with tapes we may not always be able to
- * read what we want.
- * Return:
- * Number of bytes in buffer. 0 for end of file, -1 for a read error.
- */
-
-int
-ar_read(char *buf, int cnt)
-{
- int res = 0;
-
- /*
- * if last i/o was in error, no more reads until reset or new volume
- */
- if (lstrval <= 0)
- return(lstrval);
-
- /*
- * how we read must be based on device type
- */
- switch (artyp) {
- case ISTAPE:
- if ((res = read(arfd, buf, cnt)) > 0) {
- /*
- * CAUTION: tape systems may not always return the same
- * sized records so we leave blksz == MAXBLK. The
- * physical record size that a tape drive supports is
- * very hard to determine in a uniform and portable
- * manner.
- */
- io_ok = 1;
- if (res != rdblksz) {
- /*
- * Record size changed. If this happens on
- * any record after the first, we probably have
- * a tape drive which has a fixed record size
- * (we are getting multiple records in a single
- * read). Watch out for record blocking that
- * violates pax spec (must be a multiple of
- * BLKMULT).
- */
- rdblksz = res;
- if (rdblksz % BLKMULT)
- invld_rec = 1;
- }
- return(res);
- }
- break;
- case ISREG:
- case ISBLK:
- case ISCHR:
- case ISPIPE:
- default:
- /*
- * Files are so easy to deal with. These other things cannot
- * be trusted at all. So when we are dealing with character
- * devices and pipes we just take what they have ready for us
- * and return. Trying to do anything else with them runs the
- * risk of failure.
- */
- if ((res = read(arfd, buf, cnt)) > 0) {
- io_ok = 1;
- return(res);
- }
- break;
- }
-
- /*
- * We are in trouble at this point, something is broken...
- */
- lstrval = res;
- if (res < 0)
- syswarn(1, errno, "Failed read on archive volume %d", arvol);
- else
- paxwarn(0, "End of archive volume %d reached", arvol);
- return(res);
-}
-
-/*
- * ar_write()
- * Write a specified number of bytes in supplied buffer to the archive
- * device so it appears as a single "block". Deals with errors and tries
- * to recover when faced with short writes.
- * Return:
- * Number of bytes written. 0 indicates end of volume reached and with no
- * flaws (as best that can be detected). A -1 indicates an unrecoverable
- * error in the archive occurred.
- */
-
-int
-ar_write(char *buf, int bsz)
-{
- int res;
- off_t cpos;
-
- /*
- * do not allow pax to create a "bad" archive. Once a write fails on
- * an archive volume prevent further writes to it.
- */
- if (lstrval <= 0)
- return(lstrval);
-
- if ((res = write(arfd, buf, bsz)) == bsz) {
- wr_trail = 1;
- io_ok = 1;
- return(bsz);
- }
- /*
- * write broke, see what we can do with it. We try to send any partial
- * writes that may violate pax spec to the next archive volume.
- */
- if (res < 0)
- lstrval = res;
- else
- lstrval = 0;
-
- switch (artyp) {
- case ISREG:
- if ((res > 0) && (res % BLKMULT)) {
- /*
- * try to fix up partial writes which are not BLKMULT
- * in size by forcing the runt record to next archive
- * volume
- */
- if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
- break;
- cpos -= (off_t)res;
- if (ftruncate(arfd, cpos) < 0)
- break;
- res = lstrval = 0;
- break;
- }
- if (res >= 0)
- break;
- /*
- * if file is out of space, handle it like a return of 0
- */
- if ((errno == ENOSPC) || (errno == EFBIG) || (errno == EDQUOT))
- res = lstrval = 0;
- break;
- case ISTAPE:
- case ISCHR:
- case ISBLK:
- if (res >= 0)
- break;
- if (errno == EACCES) {
- paxwarn(0, "Write failed, archive is write protected.");
- res = lstrval = 0;
- return(0);
- }
- /*
- * see if we reached the end of media, if so force a change to
- * the next volume
- */
- if ((errno == ENOSPC) || (errno == EIO) || (errno == ENXIO))
- res = lstrval = 0;
- break;
- case ISPIPE:
- default:
- /*
- * we cannot fix errors to these devices
- */
- break;
- }
-
- /*
- * Better tell the user the bad news...
- * if this is a block aligned archive format, we may have a bad archive
- * if the format wants the header to start at a BLKMULT boundary.. While
- * we can deal with the mis-aligned data, it violates spec and other
- * archive readers will likely fail. if the format is not block
- * aligned, the user may be lucky (and the archive is ok).
- */
- if (res >= 0) {
- if (res > 0)
- wr_trail = 1;
- io_ok = 1;
- }
-
- /*
- * If we were trying to rewrite the trailer and it didn't work, we
- * must quit right away.
- */
- if (!wr_trail && (res <= 0)) {
- paxwarn(1,"Unable to append, trailer re-write failed. Quitting.");
- return(res);
- }
-
- if (res == 0)
- paxwarn(0, "End of archive volume %d reached", arvol);
- else if (res < 0)
- syswarn(1, errno, "Failed write to archive volume: %d", arvol);
- else if (!frmt->blkalgn || ((res % frmt->blkalgn) == 0))
- paxwarn(0,"WARNING: partial archive write. Archive MAY BE FLAWED");
- else
- paxwarn(1,"WARNING: partial archive write. Archive IS FLAWED");
- return(res);
-}
-
-/*
- * ar_rdsync()
- * Try to move past a bad spot on a flawed archive as needed to continue
- * I/O. Clears error flags to allow I/O to continue.
- * Return:
- * 0 when ok to try i/o again, -1 otherwise.
- */
-
-int
-ar_rdsync(void)
-{
- long fsbz;
- off_t cpos;
- off_t mpos;
- struct mtop mb;
-
- /*
- * Fail resync attempts at user request (done) or if this is going to be
- * an update/append to a existing archive. if last i/o hit media end,
- * we need to go to the next volume not try a resync
- */
- if ((done > 0) || (lstrval == 0))
- return(-1);
-
- if ((act == APPND) || (act == ARCHIVE)) {
- paxwarn(1, "Cannot allow updates to an archive with flaws.");
- return(-1);
- }
- if (io_ok)
- did_io = 1;
-
- switch (artyp) {
- case ISTAPE:
- /*
- * if the last i/o was a successful data transfer, we assume
- * the fault is just a bad record on the tape that we are now
- * past. If we did not get any data since the last resync try
- * to move the tape forward one PHYSICAL record past any
- * damaged tape section. Some tape drives are stubborn and need
- * to be pushed.
- */
- if (io_ok) {
- io_ok = 0;
- lstrval = 1;
- break;
- }
- mb.mt_op = MTFSR;
- mb.mt_count = 1;
- if (ioctl(arfd, MTIOCTOP, &mb) < 0)
- break;
- lstrval = 1;
- break;
- case ISREG:
- case ISCHR:
- case ISBLK:
- /*
- * try to step over the bad part of the device.
- */
- io_ok = 0;
- if (((fsbz = arsb.st_blksize) <= 0) || (artyp != ISREG))
- fsbz = BLKMULT;
- if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
- break;
- mpos = fsbz - (cpos % (off_t)fsbz);
- if (lseek(arfd, mpos, SEEK_CUR) < 0)
- break;
- lstrval = 1;
- break;
- case ISPIPE:
- default:
- /*
- * cannot recover on these archive device types
- */
- io_ok = 0;
- break;
- }
- if (lstrval <= 0) {
- paxwarn(1, "Unable to recover from an archive read failure.");
- return(-1);
- }
- paxwarn(0, "Attempting to recover from an archive read failure.");
- return(0);
-}
-
-/*
- * ar_fow()
- * Move the I/O position within the archive forward the specified number of
- * bytes as supported by the device. If we cannot move the requested
- * number of bytes, return the actual number of bytes moved in skipped.
- * Return:
- * 0 if moved the requested distance, -1 on complete failure, 1 on
- * partial move (the amount moved is in skipped)
- */
-
-int
-ar_fow(off_t sksz, off_t *skipped)
-{
- off_t cpos;
- off_t mpos;
-
- *skipped = 0;
- if (sksz <= 0)
- return(0);
-
- /*
- * we cannot move forward at EOF or error
- */
- if (lstrval <= 0)
- return(lstrval);
-
- /*
- * Safer to read forward on devices where it is hard to find the end of
- * the media without reading to it. With tapes we cannot be sure of the
- * number of physical blocks to skip (we do not know physical block
- * size at this point), so we must only read forward on tapes!
- */
- if (artyp != ISREG)
- return(0);
-
- /*
- * figure out where we are in the archive
- */
- if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) >= 0) {
- /*
- * we can be asked to move farther than there are bytes in this
- * volume, if so, just go to file end and let normal buf_fill()
- * deal with the end of file (it will go to next volume by
- * itself)
- */
- if ((mpos = cpos + sksz) > arsb.st_size) {
- *skipped = arsb.st_size - cpos;
- mpos = arsb.st_size;
- } else
- *skipped = sksz;
- if (lseek(arfd, mpos, SEEK_SET) >= 0)
- return(0);
- }
- syswarn(1, errno, "Forward positioning operation on archive failed");
- lstrval = -1;
- return(-1);
-}
-
-/*
- * ar_rev()
- * move the i/o position within the archive backwards the specified byte
- * count as supported by the device. With tapes drives we RESET rdblksz to
- * the PHYSICAL blocksize.
- * NOTE: We should only be called to move backwards so we can rewrite the
- * last records (the trailer) of an archive (APPEND).
- * Return:
- * 0 if moved the requested distance, -1 on complete failure
- */
-
-int
-ar_rev(off_t sksz)
-{
- off_t cpos;
- struct mtop mb;
- int phyblk;
-
- /*
- * make sure we do not have try to reverse on a flawed archive
- */
- if (lstrval < 0)
- return(lstrval);
-
- switch (artyp) {
- case ISPIPE:
- if (sksz <= 0)
- break;
- /*
- * cannot go backwards on these critters
- */
- paxwarn(1, "Reverse positioning on pipes is not supported.");
- lstrval = -1;
- return(-1);
- case ISREG:
- case ISBLK:
- case ISCHR:
- default:
- if (sksz <= 0)
- break;
-
- /*
- * For things other than files, backwards movement has a very
- * high probability of failure as we really do not know the
- * true attributes of the device we are talking to (the device
- * may not even have the ability to lseek() in any direction).
- * First we figure out where we are in the archive.
- */
- if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) {
- syswarn(1, errno,
- "Unable to obtain current archive byte offset");
- lstrval = -1;
- return(-1);
- }
-
- /*
- * we may try to go backwards past the start when the archive
- * is only a single record. If this happens and we are on a
- * multi-volume archive, we need to go to the end of the
- * previous volume and continue our movement backwards from
- * there.
- */
- if ((cpos -= sksz) < (off_t)0L) {
- if (arvol > 1) {
- /*
- * this should never happen
- */
- paxwarn(1,"Reverse position on previous volume.");
- lstrval = -1;
- return(-1);
- }
- cpos = (off_t)0L;
- }
- if (lseek(arfd, cpos, SEEK_SET) < 0) {
- syswarn(1, errno, "Unable to seek archive backwards");
- lstrval = -1;
- return(-1);
- }
- break;
- case ISTAPE:
- /*
- * Calculate and move the proper number of PHYSICAL tape
- * blocks. If the sksz is not an even multiple of the physical
- * tape size, we cannot do the move (this should never happen).
- * (We also cannot handle trailers spread over two vols.)
- * get_phys() also makes sure we are in front of the filemark.
- */
- if ((phyblk = get_phys()) <= 0) {
- lstrval = -1;
- return(-1);
- }
-
- /*
- * make sure future tape reads only go by physical tape block
- * size (set rdblksz to the real size).
- */
- rdblksz = phyblk;
-
- /*
- * if no movement is required, just return (we must be after
- * get_phys() so the physical blocksize is properly set)
- */
- if (sksz <= 0)
- break;
-
- /*
- * ok we have to move. Make sure the tape drive can do it.
- */
- if (sksz % phyblk) {
- paxwarn(1,
- "Tape drive unable to backspace requested amount");
- lstrval = -1;
- return(-1);
- }
-
- /*
- * move backwards the requested number of bytes
- */
- mb.mt_op = MTBSR;
- mb.mt_count = sksz/phyblk;
- if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
- syswarn(1,errno, "Unable to backspace tape %d blocks.",
- mb.mt_count);
- lstrval = -1;
- return(-1);
- }
- break;
- }
- lstrval = 1;
- return(0);
-}
-
-/*
- * get_phys()
- * Determine the physical block size on a tape drive. We need the physical
- * block size so we know how many bytes we skip over when we move with
- * mtio commands. We also make sure we are BEFORE THE TAPE FILEMARK when
- * return.
- * This is one really SLOW routine...
- * Return:
- * physical block size if ok (ok > 0), -1 otherwise
- */
-
-static int
-get_phys(void)
-{
- int padsz = 0;
- int res;
- int phyblk;
- struct mtop mb;
- char scbuf[MAXBLK];
-
- /*
- * move to the file mark, and then back up one record and read it.
- * this should tell us the physical record size the tape is using.
- */
- if (lstrval == 1) {
- /*
- * we know we are at file mark when we get back a 0 from
- * read()
- */
- while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
- padsz += res;
- if (res < 0) {
- syswarn(1, errno, "Unable to locate tape filemark.");
- return(-1);
- }
- }
-
- /*
- * move backwards over the file mark so we are at the end of the
- * last record.
- */
- mb.mt_op = MTBSF;
- mb.mt_count = 1;
- if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
- syswarn(1, errno, "Unable to backspace over tape filemark.");
- return(-1);
- }
-
- /*
- * move backwards so we are in front of the last record and read it to
- * get physical tape blocksize.
- */
- mb.mt_op = MTBSR;
- mb.mt_count = 1;
- if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
- syswarn(1, errno, "Unable to backspace over last tape block.");
- return(-1);
- }
- if ((phyblk = read(arfd, scbuf, sizeof(scbuf))) <= 0) {
- syswarn(1, errno, "Cannot determine archive tape blocksize.");
- return(-1);
- }
-
- /*
- * read forward to the file mark, then back up in front of the filemark
- * (this is a bit paranoid, but should be safe to do).
- */
- while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
- ;
- if (res < 0) {
- syswarn(1, errno, "Unable to locate tape filemark.");
- return(-1);
- }
- mb.mt_op = MTBSF;
- mb.mt_count = 1;
- if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
- syswarn(1, errno, "Unable to backspace over tape filemark.");
- return(-1);
- }
-
- /*
- * set lstrval so we know that the filemark has not been seen
- */
- lstrval = 1;
-
- /*
- * return if there was no padding
- */
- if (padsz == 0)
- return(phyblk);
-
- /*
- * make sure we can move backwards over the padding. (this should
- * never fail).
- */
- if (padsz % phyblk) {
- paxwarn(1, "Tape drive unable to backspace requested amount");
- return(-1);
- }
-
- /*
- * move backwards over the padding so the head is where it was when
- * we were first called (if required).
- */
- mb.mt_op = MTBSR;
- mb.mt_count = padsz/phyblk;
- if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
- syswarn(1,errno,"Unable to backspace tape over %d pad blocks",
- mb.mt_count);
- return(-1);
- }
- return(phyblk);
-}
-
-/*
- * ar_next()
- * prompts the user for the next volume in this archive. For some devices
- * we may allow the media to be changed. Otherwise a new archive is
- * prompted for. By pax spec, if there is no controlling tty or an eof is
- * read on tty input, we must quit pax.
- * Return:
- * 0 when ready to continue, -1 when all done
- */
-
-int
-ar_next(void)
-{
- char buf[PAXPATHLEN+2];
- static int freeit = 0;
- sigset_t o_mask;
-
- /*
- * WE MUST CLOSE THE DEVICE. A lot of devices must see last close, (so
- * things like writing EOF etc will be done) (Watch out ar_close() can
- * also be called via a signal handler, so we must prevent a race.
- */
- if (sigprocmask(SIG_BLOCK, &s_mask, &o_mask) < 0)
- syswarn(0, errno, "Unable to set signal mask");
- ar_close();
- if (sigprocmask(SIG_SETMASK, &o_mask, NULL) < 0)
- syswarn(0, errno, "Unable to restore signal mask");
-
- if (done || !wr_trail || force_one_volume || strcmp(NM_TAR, argv0) == 0)
- return(-1);
-
- tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0);
-
- /*
- * if i/o is on stdin or stdout, we cannot reopen it (we do not know
- * the name), the user will be forced to type it in.
- */
- if (strcmp(arcname, STDO) && strcmp(arcname, STDN) && (artyp != ISREG)
- && (artyp != ISPIPE)) {
- if (artyp == ISTAPE) {
- tty_prnt("%s ready for archive tape volume: %d\n",
- arcname, arvol);
- tty_prnt("Load the NEXT TAPE on the tape drive");
- } else {
- tty_prnt("%s ready for archive volume: %d\n",
- arcname, arvol);
- tty_prnt("Load the NEXT STORAGE MEDIA (if required)");
- }
-
- if ((act == ARCHIVE) || (act == APPND))
- tty_prnt(" and make sure it is WRITE ENABLED.\n");
- else
- tty_prnt("\n");
-
- for (;;) {
- tty_prnt("Type \"y\" to continue, \".\" to quit %s,",
- argv0);
- tty_prnt(" or \"s\" to switch to new device.\nIf you");
- tty_prnt(" cannot change storage media, type \"s\"\n");
- tty_prnt("Is the device ready and online? > ");
-
- if ((tty_read(buf,sizeof(buf))<0) || !strcmp(buf,".")){
- done = 1;
- lstrval = -1;
- tty_prnt("Quitting %s!\n", argv0);
- vfpart = 0;
- return(-1);
- }
-
- if ((buf[0] == '\0') || (buf[1] != '\0')) {
- tty_prnt("%s unknown command, try again\n",buf);
- continue;
- }
-
- switch (buf[0]) {
- case 'y':
- case 'Y':
- /*
- * we are to continue with the same device
- */
- if (ar_open(arcname) >= 0)
- return(0);
- tty_prnt("Cannot re-open %s, try again\n",
- arcname);
- continue;
- case 's':
- case 'S':
- /*
- * user wants to open a different device
- */
- tty_prnt("Switching to a different archive\n");
- break;
- default:
- tty_prnt("%s unknown command, try again\n",buf);
- continue;
- }
- break;
- }
- } else
- tty_prnt("Ready for archive volume: %d\n", arvol);
-
- /*
- * have to go to a different archive
- */
- for (;;) {
- tty_prnt("Input archive name or \".\" to quit %s.\n", argv0);
- tty_prnt("Archive name > ");
-
- if ((tty_read(buf, sizeof(buf)) < 0) || !strcmp(buf, ".")) {
- done = 1;
- lstrval = -1;
- tty_prnt("Quitting %s!\n", argv0);
- vfpart = 0;
- return(-1);
- }
- if (buf[0] == '\0') {
- tty_prnt("Empty file name, try again\n");
- continue;
- }
- if (!strcmp(buf, "..")) {
- tty_prnt("Illegal file name: .. try again\n");
- continue;
- }
- if (strlen(buf) > PAXPATHLEN) {
- tty_prnt("File name too long, try again\n");
- continue;
- }
-
- /*
- * try to open new archive
- */
- if (ar_open(buf) >= 0) {
- if (freeit) {
- (void)free((char *)arcname);
- freeit = 0;
- }
- if ((arcname = strdup(buf)) == NULL) {
- done = 1;
- lstrval = -1;
- paxwarn(0, "Cannot save archive name.");
- return(-1);
- }
- freeit = 1;
- break;
- }
- tty_prnt("Cannot open %s, try again\n", buf);
- continue;
- }
- return(0);
-}
-
-/*
- * ar_start_gzip()
- * starts the gzip compression/decompression process as a child, using magic
- * to keep the fd the same in the calling function (parent).
- */
-void
-ar_start_gzip(int fd, const char *gzip_program, int wr)
-{
- int fds[2];
- const char *gzip_flags;
-
- if (pipe(fds) < 0)
- err(1, "could not pipe");
- zpid = fork();
- if (zpid < 0)
- err(1, "could not fork");
-
- /* parent */
- if (zpid) {
- if (wr)
- dup2(fds[1], fd);
- else
- dup2(fds[0], fd);
- close(fds[0]);
- close(fds[1]);
- } else {
- if (wr) {
- dup2(fds[0], STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- gzip_flags = "-c";
- } else {
- dup2(fds[1], STDOUT_FILENO);
- dup2(fd, STDIN_FILENO);
- gzip_flags = "-dc";
- }
- close(fds[0]);
- close(fds[1]);
- if (execlp(gzip_program, gzip_program, gzip_flags, (char *)NULL) < 0)
- err(1, "could not exec %s", gzip_program);
- /* NOTREACHED */
- }
-}
diff --git a/pax/ar_subs.c b/pax/ar_subs.c
@@ -1,1262 +0,0 @@
-/* $OpenBSD: ar_subs.c,v 1.33 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: ar_subs.c,v 1.5 1995/03/21 09:07:06 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "pax.h"
-#include "extern.h"
-
-static void wr_archive(ARCHD *, int is_app);
-static int get_arc(void);
-static int next_head(ARCHD *);
-extern sigset_t s_mask;
-
-/*
- * Routines which control the overall operation modes of pax as specified by
- * the user: list, append, read ...
- */
-
-static char hdbuf[BLKMULT]; /* space for archive header on read */
-u_long flcnt; /* number of files processed */
-
-/*
- * list()
- * list the contents of an archive which match user supplied pattern(s)
- * (no pattern matches all).
- */
-
-void
-list(void)
-{
- ARCHD *arcn;
- int res;
- ARCHD archd;
- time_t now;
-
- arcn = &archd;
- /*
- * figure out archive type; pass any format specific options to the
- * archive option processing routine; call the format init routine. We
- * also save current time for ls_list() so we do not make a system
- * call for each file we need to print. If verbose (vflag) start up
- * the name and group caches.
- */
- if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
- ((*frmt->st_rd)() < 0))
- return;
-
- if (vflag && ((uidtb_start() < 0) || (gidtb_start() < 0)))
- return;
-
- now = time(NULL);
-
- /*
- * step through the archive until the format says it is done
- */
- while (next_head(arcn) == 0) {
- if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
- /*
- * we need to read, to get the real filename
- */
- off_t cnt;
- if (!(*frmt->rd_data)(arcn, arcn->type == PAX_GLF
- ? -1 : -2, &cnt))
- (void)rd_skip(cnt + arcn->pad);
- continue;
- }
-
- /*
- * check for pattern, and user specified options match.
- * When all patterns are matched we are done.
- */
- if ((res = pat_match(arcn)) < 0)
- break;
-
- if ((res == 0) && (sel_chk(arcn) == 0)) {
- /*
- * pattern resulted in a selected file
- */
- if (pat_sel(arcn) < 0)
- break;
-
- /*
- * modify the name as requested by the user if name
- * survives modification, do a listing of the file
- */
- if ((res = mod_name(arcn)) < 0)
- break;
- if (res == 0)
- ls_list(arcn, now, stdout);
- }
-
- /*
- * skip to next archive format header using values calculated
- * by the format header read routine
- */
- if (rd_skip(arcn->skip + arcn->pad) == 1)
- break;
- }
-
- /*
- * all done, let format have a chance to cleanup, and make sure that
- * the patterns supplied by the user were all matched
- */
- (void)(*frmt->end_rd)();
- (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
- ar_close();
- pat_chk();
-}
-
-/*
- * extract()
- * extract the member(s) of an archive as specified by user supplied
- * pattern(s) (no patterns extracts all members)
- */
-
-void
-extract(void)
-{
- ARCHD *arcn;
- int res;
- off_t cnt;
- ARCHD archd;
- struct stat sb;
- int fd;
- time_t now;
-
- arcn = &archd;
- /*
- * figure out archive type; pass any format specific options to the
- * archive option processing routine; call the format init routine;
- * start up the directory modification time and access mode database
- */
- if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
- ((*frmt->st_rd)() < 0) || (dir_start() < 0))
- return;
-
- /*
- * When we are doing interactive rename, we store the mapping of names
- * so we can fix up hard links files later in the archive.
- */
- if (iflag && (name_start() < 0))
- return;
-
- now = time(NULL);
-
- /*
- * step through each entry on the archive until the format read routine
- * says it is done
- */
- while (next_head(arcn) == 0) {
- if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
- /*
- * we need to read, to get the real filename
- */
- if (!(*frmt->rd_data)(arcn, arcn->type == PAX_GLF
- ? -1 : -2, &cnt))
- (void)rd_skip(cnt + arcn->pad);
- continue;
- }
-
- /*
- * check for pattern, and user specified options match. When
- * all the patterns are matched we are done
- */
- if ((res = pat_match(arcn)) < 0)
- break;
-
- if ((res > 0) || (sel_chk(arcn) != 0)) {
- /*
- * file is not selected. skip past any file data and
- * padding and go back for the next archive member
- */
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
-
- /*
- * with -u or -D only extract when the archive member is newer
- * than the file with the same name in the file system (no
- * test of being the same type is required).
- * NOTE: this test is done BEFORE name modifications as
- * specified by pax. this operation can be confusing to the
- * user who might expect the test to be done on an existing
- * file AFTER the name mod. In honesty the pax spec is probably
- * flawed in this respect.
- */
- if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) {
- if (uflag && Dflag) {
- if ((arcn->sb.st_mtime <= sb.st_mtime) &&
- (arcn->sb.st_ctime <= sb.st_ctime)) {
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
- } else if (Dflag) {
- if (arcn->sb.st_ctime <= sb.st_ctime) {
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
- } else if (arcn->sb.st_mtime <= sb.st_mtime) {
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
- }
-
- /*
- * this archive member is now been selected. modify the name.
- */
- if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0))
- break;
- if (res > 0) {
- /*
- * a bad name mod, skip and purge name from link table
- */
- purg_lnk(arcn);
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
-
- /*
- * Non standard -Y and -Z flag. When the existing file is
- * same age or newer skip
- */
- if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
- if (Yflag && Zflag) {
- if ((arcn->sb.st_mtime <= sb.st_mtime) &&
- (arcn->sb.st_ctime <= sb.st_ctime)) {
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
- } else if (Yflag) {
- if (arcn->sb.st_ctime <= sb.st_ctime) {
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
- } else if (arcn->sb.st_mtime <= sb.st_mtime) {
- (void)rd_skip(arcn->skip + arcn->pad);
- continue;
- }
- }
-
- if (vflag) {
- if (vflag > 1)
- ls_list(arcn, now, listf);
- else {
- (void)safe_print(arcn->name, listf);
- vfpart = 1;
- }
- }
-
- /*
- * if required, chdir around.
- */
- if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
- if (chdir(arcn->pat->chdname) != 0)
- syswarn(1, errno, "Cannot chdir to %s",
- arcn->pat->chdname);
-
- /*
- * all ok, extract this member based on type
- */
- if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
- /*
- * process archive members that are not regular files.
- * throw out padding and any data that might follow the
- * header (as determined by the format).
- */
- if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
- res = lnk_creat(arcn);
- else
- res = node_creat(arcn);
-
- (void)rd_skip(arcn->skip + arcn->pad);
- if (res < 0)
- purg_lnk(arcn);
-
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- goto popd;
- }
- /*
- * we have a file with data here. If we can not create it, skip
- * over the data and purge the name from hard link table
- */
- if ((fd = file_creat(arcn)) < 0) {
- (void)rd_skip(arcn->skip + arcn->pad);
- purg_lnk(arcn);
- goto popd;
- }
- /*
- * extract the file from the archive and skip over padding and
- * any unprocessed data
- */
- res = (*frmt->rd_data)(arcn, fd, &cnt);
- file_close(arcn, fd);
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- if (!res)
- (void)rd_skip(cnt + arcn->pad);
-
-popd:
- /*
- * if required, chdir around.
- */
- if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
- if (fchdir(cwdfd) != 0)
- syswarn(1, errno,
- "Can't fchdir to starting directory");
- }
-
- /*
- * all done, restore directory modes and times as required; make sure
- * all patterns supplied by the user were matched; block off signals
- * to avoid chance for multiple entry into the cleanup code.
- */
- (void)(*frmt->end_rd)();
- (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
- ar_close();
- proc_dir();
- pat_chk();
-}
-
-/*
- * wr_archive()
- * Write an archive. used in both creating a new archive and appends on
- * previously written archive.
- */
-
-static void
-wr_archive(ARCHD *arcn, int is_app)
-{
- int res;
- int hlk;
- int wr_one;
- off_t cnt;
- int (*wrf)(ARCHD *);
- int fd = -1;
- time_t now;
-
- /*
- * if this format supports hard link storage, start up the database
- * that detects them.
- */
- if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0))
- return;
-
- /*
- * if this is not append, and there are no files, we do not write a
- * trailer
- */
- wr_one = is_app;
-
- /*
- * start up the file traversal code and format specific write
- */
- if (ftree_start() < 0) {
- if (is_app)
- goto trailer;
- return;
- } else if (((*frmt->st_wr)() < 0))
- return;
-
- wrf = frmt->wr;
-
- /*
- * When we are doing interactive rename, we store the mapping of names
- * so we can fix up hard links files later in the archive.
- */
- if (iflag && (name_start() < 0))
- return;
-
- now = time(NULL);
-
- /*
- * while there are files to archive, process them one at at time
- */
- while (next_file(arcn) == 0) {
- /*
- * check if this file meets user specified options match.
- */
- if (sel_chk(arcn) != 0)
- continue;
- fd = -1;
- if (uflag) {
- /*
- * only archive if this file is newer than a file with
- * the same name that is already stored on the archive
- */
- if ((res = chk_ftime(arcn)) < 0)
- break;
- if (res > 0) {
- ftree_skipped_newer(arcn);
- continue;
- }
- }
-
- /*
- * this file is considered selected now. see if this is a hard
- * link to a file already stored
- */
- ftree_sel(arcn);
- if (hlk && (chk_lnk(arcn) < 0))
- break;
-
- if ((arcn->type == PAX_REG) || (arcn->type == PAX_HRG) ||
- (arcn->type == PAX_CTG)) {
- /*
- * we will have to read this file. by opening it now we
- * can avoid writing a header to the archive for a file
- * we were later unable to read (we also purge it from
- * the link table).
- */
- if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) {
- syswarn(1,errno, "Unable to open %s to read",
- arcn->org_name);
- purg_lnk(arcn);
- continue;
- }
- }
-
- /*
- * Now modify the name as requested by the user
- */
- if ((res = mod_name(arcn)) < 0) {
- /*
- * name modification says to skip this file, close the
- * file and purge link table entry
- */
- rdfile_close(arcn, &fd);
- purg_lnk(arcn);
- break;
- }
-
- if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) {
- /*
- * unable to obtain the crc we need, close the file,
- * purge link table entry
- */
- rdfile_close(arcn, &fd);
- purg_lnk(arcn);
- continue;
- }
-
- if (vflag) {
- if (vflag > 1)
- ls_list(arcn, now, listf);
- else {
- (void)safe_print(arcn->name, listf);
- vfpart = 1;
- }
- }
- ++flcnt;
-
- /*
- * looks safe to store the file, have the format specific
- * routine write routine store the file header on the archive
- */
- if ((res = (*wrf)(arcn)) < 0) {
- rdfile_close(arcn, &fd);
- break;
- }
- wr_one = 1;
- if (res > 0) {
- /*
- * format write says no file data needs to be stored
- * so we are done messing with this file
- */
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- rdfile_close(arcn, &fd);
- continue;
- }
-
- /*
- * Add file data to the archive, quit on write error. if we
- * cannot write the entire file contents to the archive we
- * must pad the archive to replace the missing file data
- * (otherwise during an extract the file header for the file
- * which FOLLOWS this one will not be where we expect it to
- * be).
- */
- res = (*frmt->wr_data)(arcn, fd, &cnt);
- rdfile_close(arcn, &fd);
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- if (res < 0)
- break;
-
- /*
- * pad as required, cnt is number of bytes not written
- */
- if (((cnt > 0) && (wr_skip(cnt) < 0)) ||
- ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0)))
- break;
- }
-
-trailer:
- /*
- * tell format to write trailer; pad to block boundary; reset directory
- * mode/access times, and check if all patterns supplied by the user
- * were matched. block off signals to avoid chance for multiple entry
- * into the cleanup code
- */
- if (wr_one) {
- (*frmt->end_wr)();
- wr_fin();
- }
- (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
- ar_close();
- if (tflag)
- proc_dir();
- ftree_chk();
-}
-
-/*
- * append()
- * Add file to previously written archive. Archive format specified by the
- * user must agree with archive. The archive is read first to collect
- * modification times (if -u) and locate the archive trailer. The archive
- * is positioned in front of the record with the trailer and wr_archive()
- * is called to add the new members.
- * PAX IMPLEMENTATION DETAIL NOTE:
- * -u is implemented by adding the new members to the end of the archive.
- * Care is taken so that these do not end up as links to the older
- * version of the same file already stored in the archive. It is expected
- * when extraction occurs these newer versions will over-write the older
- * ones stored "earlier" in the archive (this may be a bad assumption as
- * it depends on the implementation of the program doing the extraction).
- * It is really difficult to splice in members without either re-writing
- * the entire archive (from the point were the old version was), or having
- * assistance of the format specification in terms of a special update
- * header that invalidates a previous archive record. The posix spec left
- * the method used to implement -u unspecified. This pax is able to
- * over write existing files that it creates.
- */
-
-void
-append(void)
-{
- ARCHD *arcn;
- int res;
- ARCHD archd;
- FSUB *orgfrmt;
- int udev;
- off_t tlen;
-
- arcn = &archd;
- orgfrmt = frmt;
-
- /*
- * Do not allow an append operation if the actual archive is of a
- * different format than the user specified format.
- */
- if (get_arc() < 0)
- return;
- if ((orgfrmt != NULL) && (orgfrmt != frmt)) {
- paxwarn(1, "Cannot mix current archive format %s with %s",
- frmt->name, orgfrmt->name);
- return;
- }
-
- /*
- * pass the format any options and start up format
- */
- if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0))
- return;
-
- /*
- * if we only are adding members that are newer, we need to save the
- * mod times for all files we see.
- */
- if (uflag && (ftime_start() < 0))
- return;
-
- /*
- * some archive formats encode hard links by recording the device and
- * file serial number (inode) but copy the file anyway (multiple times)
- * to the archive. When we append, we run the risk that newly added
- * files may have the same device and inode numbers as those recorded
- * on the archive but during a previous run. If this happens, when the
- * archive is extracted we get INCORRECT hard links. We avoid this by
- * remapping the device numbers so that newly added files will never
- * use the same device number as one found on the archive. remapping
- * allows new members to safely have links among themselves. remapping
- * also avoids problems with file inode (serial number) truncations
- * when the inode number is larger than storage space in the archive
- * header. See the remap routines for more details.
- */
- if ((udev = frmt->udev) && (dev_start() < 0))
- return;
-
- /*
- * reading the archive may take a long time. If verbose tell the user
- */
- if (vflag) {
- (void)fprintf(listf,
- "%s: Reading archive to position at the end...", argv0);
- vfpart = 1;
- }
-
- /*
- * step through the archive until the format says it is done
- */
- while (next_head(arcn) == 0) {
- /*
- * check if this file meets user specified options.
- */
- if (sel_chk(arcn) != 0) {
- if (rd_skip(arcn->skip + arcn->pad) == 1)
- break;
- continue;
- }
-
- if (uflag) {
- /*
- * see if this is the newest version of this file has
- * already been seen, if so skip.
- */
- if ((res = chk_ftime(arcn)) < 0)
- break;
- if (res > 0) {
- if (rd_skip(arcn->skip + arcn->pad) == 1)
- break;
- continue;
- }
- }
-
- /*
- * Store this device number. Device numbers seen during the
- * read phase of append will cause newly appended files with a
- * device number seen in the old part of the archive to be
- * remapped to an unused device number.
- */
- if ((udev && (add_dev(arcn) < 0)) ||
- (rd_skip(arcn->skip + arcn->pad) == 1))
- break;
- }
-
- /*
- * done, finish up read and get the number of bytes to back up so we
- * can add new members. The format might have used the hard link table,
- * purge it.
- */
- tlen = (*frmt->end_rd)();
- lnk_end();
-
- /*
- * try to position for write, if this fails quit. if any error occurs,
- * we will refuse to write
- */
- if (appnd_start(tlen) < 0)
- return;
-
- /*
- * tell the user we are done reading.
- */
- if (vflag && vfpart) {
- (void)fputs("done.\n", listf);
- vfpart = 0;
- }
-
- /*
- * go to the writing phase to add the new members
- */
- wr_archive(arcn, 1);
-}
-
-/*
- * archive()
- * write a new archive
- */
-
-void
-archive(void)
-{
- ARCHD archd;
-
- /*
- * if we only are adding members that are newer, we need to save the
- * mod times for all files; set up for writing; pass the format any
- * options write the archive
- */
- if ((uflag && (ftime_start() < 0)) || (wr_start() < 0))
- return;
- if ((*frmt->options)() < 0)
- return;
-
- wr_archive(&archd, 0);
-}
-
-/*
- * copy()
- * copy files from one part of the file system to another. this does not
- * use any archive storage. The EFFECT OF THE COPY IS THE SAME as if an
- * archive was written and then extracted in the destination directory
- * (except the files are forced to be under the destination directory).
- */
-
-void
-copy(void)
-{
- ARCHD *arcn;
- int res;
- int fddest;
- char *dest_pt;
- int dlen;
- int drem;
- int fdsrc = -1;
- struct stat sb;
- ARCHD archd;
- char dirbuf[PAXPATHLEN+1];
-
- arcn = &archd;
- /*
- * set up the destination dir path and make sure it is a directory. We
- * make sure we have a trailing / on the destination
- */
- dlen = strlcpy(dirbuf, dirptr, sizeof(dirbuf));
- if (dlen >= sizeof(dirbuf) ||
- (dlen == sizeof(dirbuf) - 1 && dirbuf[dlen - 1] != '/')) {
- paxwarn(1, "directory name is too long %s", dirptr);
- return;
- }
- dest_pt = dirbuf + dlen;
- if (*(dest_pt-1) != '/') {
- *dest_pt++ = '/';
- *dest_pt = '\0';
- ++dlen;
- }
- drem = PAXPATHLEN - dlen;
-
- if (stat(dirptr, &sb) < 0) {
- syswarn(1, errno, "Cannot access destination directory %s",
- dirptr);
- return;
- }
- if (!S_ISDIR(sb.st_mode)) {
- paxwarn(1, "Destination is not a directory %s", dirptr);
- return;
- }
-
- /*
- * start up the hard link table; file traversal routines and the
- * modification time and access mode database
- */
- if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0))
- return;
-
- /*
- * When we are doing interactive rename, we store the mapping of names
- * so we can fix up hard links files later in the archive.
- */
- if (iflag && (name_start() < 0))
- return;
-
- /*
- * set up to cp file trees
- */
- cp_start();
-
- /*
- * while there are files to archive, process them
- */
- while (next_file(arcn) == 0) {
- fdsrc = -1;
-
- /*
- * check if this file meets user specified options
- */
- if (sel_chk(arcn) != 0)
- continue;
-
- /*
- * if there is already a file in the destination directory with
- * the same name and it is newer, skip the one stored on the
- * archive.
- * NOTE: this test is done BEFORE name modifications as
- * specified by pax. this can be confusing to the user who
- * might expect the test to be done on an existing file AFTER
- * the name mod. In honesty the pax spec is probably flawed in
- * this respect
- */
- if (uflag || Dflag) {
- /*
- * create the destination name
- */
- if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'),
- drem + 1) > drem) {
- paxwarn(1, "Destination pathname too long %s",
- arcn->name);
- continue;
- }
-
- /*
- * if existing file is same age or newer skip
- */
- res = lstat(dirbuf, &sb);
- *dest_pt = '\0';
-
- if (res == 0) {
- ftree_skipped_newer(arcn);
- if (uflag && Dflag) {
- if ((arcn->sb.st_mtime<=sb.st_mtime) &&
- (arcn->sb.st_ctime<=sb.st_ctime))
- continue;
- } else if (Dflag) {
- if (arcn->sb.st_ctime <= sb.st_ctime)
- continue;
- } else if (arcn->sb.st_mtime <= sb.st_mtime)
- continue;
- }
- }
-
- /*
- * this file is considered selected. See if this is a hard link
- * to a previous file; modify the name as requested by the
- * user; set the final destination.
- */
- ftree_sel(arcn);
- if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0))
- break;
- if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) {
- /*
- * skip file, purge from link table
- */
- purg_lnk(arcn);
- continue;
- }
-
- /*
- * Non standard -Y and -Z flag. When the existing file is
- * same age or newer skip
- */
- if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
- if (Yflag && Zflag) {
- if ((arcn->sb.st_mtime <= sb.st_mtime) &&
- (arcn->sb.st_ctime <= sb.st_ctime))
- continue;
- } else if (Yflag) {
- if (arcn->sb.st_ctime <= sb.st_ctime)
- continue;
- } else if (arcn->sb.st_mtime <= sb.st_mtime)
- continue;
- }
-
- if (vflag) {
- (void)safe_print(arcn->name, listf);
- vfpart = 1;
- }
- ++flcnt;
-
- /*
- * try to create a hard link to the src file if requested
- * but make sure we are not trying to overwrite ourselves.
- */
- if (lflag)
- res = cross_lnk(arcn);
- else
- res = chk_same(arcn);
- if (res <= 0) {
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- continue;
- }
-
- /*
- * have to create a new file
- */
- if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
- /*
- * create a link or special file
- */
- if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
- res = lnk_creat(arcn);
- else
- res = node_creat(arcn);
- if (res < 0)
- purg_lnk(arcn);
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- continue;
- }
-
- /*
- * have to copy a regular file to the destination directory.
- * first open source file and then create the destination file
- */
- if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) {
- syswarn(1, errno, "Unable to open %s to read",
- arcn->org_name);
- purg_lnk(arcn);
- continue;
- }
- if ((fddest = file_creat(arcn)) < 0) {
- rdfile_close(arcn, &fdsrc);
- purg_lnk(arcn);
- continue;
- }
-
- /*
- * copy source file data to the destination file
- */
- cp_file(arcn, fdsrc, fddest);
- file_close(arcn, fddest);
- rdfile_close(arcn, &fdsrc);
-
- if (vflag && vfpart) {
- (void)putc('\n', listf);
- vfpart = 0;
- }
- }
-
- /*
- * restore directory modes and times as required; make sure all
- * patterns were selected block off signals to avoid chance for
- * multiple entry into the cleanup code.
- */
- (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
- ar_close();
- proc_dir();
- ftree_chk();
-}
-
-/*
- * next_head()
- * try to find a valid header in the archive. Uses format specific
- * routines to extract the header and id the trailer. Trailers may be
- * located within a valid header or in an invalid header (the location
- * is format specific. The inhead field from the option table tells us
- * where to look for the trailer).
- * We keep reading (and resyncing) until we get enough contiguous data
- * to check for a header. If we cannot find one, we shift by a byte
- * add a new byte from the archive to the end of the buffer and try again.
- * If we get a read error, we throw out what we have (as we must have
- * contiguous data) and start over again.
- * ASSUMED: headers fit within a BLKMULT header.
- * Return:
- * 0 if we got a header, -1 if we are unable to ever find another one
- * (we reached the end of input, or we reached the limit on retries. see
- * the specs for rd_wrbuf() for more details)
- */
-
-static int
-next_head(ARCHD *arcn)
-{
- int ret;
- char *hdend;
- int res;
- int shftsz;
- int hsz;
- int in_resync = 0; /* set when we are in resync mode */
- int cnt = 0; /* counter for trailer function */
- int first = 1; /* on 1st read, EOF isn't premature. */
-
- /*
- * set up initial conditions, we want a whole frmt->hsz block as we
- * have no data yet.
- */
- res = hsz = frmt->hsz;
- hdend = hdbuf;
- shftsz = hsz - 1;
- for (;;) {
- /*
- * keep looping until we get a contiguous FULL buffer
- * (frmt->hsz is the proper size)
- */
- for (;;) {
- if ((ret = rd_wrbuf(hdend, res)) == res)
- break;
-
- /*
- * If we read 0 bytes (EOF) from an archive when we
- * expect to find a header, we have stepped upon
- * an archive without the customary block of zeroes
- * end marker. It's just stupid to error out on
- * them, so exit gracefully.
- */
- if (first && ret == 0)
- return(-1);
- first = 0;
-
- /*
- * some kind of archive read problem, try to resync the
- * storage device, better give the user the bad news.
- */
- if ((ret == 0) || (rd_sync() < 0)) {
- paxwarn(1,"Premature end of file on archive read");
- return(-1);
- }
- if (!in_resync) {
- if (act == APPND) {
- paxwarn(1,
- "Archive I/O error, cannot continue");
- return(-1);
- }
- paxwarn(1,"Archive I/O error. Trying to recover.");
- ++in_resync;
- }
-
- /*
- * oh well, throw it all out and start over
- */
- res = hsz;
- hdend = hdbuf;
- }
-
- /*
- * ok we have a contiguous buffer of the right size. Call the
- * format read routine. If this was not a valid header and this
- * format stores trailers outside of the header, call the
- * format specific trailer routine to check for a trailer. We
- * have to watch out that we do not mis-identify file data or
- * block padding as a header or trailer. Format specific
- * trailer functions must NOT check for the trailer while we
- * are running in resync mode. Some trailer functions may tell
- * us that this block cannot contain a valid header either, so
- * we then throw out the entire block and start over.
- */
- if ((*frmt->rd)(arcn, hdbuf) == 0)
- break;
-
- if (!frmt->inhead) {
- /*
- * this format has trailers outside of valid headers
- */
- if ((ret = (*frmt->trail)(arcn,hdbuf,in_resync,&cnt)) == 0){
- /*
- * valid trailer found, drain input as required
- */
- ar_drain();
- return(-1);
- }
-
- if (ret == 1) {
- /*
- * we are in resync and we were told to throw
- * the whole block out because none of the
- * bytes in this block can be used to form a
- * valid header
- */
- res = hsz;
- hdend = hdbuf;
- continue;
- }
- }
-
- /*
- * Brute force section.
- * not a valid header. We may be able to find a header yet. So
- * we shift over by one byte, and set up to read one byte at a
- * time from the archive and place it at the end of the buffer.
- * We will keep moving byte at a time until we find a header or
- * get a read error and have to start over.
- */
- if (!in_resync) {
- if (act == APPND) {
- paxwarn(1,"Unable to append, archive header flaw");
- return(-1);
- }
- paxwarn(1,"Invalid header, starting valid header search.");
- ++in_resync;
- }
- memmove(hdbuf, hdbuf+1, shftsz);
- res = 1;
- hdend = hdbuf + shftsz;
- }
-
- /*
- * ok got a valid header, check for trailer if format encodes it in the
- * the header. NOTE: the parameters are different than trailer routines
- * which encode trailers outside of the header!
- */
- if (frmt->inhead && ((*frmt->trail)(arcn,NULL,0,NULL) == 0)) {
- /*
- * valid trailer found, drain input as required
- */
- ar_drain();
- return(-1);
- }
-
- ++flcnt;
- return(0);
-}
-
-/*
- * get_arc()
- * Figure out what format an archive is. Handles archive with flaws by
- * brute force searches for a legal header in any supported format. The
- * format id routines have to be careful to NOT mis-identify a format.
- * ASSUMED: headers fit within a BLKMULT header.
- * Return:
- * 0 if archive found -1 otherwise
- */
-
-static int
-get_arc(void)
-{
- int i;
- int hdsz = 0;
- int res;
- int minhd = BLKMULT;
- char *hdend;
- int notice = 0;
-
- /*
- * find the smallest header size in all archive formats and then set up
- * to read the archive.
- */
- for (i = 0; ford[i] >= 0; ++i) {
- if (fsub[ford[i]].hsz < minhd)
- minhd = fsub[ford[i]].hsz;
- }
- if (rd_start() < 0)
- return(-1);
- res = BLKMULT;
- hdsz = 0;
- hdend = hdbuf;
- for (;;) {
- for (;;) {
- /*
- * fill the buffer with at least the smallest header
- */
- i = rd_wrbuf(hdend, res);
- if (i > 0)
- hdsz += i;
- if (hdsz >= minhd)
- break;
-
- /*
- * if we cannot recover from a read error quit
- */
- if ((i == 0) || (rd_sync() < 0))
- goto out;
-
- /*
- * when we get an error none of the data we already
- * have can be used to create a legal header (we just
- * got an error in the middle), so we throw it all out
- * and refill the buffer with fresh data.
- */
- res = BLKMULT;
- hdsz = 0;
- hdend = hdbuf;
- if (!notice) {
- if (act == APPND)
- return(-1);
- paxwarn(1,"Cannot identify format. Searching...");
- ++notice;
- }
- }
-
- /*
- * we have at least the size of the smallest header in any
- * archive format. Look to see if we have a match. The array
- * ford[] is used to specify the header id order to reduce the
- * chance of incorrectly id'ing a valid header (some formats
- * may be subsets of each other and the order would then be
- * important).
- */
- for (i = 0; ford[i] >= 0; ++i) {
- if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0)
- continue;
- frmt = &(fsub[ford[i]]);
- /*
- * yuck, to avoid slow special case code in the extract
- * routines, just push this header back as if it was
- * not seen. We have left extra space at start of the
- * buffer for this purpose. This is a bit ugly, but
- * adding all the special case code is far worse.
- */
- pback(hdbuf, hdsz);
- return(0);
- }
-
- /*
- * We have a flawed archive, no match. we start searching, but
- * we never allow additions to flawed archives
- */
- if (!notice) {
- if (act == APPND)
- return(-1);
- paxwarn(1, "Cannot identify format. Searching...");
- ++notice;
- }
-
- /*
- * brute force search for a header that we can id.
- * we shift through byte at a time. this is slow, but we cannot
- * determine the nature of the flaw in the archive in a
- * portable manner
- */
- if (--hdsz > 0) {
- memmove(hdbuf, hdbuf+1, hdsz);
- res = BLKMULT - hdsz;
- hdend = hdbuf + hdsz;
- } else {
- res = BLKMULT;
- hdend = hdbuf;
- hdsz = 0;
- }
- }
-
- out:
- /*
- * we cannot find a header, bow, apologize and quit
- */
- paxwarn(1, "Sorry, unable to determine archive format.");
- return(-1);
-}
diff --git a/pax/buf_subs.c b/pax/buf_subs.c
@@ -1,985 +0,0 @@
-/* $OpenBSD: buf_subs.c,v 1.23 2009/12/22 12:09:36 jasper Exp $ */
-/* $NetBSD: buf_subs.c,v 1.5 1995/03/21 09:07:08 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include "pax.h"
-#include "extern.h"
-
-/*
- * routines which implement archive and file buffering
- */
-
-#define MINFBSZ 512 /* default block size for hole detect */
-#define MAXFLT 10 /* default media read error limit */
-
-/*
- * Need to change bufmem to dynamic allocation when the upper
- * limit on blocking size is removed (though that will violate pax spec)
- * MAXBLK define and tests will also need to be updated.
- */
-static char bufmem[MAXBLK+BLKMULT]; /* i/o buffer + pushback id space */
-static char *buf; /* normal start of i/o buffer */
-static char *bufend; /* end or last char in i/o buffer */
-static char *bufpt; /* read/write point in i/o buffer */
-int blksz = MAXBLK; /* block input/output size in bytes */
-int wrblksz; /* user spec output size in bytes */
-int maxflt = MAXFLT; /* MAX consecutive media errors */
-int rdblksz; /* first read blksize (tapes only) */
-off_t wrlimit; /* # of bytes written per archive vol */
-off_t wrcnt; /* # of bytes written on current vol */
-off_t rdcnt; /* # of bytes read on current vol */
-
-/*
- * wr_start()
- * set up the buffering system to operate in a write mode
- * Return:
- * 0 if ok, -1 if the user specified write block size violates pax spec
- */
-
-int
-wr_start(void)
-{
- buf = &(bufmem[BLKMULT]);
- /*
- * Check to make sure the write block size meets pax specs. If the user
- * does not specify a blocksize, we use the format default blocksize.
- * We must be picky on writes, so we do not allow the user to create an
- * archive that might be hard to read elsewhere. If all ok, we then
- * open the first archive volume
- */
- if (!wrblksz)
- wrblksz = frmt->bsz;
- if (wrblksz > MAXBLK) {
- paxwarn(1, "Write block size of %d too large, maximium is: %d",
- wrblksz, MAXBLK);
- return(-1);
- }
- if (wrblksz % BLKMULT) {
- paxwarn(1, "Write block size of %d is not a %d byte multiple",
- wrblksz, BLKMULT);
- return(-1);
- }
- if (wrblksz > MAXBLK_POSIX) {
- paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable",
- wrblksz, MAXBLK_POSIX);
- return(-1);
- }
-
- /*
- * we only allow wrblksz to be used with all archive operations
- */
- blksz = rdblksz = wrblksz;
- if ((ar_open(arcname) < 0) && (ar_next() < 0))
- return(-1);
- wrcnt = 0;
- bufend = buf + wrblksz;
- bufpt = buf;
- return(0);
-}
-
-/*
- * rd_start()
- * set up buffering system to read an archive
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-rd_start(void)
-{
- /*
- * leave space for the header pushback (see get_arc()). If we are
- * going to append and user specified a write block size, check it
- * right away
- */
- buf = &(bufmem[BLKMULT]);
- if ((act == APPND) && wrblksz) {
- if (wrblksz > MAXBLK) {
- paxwarn(1,"Write block size %d too large, maximium is: %d",
- wrblksz, MAXBLK);
- return(-1);
- }
- if (wrblksz % BLKMULT) {
- paxwarn(1, "Write block size %d is not a %d byte multiple",
- wrblksz, BLKMULT);
- return(-1);
- }
- }
-
- /*
- * open the archive
- */
- if ((ar_open(arcname) < 0) && (ar_next() < 0))
- return(-1);
- bufend = buf + rdblksz;
- bufpt = bufend;
- rdcnt = 0;
- return(0);
-}
-
-/*
- * cp_start()
- * set up buffer system for copying within the file system
- */
-
-void
-cp_start(void)
-{
- buf = &(bufmem[BLKMULT]);
- rdblksz = blksz = MAXBLK;
-}
-
-/*
- * appnd_start()
- * Set up the buffering system to append new members to an archive that
- * was just read. The last block(s) of an archive may contain a format
- * specific trailer. To append a new member, this trailer has to be
- * removed from the archive. The first byte of the trailer is replaced by
- * the start of the header of the first file added to the archive. The
- * format specific end read function tells us how many bytes to move
- * backwards in the archive to be positioned BEFORE the trailer. Two
- * different position have to be adjusted, the O.S. file offset (e.g. the
- * position of the tape head) and the write point within the data we have
- * stored in the read (soon to become write) buffer. We may have to move
- * back several records (the number depends on the size of the archive
- * record and the size of the format trailer) to read up the record where
- * the first byte of the trailer is recorded. Trailers may span (and
- * overlap) record boundaries.
- * We first calculate which record has the first byte of the trailer. We
- * move the OS file offset back to the start of this record and read it
- * up. We set the buffer write pointer to be at this byte (the byte where
- * the trailer starts). We then move the OS file pointer back to the
- * start of this record so a flush of this buffer will replace the record
- * in the archive.
- * A major problem is rewriting this last record. For archives stored
- * on disk files, this is trivial. However, many devices are really picky
- * about the conditions under which they will allow a write to occur.
- * Often devices restrict the conditions where writes can be made,
- * so it may not be feasible to append archives stored on all types of
- * devices.
- * Return:
- * 0 for success, -1 for failure
- */
-
-int
-appnd_start(off_t skcnt)
-{
- int res;
- off_t cnt;
-
- if (exit_val != 0) {
- paxwarn(0, "Cannot append to an archive that may have flaws.");
- return(-1);
- }
- /*
- * if the user did not specify a write blocksize, inherit the size used
- * in the last archive volume read. (If a is set we still use rdblksz
- * until next volume, cannot shift sizes within a single volume).
- */
- if (!wrblksz)
- wrblksz = blksz = rdblksz;
- else
- blksz = rdblksz;
-
- /*
- * make sure that this volume allows appends
- */
- if (ar_app_ok() < 0)
- return(-1);
-
- /*
- * Calculate bytes to move back and move in front of record where we
- * need to start writing from. Remember we have to add in any padding
- * that might be in the buffer after the trailer in the last block. We
- * travel skcnt + padding ROUNDED UP to blksize.
- */
- skcnt += bufend - bufpt;
- if ((cnt = (skcnt/blksz) * blksz) < skcnt)
- cnt += blksz;
- if (ar_rev((off_t)cnt) < 0)
- goto out;
-
- /*
- * We may have gone too far if there is valid data in the block we are
- * now in front of, read up the block and position the pointer after
- * the valid data.
- */
- if ((cnt -= skcnt) > 0) {
- /*
- * watch out for stupid tape drives. ar_rev() will set rdblksz
- * to be real physical blocksize so we must loop until we get
- * the old rdblksz (now in blksz). If ar_rev() fouls up the
- * determination of the physical block size, we will fail.
- */
- bufpt = buf;
- bufend = buf + blksz;
- while (bufpt < bufend) {
- if ((res = ar_read(bufpt, rdblksz)) <= 0)
- goto out;
- bufpt += res;
- }
- if (ar_rev((off_t)(bufpt - buf)) < 0)
- goto out;
- bufpt = buf + cnt;
- bufend = buf + blksz;
- } else {
- /*
- * buffer is empty
- */
- bufend = buf + blksz;
- bufpt = buf;
- }
- rdblksz = blksz;
- rdcnt -= skcnt;
- wrcnt = 0;
-
- /*
- * At this point we are ready to write. If the device requires special
- * handling to write at a point were previously recorded data resides,
- * that is handled in ar_set_wr(). From now on we operate under normal
- * ARCHIVE mode (write) conditions
- */
- if (ar_set_wr() < 0)
- return(-1);
- act = ARCHIVE;
- return(0);
-
- out:
- paxwarn(1, "Unable to rewrite archive trailer, cannot append.");
- return(-1);
-}
-
-/*
- * rd_sync()
- * A read error occurred on this archive volume. Resync the buffer and
- * try to reset the device (if possible) so we can continue to read. Keep
- * trying to do this until we get a valid read, or we reach the limit on
- * consecutive read faults (at which point we give up). The user can
- * adjust the read error limit through a command line option.
- * Returns:
- * 0 on success, and -1 on failure
- */
-
-int
-rd_sync(void)
-{
- int errcnt = 0;
- int res;
-
- /*
- * if the user says bail out on first fault, we are out of here...
- */
- if (maxflt == 0)
- return(-1);
- if (act == APPND) {
- paxwarn(1, "Unable to append when there are archive read errors.");
- return(-1);
- }
-
- /*
- * poke at device and try to get past media error
- */
- if (ar_rdsync() < 0) {
- if (ar_next() < 0)
- return(-1);
- else
- rdcnt = 0;
- }
-
- for (;;) {
- if ((res = ar_read(buf, blksz)) > 0) {
- /*
- * All right! got some data, fill that buffer
- */
- bufpt = buf;
- bufend = buf + res;
- rdcnt += res;
- return(0);
- }
-
- /*
- * Oh well, yet another failed read...
- * if error limit reached, ditch. o.w. poke device to move past
- * bad media and try again. if media is badly damaged, we ask
- * the poor (and upset user at this point) for the next archive
- * volume. remember the goal on reads is to get the most we
- * can extract out of the archive.
- */
- if ((maxflt > 0) && (++errcnt > maxflt))
- paxwarn(0,"Archive read error limit (%d) reached",maxflt);
- else if (ar_rdsync() == 0)
- continue;
- if (ar_next() < 0)
- break;
- rdcnt = 0;
- errcnt = 0;
- }
- return(-1);
-}
-
-/*
- * pback()
- * push the data used during the archive id phase back into the I/O
- * buffer. This is required as we cannot be sure that the header does NOT
- * overlap a block boundary (as in the case we are trying to recover a
- * flawed archived). This was not designed to be used for any other
- * purpose. (What software engineering, HA!)
- * WARNING: do not even THINK of pback greater than BLKMULT, unless the
- * pback space is increased.
- */
-
-void
-pback(char *pt, int cnt)
-{
- bufpt -= cnt;
- memcpy(bufpt, pt, cnt);
- return;
-}
-
-/*
- * rd_skip()
- * skip forward in the archive during a archive read. Used to get quickly
- * past file data and padding for files the user did NOT select.
- * Return:
- * 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected.
- */
-
-int
-rd_skip(off_t skcnt)
-{
- off_t res;
- off_t cnt;
- off_t skipped = 0;
-
- /*
- * consume what data we have in the buffer. If we have to move forward
- * whole records, we call the low level skip function to see if we can
- * move within the archive without doing the expensive reads on data we
- * do not want.
- */
- if (skcnt == 0)
- return(0);
- res = MIN((bufend - bufpt), skcnt);
- bufpt += res;
- skcnt -= res;
-
- /*
- * if skcnt is now 0, then no additional i/o is needed
- */
- if (skcnt == 0)
- return(0);
-
- /*
- * We have to read more, calculate complete and partial record reads
- * based on rdblksz. we skip over "cnt" complete records
- */
- res = skcnt%rdblksz;
- cnt = (skcnt/rdblksz) * rdblksz;
-
- /*
- * if the skip fails, we will have to resync. ar_fow will tell us
- * how much it can skip over. We will have to read the rest.
- */
- if (ar_fow(cnt, &skipped) < 0)
- return(-1);
- res += cnt - skipped;
- rdcnt += skipped;
-
- /*
- * what is left we have to read (which may be the whole thing if
- * ar_fow() told us the device can only read to skip records);
- */
- while (res > 0L) {
- cnt = bufend - bufpt;
- /*
- * if the read fails, we will have to resync
- */
- if ((cnt <= 0) && ((cnt = buf_fill()) < 0))
- return(-1);
- if (cnt == 0)
- return(1);
- cnt = MIN(cnt, res);
- bufpt += cnt;
- res -= cnt;
- }
- return(0);
-}
-
-/*
- * wr_fin()
- * flush out any data (and pad if required) the last block. We always pad
- * with zero (even though we do not have to). Padding with 0 makes it a
- * lot easier to recover if the archive is damaged. zero padding SHOULD
- * BE a requirement....
- */
-
-void
-wr_fin(void)
-{
- if (bufpt > buf) {
- memset(bufpt, 0, bufend - bufpt);
- bufpt = bufend;
- (void)buf_flush(blksz);
- }
-}
-
-/*
- * wr_rdbuf()
- * fill the write buffer from data passed to it in a buffer (usually used
- * by format specific write routines to pass a file header). On failure we
- * punt. We do not allow the user to continue to write flawed archives.
- * We assume these headers are not very large (the memory copy we use is
- * a bit expensive).
- * Return:
- * 0 if buffer was filled ok, -1 o.w. (buffer flush failure)
- */
-
-int
-wr_rdbuf(char *out, int outcnt)
-{
- int cnt;
-
- /*
- * while there is data to copy copy into the write buffer. when the
- * write buffer fills, flush it to the archive and continue
- */
- while (outcnt > 0) {
- cnt = bufend - bufpt;
- if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
- return(-1);
- /*
- * only move what we have space for
- */
- cnt = MIN(cnt, outcnt);
- memcpy(bufpt, out, cnt);
- bufpt += cnt;
- out += cnt;
- outcnt -= cnt;
- }
- return(0);
-}
-
-/*
- * rd_wrbuf()
- * copy from the read buffer into a supplied buffer a specified number of
- * bytes. If the read buffer is empty fill it and continue to copy.
- * usually used to obtain a file header for processing by a format
- * specific read routine.
- * Return
- * number of bytes copied to the buffer, 0 indicates EOF on archive volume,
- * -1 is a read error
- */
-
-int
-rd_wrbuf(char *in, int cpcnt)
-{
- int res;
- int cnt;
- int incnt = cpcnt;
-
- /*
- * loop until we fill the buffer with the requested number of bytes
- */
- while (incnt > 0) {
- cnt = bufend - bufpt;
- if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) {
- /*
- * read error, return what we got (or the error if
- * no data was copied). The caller must know that an
- * error occurred and has the best knowledge what to
- * do with it
- */
- if ((res = cpcnt - incnt) > 0)
- return(res);
- return(cnt);
- }
-
- /*
- * calculate how much data to copy based on whats left and
- * state of buffer
- */
- cnt = MIN(cnt, incnt);
- memcpy(in, bufpt, cnt);
- bufpt += cnt;
- incnt -= cnt;
- in += cnt;
- }
- return(cpcnt);
-}
-
-/*
- * wr_skip()
- * skip forward during a write. In other words add padding to the file.
- * we add zero filled padding as it makes flawed archives much easier to
- * recover from. the caller tells us how many bytes of padding to add
- * This routine was not designed to add HUGE amount of padding, just small
- * amounts (a few 512 byte blocks at most)
- * Return:
- * 0 if ok, -1 if there was a buf_flush failure
- */
-
-int
-wr_skip(off_t skcnt)
-{
- int cnt;
-
- /*
- * loop while there is more padding to add
- */
- while (skcnt > 0L) {
- cnt = bufend - bufpt;
- if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
- return(-1);
- cnt = MIN(cnt, skcnt);
- memset(bufpt, 0, cnt);
- bufpt += cnt;
- skcnt -= cnt;
- }
- return(0);
-}
-
-/*
- * wr_rdfile()
- * fill write buffer with the contents of a file. We are passed an open
- * file descriptor to the file an the archive structure that describes the
- * file we are storing. The variable "left" is modified to contain the
- * number of bytes of the file we were NOT able to write to the archive.
- * it is important that we always write EXACTLY the number of bytes that
- * the format specific write routine told us to. The file can also get
- * bigger, so reading to the end of file would create an improper archive,
- * we just detect this case and warn the user. We never create a bad
- * archive if we can avoid it. Of course trying to archive files that are
- * active is asking for trouble. It we fail, we pass back how much we
- * could NOT copy and let the caller deal with it.
- * Return:
- * 0 ok, -1 if archive write failure. a short read of the file returns a
- * 0, but "left" is set to be greater than zero.
- */
-
-int
-wr_rdfile(ARCHD *arcn, int ifd, off_t *left)
-{
- int cnt;
- int res = 0;
- off_t size = arcn->sb.st_size;
- struct stat sb;
-
- /*
- * while there are more bytes to write
- */
- while (size > 0L) {
- cnt = bufend - bufpt;
- if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) {
- *left = size;
- return(-1);
- }
- cnt = MIN(cnt, size);
- if ((res = read(ifd, bufpt, cnt)) <= 0)
- break;
- size -= res;
- bufpt += res;
- }
-
- /*
- * better check the file did not change during this operation
- * or the file read failed.
- */
- if (res < 0)
- syswarn(1, errno, "Read fault on %s", arcn->org_name);
- else if (size != 0L)
- paxwarn(1, "File changed size during read %s", arcn->org_name);
- else if (fstat(ifd, &sb) < 0)
- syswarn(1, errno, "Failed stat on %s", arcn->org_name);
- else if (arcn->sb.st_mtime != sb.st_mtime)
- paxwarn(1, "File %s was modified during copy to archive",
- arcn->org_name);
- *left = size;
- return(0);
-}
-
-/*
- * rd_wrfile()
- * extract the contents of a file from the archive. If we are unable to
- * extract the entire file (due to failure to write the file) we return
- * the numbers of bytes we did NOT process. This way the caller knows how
- * many bytes to skip past to find the next archive header. If the failure
- * was due to an archive read, we will catch that when we try to skip. If
- * the format supplies a file data crc value, we calculate the actual crc
- * so that it can be compared to the value stored in the header
- * NOTE:
- * We call a special function to write the file. This function attempts to
- * restore file holes (blocks of zeros) into the file. When files are
- * sparse this saves space, and is a LOT faster. For non sparse files
- * the performance hit is small. As of this writing, no archive supports
- * information on where the file holes are.
- * Return:
- * 0 ok, -1 if archive read failure. if we cannot write the entire file,
- * we return a 0 but "left" is set to be the amount unwritten
- */
-
-int
-rd_wrfile(ARCHD *arcn, int ofd, off_t *left)
-{
- int cnt = 0;
- off_t size = arcn->sb.st_size;
- int res = 0;
- char *fnm = arcn->name;
- int isem = 1;
- int rem;
- int sz = MINFBSZ;
- struct stat sb;
- u_int32_t crc = 0;
-
- /*
- * pass the blocksize of the file being written to the write routine,
- * if the size is zero, use the default MINFBSZ
- */
- if (ofd < 0)
- sz = PAXPATHLEN + 1; /* GNU tar long link/file */
- else if (fstat(ofd, &sb) == 0) {
- if (sb.st_blksize > 0)
- sz = (int)sb.st_blksize;
- } else
- syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
- rem = sz;
- *left = 0L;
-
- /*
- * Copy the archive to the file the number of bytes specified. We have
- * to assume that we want to recover file holes as none of the archive
- * formats can record the location of file holes.
- */
- while (size > 0L) {
- cnt = bufend - bufpt;
- /*
- * if we get a read error, we do not want to skip, as we may
- * miss a header, so we do not set left, but if we get a write
- * error, we do want to skip over the unprocessed data.
- */
- if ((cnt <= 0) && ((cnt = buf_fill()) <= 0))
- break;
- cnt = MIN(cnt, size);
- if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) {
- *left = size;
- break;
- }
-
- if (docrc) {
- /*
- * update the actual crc value
- */
- cnt = res;
- while (--cnt >= 0)
- crc += *bufpt++ & 0xff;
- } else
- bufpt += res;
- size -= res;
- }
-
- /*
- * if the last block has a file hole (all zero), we must make sure this
- * gets updated in the file. We force the last block of zeros to be
- * written. just closing with the file offset moved forward may not put
- * a hole at the end of the file.
- */
- if (isem && (arcn->sb.st_size > 0L))
- file_flush(ofd, fnm, isem);
-
- /*
- * if we failed from archive read, we do not want to skip
- */
- if ((size > 0L) && (*left == 0L))
- return(-1);
-
- /*
- * some formats record a crc on file data. If so, then we compare the
- * calculated crc to the crc stored in the archive
- */
- if (docrc && (size == 0L) && (arcn->crc != crc))
- paxwarn(1,"Actual crc does not match expected crc %s",arcn->name);
- return(0);
-}
-
-/*
- * cp_file()
- * copy the contents of one file to another. used during -rw phase of pax
- * just as in rd_wrfile() we use a special write function to write the
- * destination file so we can properly copy files with holes.
- */
-
-void
-cp_file(ARCHD *arcn, int fd1, int fd2)
-{
- int cnt;
- off_t cpcnt = 0L;
- int res = 0;
- char *fnm = arcn->name;
- int no_hole = 0;
- int isem = 1;
- int rem;
- int sz = MINFBSZ;
- struct stat sb;
-
- /*
- * check for holes in the source file. If none, we will use regular
- * write instead of file write.
- */
- if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size)
- ++no_hole;
-
- /*
- * pass the blocksize of the file being written to the write routine,
- * if the size is zero, use the default MINFBSZ
- */
- if (fstat(fd2, &sb) == 0) {
- if (sb.st_blksize > 0)
- sz = sb.st_blksize;
- } else
- syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
- rem = sz;
-
- /*
- * read the source file and copy to destination file until EOF
- */
- for (;;) {
- if ((cnt = read(fd1, buf, blksz)) <= 0)
- break;
- if (no_hole)
- res = write(fd2, buf, cnt);
- else
- res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm);
- if (res != cnt)
- break;
- cpcnt += cnt;
- }
-
- /*
- * check to make sure the copy is valid.
- */
- if (res < 0)
- syswarn(1, errno, "Failed write during copy of %s to %s",
- arcn->org_name, arcn->name);
- else if (cpcnt != arcn->sb.st_size)
- paxwarn(1, "File %s changed size during copy to %s",
- arcn->org_name, arcn->name);
- else if (fstat(fd1, &sb) < 0)
- syswarn(1, errno, "Failed stat of %s", arcn->org_name);
- else if (arcn->sb.st_mtime != sb.st_mtime)
- paxwarn(1, "File %s was modified during copy to %s",
- arcn->org_name, arcn->name);
-
- /*
- * if the last block has a file hole (all zero), we must make sure this
- * gets updated in the file. We force the last block of zeros to be
- * written. just closing with the file offset moved forward may not put
- * a hole at the end of the file.
- */
- if (!no_hole && isem && (arcn->sb.st_size > 0L))
- file_flush(fd2, fnm, isem);
- return;
-}
-
-/*
- * buf_fill()
- * fill the read buffer with the next record (or what we can get) from
- * the archive volume.
- * Return:
- * Number of bytes of data in the read buffer, -1 for read error, and
- * 0 when finished (user specified termination in ar_next()).
- */
-
-int
-buf_fill(void)
-{
- int cnt;
- static int fini = 0;
-
- if (fini)
- return(0);
-
- for (;;) {
- /*
- * try to fill the buffer. on error the next archive volume is
- * opened and we try again.
- */
- if ((cnt = ar_read(buf, blksz)) > 0) {
- bufpt = buf;
- bufend = buf + cnt;
- rdcnt += cnt;
- return(cnt);
- }
-
- /*
- * errors require resync, EOF goes to next archive
- */
- if (cnt < 0)
- break;
- if (ar_next() < 0) {
- fini = 1;
- return(0);
- }
- rdcnt = 0;
- }
- exit_val = 1;
- return(-1);
-}
-
-/*
- * buf_flush()
- * force the write buffer to the archive. We are passed the number of
- * bytes in the buffer at the point of the flush. When we change archives
- * the record size might change. (either larger or smaller).
- * Return:
- * 0 if all is ok, -1 when a write error occurs.
- */
-
-int
-buf_flush(int bufcnt)
-{
- int cnt;
- int push = 0;
- int totcnt = 0;
-
- /*
- * if we have reached the user specified byte count for each archive
- * volume, prompt for the next volume. (The non-standard -R flag).
- * NOTE: If the wrlimit is smaller than wrcnt, we will always write
- * at least one record. We always round limit UP to next blocksize.
- */
- if ((wrlimit > 0) && (wrcnt > wrlimit)) {
- paxwarn(0, "User specified archive volume byte limit reached.");
- if (ar_next() < 0) {
- wrcnt = 0;
- exit_val = 1;
- return(-1);
- }
- wrcnt = 0;
-
- /*
- * The new archive volume might have changed the size of the
- * write blocksize. if so we figure out if we need to write
- * (one or more times), or if there is now free space left in
- * the buffer (it is no longer full). bufcnt has the number of
- * bytes in the buffer, (the blocksize, at the point we were
- * CALLED). Push has the amount of "extra" data in the buffer
- * if the block size has shrunk from a volume change.
- */
- bufend = buf + blksz;
- if (blksz > bufcnt)
- return(0);
- if (blksz < bufcnt)
- push = bufcnt - blksz;
- }
-
- /*
- * We have enough data to write at least one archive block
- */
- for (;;) {
- /*
- * write a block and check if it all went out ok
- */
- cnt = ar_write(buf, blksz);
- if (cnt == blksz) {
- /*
- * the write went ok
- */
- wrcnt += cnt;
- totcnt += cnt;
- if (push > 0) {
- /* we have extra data to push to the front.
- * check for more than 1 block of push, and if
- * so we loop back to write again
- */
- memcpy(buf, bufend, push);
- bufpt = buf + push;
- if (push >= blksz) {
- push -= blksz;
- continue;
- }
- } else
- bufpt = buf;
- return(totcnt);
- } else if (cnt > 0) {
- /*
- * Oh drat we got a partial write!
- * if format does not care about alignment let it go,
- * we warned the user in ar_write().... but this means
- * the last record on this volume violates pax spec....
- */
- totcnt += cnt;
- wrcnt += cnt;
- bufpt = buf + cnt;
- cnt = bufcnt - cnt;
- memcpy(buf, bufpt, cnt);
- bufpt = buf + cnt;
- if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0))
- return(totcnt);
- break;
- }
-
- /*
- * All done, go to next archive
- */
- wrcnt = 0;
- if (ar_next() < 0)
- break;
-
- /*
- * The new archive volume might also have changed the block
- * size. if so, figure out if we have too much or too little
- * data for using the new block size
- */
- bufend = buf + blksz;
- if (blksz > bufcnt)
- return(0);
- if (blksz < bufcnt)
- push = bufcnt - blksz;
- }
-
- /*
- * write failed, stop pax. we must not create a bad archive!
- */
- exit_val = 1;
- return(-1);
-}
diff --git a/pax/cache.c b/pax/cache.c
@@ -1,417 +0,0 @@
-/* $OpenBSD: cache.c,v 1.19 2009/12/22 12:09:36 jasper Exp $ */
-/* $NetBSD: cache.c,v 1.4 1995/03/21 09:07:10 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <string.h>
-#include <stdio.h>
-#include <pwd.h>
-#include <grp.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "pax.h"
-#include "cache.h"
-#include "extern.h"
-
-/*
- * routines that control user, group, uid and gid caches (for the archive
- * member print routine).
- * IMPORTANT:
- * these routines cache BOTH hits and misses, a major performance improvement
- */
-
-static int pwopn = 0; /* is password file open */
-static int gropn = 0; /* is group file open */
-static UIDC **uidtb = NULL; /* uid to name cache */
-static GIDC **gidtb = NULL; /* gid to name cache */
-static UIDC **usrtb = NULL; /* user name to uid cache */
-static GIDC **grptb = NULL; /* group name to gid cache */
-
-/*
- * uidtb_start
- * creates an empty uidtb
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-uidtb_start(void)
-{
- static int fail = 0;
-
- if (uidtb != NULL)
- return(0);
- if (fail)
- return(-1);
- if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
- ++fail;
- paxwarn(1, "Unable to allocate memory for user id cache table");
- return(-1);
- }
- return(0);
-}
-
-/*
- * gidtb_start
- * creates an empty gidtb
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-gidtb_start(void)
-{
- static int fail = 0;
-
- if (gidtb != NULL)
- return(0);
- if (fail)
- return(-1);
- if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
- ++fail;
- paxwarn(1, "Unable to allocate memory for group id cache table");
- return(-1);
- }
- return(0);
-}
-
-/*
- * usrtb_start
- * creates an empty usrtb
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-usrtb_start(void)
-{
- static int fail = 0;
-
- if (usrtb != NULL)
- return(0);
- if (fail)
- return(-1);
- if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
- ++fail;
- paxwarn(1, "Unable to allocate memory for user name cache table");
- return(-1);
- }
- return(0);
-}
-
-/*
- * grptb_start
- * creates an empty grptb
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-grptb_start(void)
-{
- static int fail = 0;
-
- if (grptb != NULL)
- return(0);
- if (fail)
- return(-1);
- if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
- ++fail;
- paxwarn(1,"Unable to allocate memory for group name cache table");
- return(-1);
- }
- return(0);
-}
-
-/*
- * name_uid()
- * caches the name (if any) for the uid. If frc set, we always return the
- * the stored name (if valid or invalid match). We use a simple hash table.
- * Return
- * Pointer to stored name (or a empty string)
- */
-
-char *
-name_uid(uid_t uid, int frc)
-{
- struct passwd *pw;
- UIDC *ptr;
-
- if ((uidtb == NULL) && (uidtb_start() < 0))
- return("");
-
- /*
- * see if we have this uid cached
- */
- ptr = uidtb[uid % UID_SZ];
- if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
- /*
- * have an entry for this uid
- */
- if (frc || (ptr->valid == VALID))
- return(ptr->name);
- return("");
- }
-
- /*
- * No entry for this uid, we will add it
- */
- if (!pwopn) {
- setpassent(1);
- ++pwopn;
- }
- if (ptr == NULL)
- ptr = uidtb[uid % UID_SZ] = malloc(sizeof(UIDC));
-
- if ((pw = getpwuid(uid)) == NULL) {
- /*
- * no match for this uid in the local password file
- * a string that is the uid in numeric format
- */
- if (ptr == NULL)
- return("");
- ptr->uid = uid;
- ptr->valid = INVALID;
- (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
- (unsigned long)uid);
- if (frc == 0)
- return("");
- } else {
- /*
- * there is an entry for this uid in the password file
- */
- if (ptr == NULL)
- return(pw->pw_name);
- ptr->uid = uid;
- (void)strlcpy(ptr->name, pw->pw_name, sizeof(ptr->name));
- ptr->valid = VALID;
- }
- return(ptr->name);
-}
-
-/*
- * name_gid()
- * caches the name (if any) for the gid. If frc set, we always return the
- * the stored name (if valid or invalid match). We use a simple hash table.
- * Return
- * Pointer to stored name (or a empty string)
- */
-
-char *
-name_gid(gid_t gid, int frc)
-{
- struct group *gr;
- GIDC *ptr;
-
- if ((gidtb == NULL) && (gidtb_start() < 0))
- return("");
-
- /*
- * see if we have this gid cached
- */
- ptr = gidtb[gid % GID_SZ];
- if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
- /*
- * have an entry for this gid
- */
- if (frc || (ptr->valid == VALID))
- return(ptr->name);
- return("");
- }
-
- /*
- * No entry for this gid, we will add it
- */
- if (!gropn) {
- setgroupent(1);
- ++gropn;
- }
- if (ptr == NULL)
- ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC));
-
- if ((gr = getgrgid(gid)) == NULL) {
- /*
- * no match for this gid in the local group file, put in
- * a string that is the gid in numeric format
- */
- if (ptr == NULL)
- return("");
- ptr->gid = gid;
- ptr->valid = INVALID;
- (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
- (unsigned long)gid);
- if (frc == 0)
- return("");
- } else {
- /*
- * there is an entry for this group in the group file
- */
- if (ptr == NULL)
- return(gr->gr_name);
- ptr->gid = gid;
- (void)strlcpy(ptr->name, gr->gr_name, sizeof(ptr->name));
- ptr->valid = VALID;
- }
- return(ptr->name);
-}
-
-/*
- * uid_name()
- * caches the uid for a given user name. We use a simple hash table.
- * Return
- * the uid (if any) for a user name, or a -1 if no match can be found
- */
-
-int
-uid_name(char *name, uid_t *uid)
-{
- struct passwd *pw;
- UIDC *ptr;
- int namelen;
-
- /*
- * return -1 for mangled names
- */
- if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
- return(-1);
- if ((usrtb == NULL) && (usrtb_start() < 0))
- return(-1);
-
- /*
- * look up in hash table, if found and valid return the uid,
- * if found and invalid, return a -1
- */
- ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
- if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
- if (ptr->valid == INVALID)
- return(-1);
- *uid = ptr->uid;
- return(0);
- }
-
- if (!pwopn) {
- setpassent(1);
- ++pwopn;
- }
-
- if (ptr == NULL)
- ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
- (UIDC *)malloc(sizeof(UIDC));
-
- /*
- * no match, look it up, if no match store it as an invalid entry,
- * or store the matching uid
- */
- if (ptr == NULL) {
- if ((pw = getpwnam(name)) == NULL)
- return(-1);
- *uid = pw->pw_uid;
- return(0);
- }
- (void)strlcpy(ptr->name, name, sizeof(ptr->name));
- if ((pw = getpwnam(name)) == NULL) {
- ptr->valid = INVALID;
- return(-1);
- }
- ptr->valid = VALID;
- *uid = ptr->uid = pw->pw_uid;
- return(0);
-}
-
-/*
- * gid_name()
- * caches the gid for a given group name. We use a simple hash table.
- * Return
- * the gid (if any) for a group name, or a -1 if no match can be found
- */
-
-int
-gid_name(char *name, gid_t *gid)
-{
- struct group *gr;
- GIDC *ptr;
- int namelen;
-
- /*
- * return -1 for mangled names
- */
- if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
- return(-1);
- if ((grptb == NULL) && (grptb_start() < 0))
- return(-1);
-
- /*
- * look up in hash table, if found and valid return the uid,
- * if found and invalid, return a -1
- */
- ptr = grptb[st_hash(name, namelen, GID_SZ)];
- if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
- if (ptr->valid == INVALID)
- return(-1);
- *gid = ptr->gid;
- return(0);
- }
-
- if (!gropn) {
- setgroupent(1);
- ++gropn;
- }
- if (ptr == NULL)
- ptr = grptb[st_hash(name, namelen, GID_SZ)] =
- (GIDC *)malloc(sizeof(GIDC));
-
- /*
- * no match, look it up, if no match store it as an invalid entry,
- * or store the matching gid
- */
- if (ptr == NULL) {
- if ((gr = getgrnam(name)) == NULL)
- return(-1);
- *gid = gr->gr_gid;
- return(0);
- }
-
- (void)strlcpy(ptr->name, name, sizeof(ptr->name));
- if ((gr = getgrnam(name)) == NULL) {
- ptr->valid = INVALID;
- return(-1);
- }
- ptr->valid = VALID;
- *gid = ptr->gid = gr->gr_gid;
- return(0);
-}
diff --git a/pax/cache.h b/pax/cache.h
@@ -1,73 +0,0 @@
-/* $OpenBSD: cache.h,v 1.4 2003/10/20 06:22:27 jmc Exp $ */
-/* $NetBSD: cache.h,v 1.3 1995/03/21 09:07:12 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)cache.h 8.1 (Berkeley) 5/31/93
- */
-
-/*
- * Constants and data structures used to implement group and password file
- * caches. Traditional passwd/group cache routines perform quite poorly with
- * archives. The chances of hitting a valid lookup with an archive is quite a
- * bit worse than with files already resident on the file system. These misses
- * create a MAJOR performance cost. To address this problem, these routines
- * cache both hits and misses.
- *
- * NOTE: name lengths must be as large as those stored in ANY PROTOCOL and
- * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME
- */
-#define UNMLEN 32 /* >= user name found in any protocol */
-#define GNMLEN 32 /* >= group name found in any protocol */
-#define UID_SZ 317 /* size of user_name/uid cache */
-#define UNM_SZ 317 /* size of user_name/uid cache */
-#define GID_SZ 251 /* size of gid cache */
-#define GNM_SZ 317 /* size of group name cache */
-#define VALID 1 /* entry and name are valid */
-#define INVALID 2 /* entry valid, name NOT valid */
-
-/*
- * Node structures used in the user, group, uid, and gid caches.
- */
-
-typedef struct uidc {
- int valid; /* is this a valid or a miss entry */
- char name[UNMLEN]; /* uid name */
- uid_t uid; /* cached uid */
-} UIDC;
-
-typedef struct gidc {
- int valid; /* is this a valid or a miss entry */
- char name[GNMLEN]; /* gid name */
- gid_t gid; /* cached gid */
-} GIDC;
diff --git a/pax/cpio.1 b/pax/cpio.1
@@ -1,308 +0,0 @@
-.\" $OpenBSD: cpio.1,v 1.34 2011/09/03 22:59:08 jmc Exp $
-.\"
-.\" Copyright (c) 1997 SigmaSoft, Th. Lockert
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.Dd $Mdocdate: September 3 2011 $
-.Dt CPIO 1
-.Os
-.Sh NAME
-.Nm cpio
-.Nd copy file archives in and out
-.Sh SYNOPSIS
-.Nm cpio
-.Fl o
-.Op Fl AaBcjLvZz
-.Op Fl C Ar bytes
-.Op Fl F Ar archive
-.Op Fl H Ar format
-.Op Fl O Ar archive
-.No \*(Lt Ar name-list
-.Op \*(Gt Ar archive
-.Nm cpio
-.Fl i
-.Op Fl 6BbcdfjmrSstuvZz
-.Op Fl C Ar bytes
-.Op Fl E Ar file
-.Op Fl F Ar archive
-.Op Fl H Ar format
-.Op Fl I Ar archive
-.Op Ar pattern ...
-.Op \*(Lt Ar archive
-.Nm cpio
-.Fl p
-.Op Fl adLlmuv
-.Ar destination-directory
-.No \*(Lt Ar name-list
-.Sh DESCRIPTION
-The
-.Nm
-command copies files to and from a
-.Nm
-archive.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl o
-Create an archive.
-Reads the list of files to store in the
-archive from standard input, and writes the archive on standard
-output.
-.Bl -tag -width Ds
-.It Fl A
-Append to the specified archive.
-.It Fl a
-Reset the access times on files that have been copied to the
-archive.
-.It Fl B
-Set block size of output to 5120 bytes.
-.It Fl C Ar bytes
-Set the block size of output to
-.Ar bytes .
-.It Fl c
-Use ASCII format for
-.Nm
-header for portability.
-.It Fl F Ar archive
-Use the specified file as the input for the archive.
-.It Fl H Ar format
-Write the archive in the specified format.
-Recognized formats are:
-.Pp
-.Bl -tag -width sv4cpio -compact
-.It Ar bcpio
-Old binary
-.Nm
-format.
-.It Ar cpio
-Old octal character
-.Nm
-format.
-.It Ar sv4cpio
-SVR4 hex
-.Nm
-format.
-.It Ar tar
-Old tar format.
-.It Ar ustar
-POSIX ustar format.
-.El
-.It Fl j
-Compress archive using the bzip2 format.
-The bzip2 utility must be installed separately.
-.It Fl L
-Follow symbolic links.
-.It Fl O Ar archive
-Use the specified file name as the archive to write to.
-.It Fl v
-Be verbose about operations.
-List filenames as they are written to the archive.
-.It Fl Z
-Compress archive using
-.Xr compress 1
-format.
-.It Fl z
-Compress archive using
-.Xr gzip 1
-format.
-.El
-.It Fl i
-Restore files from an archive.
-Reads the archive file from
-standard input and extracts files matching the
-.Ar patterns
-that were specified on the command line.
-.Bl -tag -width Ds
-.It Fl 6
-Process old-style
-.Nm
-format archives.
-.It Fl B
-Set the block size of the archive being read to 5120 bytes.
-.It Fl b
-Do byte and word swapping after reading in data from the
-archive, for restoring archives created on systems with
-a different byte order.
-.It Fl C Ar bytes
-Read archive written with a block size of
-.Ar bytes .
-.It Fl c
-Expect the archive headers to be in ASCII format.
-.It Fl d
-Create any intermediate directories as needed during
-restore.
-.It Fl E Ar file
-Read list of file name patterns to extract or list from
-.Ar file .
-.It Fl F Ar archive , Fl I Ar archive
-Use the specified file as the input for the archive.
-.It Fl f
-Restore all files except those matching the
-.Ar patterns
-given on the command line.
-.It Fl H Ar format
-Read an archive of the specified format.
-Recognized formats are:
-.Pp
-.Bl -tag -width sv4cpio -compact
-.It Ar bcpio
-Old binary
-.Nm
-format.
-.It Ar cpio
-Old octal character
-.Nm
-format.
-.It Ar sv4cpio
-SVR4 hex
-.Nm
-format.
-.It Ar tar
-Old tar format.
-.It Ar ustar
-POSIX ustar format.
-.El
-.It Fl j
-Uncompress archive using the bzip2 format.
-The bzip2 utility must be installed separately.
-.It Fl m
-Restore modification times on files.
-.It Fl r
-Rename restored files interactively.
-.It Fl S
-Swap words after reading data from the archive.
-.It Fl s
-Swap bytes after reading data from the archive.
-.It Fl t
-Only list the contents of the archive, no files or
-directories will be created.
-.It Fl u
-Overwrite files even when the file in the archive is
-older than the one that will be overwritten.
-.It Fl v
-Be verbose about operations.
-List filenames as they are copied in from the archive.
-.It Fl Z
-Uncompress archive using
-.Xr compress 1
-format.
-.It Fl z
-Uncompress archive using
-.Xr gzip 1
-format.
-.El
-.It Fl p
-Copy files from one location to another in a single pass.
-The list of files to copy are read from standard input and
-written out to a directory relative to the specified
-.Ar directory
-argument.
-.Bl -tag -width Ds
-.It Fl a
-Reset the access times on files that have been copied.
-.It Fl d
-Create any intermediate directories as needed to write
-the files at the new location.
-.It Fl L
-Follow symbolic links.
-.It Fl l
-When possible, link files rather than creating an
-extra copy.
-.It Fl m
-Restore modification times on files.
-.It Fl u
-Overwrite files even when the original file being copied is
-older than the one that will be overwritten.
-.It Fl v
-Be verbose about operations.
-List filenames as they are copied.
-.El
-.El
-.Sh ENVIRONMENT
-.Bl -tag -width Fl
-.It Ev TMPDIR
-Path in which to store temporary files.
-.El
-.Sh EXIT STATUS
-The
-.Nm
-utility exits with one of the following values:
-.Pp
-.Bl -tag -width Ds -offset indent -compact
-.It 0
-All files were processed successfully.
-.It 1
-An error occurred.
-.El
-.Sh DIAGNOSTICS
-Whenever
-.Nm
-cannot create a file or a link when extracting an archive or cannot
-find a file while writing an archive, or cannot preserve the user
-ID, group ID, file mode, or access and modification times when the
-.Fl p
-option is specified, a diagnostic message is written to standard
-error and a non-zero exit value will be returned, but processing
-will continue.
-In the case where
-.Nm
-cannot create a link to a file,
-.Nm
-will not create a second copy of the file.
-.Pp
-If the extraction of a file from an archive is prematurely terminated
-by a signal or error,
-.Nm
-may have only partially extracted the file the user wanted.
-Additionally, the file modes of extracted files and directories may
-have incorrect file bits, and the modification and access times may
-be wrong.
-.Pp
-If the creation of an archive is prematurely terminated by a signal
-or error,
-.Nm
-may have only partially created the archive, which may violate the
-specific archive format specification.
-.Sh SEE ALSO
-.Xr pax 1 ,
-.Xr tar 1
-.Sh AUTHORS
-Keith Muller at the University of California, San Diego.
-.Sh CAVEATS
-Different file formats have different maximum file sizes.
-It is recommended that a format such as cpio or ustar
-be used for larger files.
-.Bl -column "File format" "Maximum file size" -offset indent
-.It Sy "File format" Ta Sy "Maximum file size"
-.It bcpio Ta "4 Gigabytes"
-.It sv4cpio Ta "4 Gigabytes"
-.It cpio Ta "8 Gigabytes"
-.It tar Ta "8 Gigabytes"
-.It ustar Ta "8 Gigabytes"
-.El
-.Sh BUGS
-The
-.Fl s
-and
-.Fl S
-options are currently not implemented.
diff --git a/pax/cpio.c b/pax/cpio.c
@@ -1,1140 +0,0 @@
-/* $OpenBSD: cpio.c,v 1.19 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: cpio.c,v 1.5 1995/03/21 09:07:13 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "pax.h"
-#include "cpio.h"
-#include "extern.h"
-
-static int rd_nm(ARCHD *, int);
-static int rd_ln_nm(ARCHD *);
-static int com_rd(ARCHD *);
-
-/*
- * Routines which support the different cpio versions
- */
-
-static int swp_head; /* binary cpio header byte swap */
-
-/*
- * Routines common to all versions of cpio
- */
-
-/*
- * cpio_strd()
- * Fire up the hard link detection code
- * Return:
- * 0 if ok -1 otherwise (the return values of lnk_start())
- */
-
-int
-cpio_strd(void)
-{
- return(lnk_start());
-}
-
-/*
- * cpio_trail()
- * Called to determine if a header block is a valid trailer. We are
- * passed the block, the in_sync flag (which tells us we are in resync
- * mode; looking for a valid header), and cnt (which starts at zero)
- * which is used to count the number of empty blocks we have seen so far.
- * Return:
- * 0 if a valid trailer, -1 if not a valid trailer,
- */
-
-int
-cpio_trail(ARCHD *arcn, char *notused, int notused2, int *notused3)
-{
- /*
- * look for trailer id in file we are about to process
- */
- if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
- return(0);
- return(-1);
-}
-
-/*
- * com_rd()
- * operations common to all cpio read functions.
- * Return:
- * 0
- */
-
-static int
-com_rd(ARCHD *arcn)
-{
- arcn->skip = 0;
- arcn->pat = NULL;
- arcn->org_name = arcn->name;
- switch (arcn->sb.st_mode & C_IFMT) {
- case C_ISFIFO:
- arcn->type = PAX_FIF;
- break;
- case C_ISDIR:
- arcn->type = PAX_DIR;
- break;
- case C_ISBLK:
- arcn->type = PAX_BLK;
- break;
- case C_ISCHR:
- arcn->type = PAX_CHR;
- break;
- case C_ISLNK:
- arcn->type = PAX_SLK;
- break;
- case C_ISOCK:
- arcn->type = PAX_SCK;
- break;
- case C_ISCTG:
- case C_ISREG:
- default:
- /*
- * we have file data, set up skip (pad is set in the format
- * specific sections)
- */
- arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
- arcn->type = PAX_REG;
- arcn->skip = arcn->sb.st_size;
- break;
- }
- if (chk_lnk(arcn) < 0)
- return(-1);
- return(0);
-}
-
-/*
- * cpio_endwr()
- * write the special file with the name trailer in the proper format
- * Return:
- * result of the write of the trailer from the cpio specific write func
- */
-
-int
-cpio_endwr(void)
-{
- ARCHD last;
-
- /*
- * create a trailer request and call the proper format write function
- */
- memset(&last, 0, sizeof(last));
- last.nlen = sizeof(TRAILER) - 1;
- last.type = PAX_REG;
- last.sb.st_nlink = 1;
- (void)strlcpy(last.name, TRAILER, sizeof(last.name));
- return((*frmt->wr)(&last));
-}
-
-/*
- * rd_nam()
- * read in the file name which follows the cpio header
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-static int
-rd_nm(ARCHD *arcn, int nsz)
-{
- /*
- * do not even try bogus values
- */
- if ((nsz == 0) || (nsz > sizeof(arcn->name))) {
- paxwarn(1, "Cpio file name length %d is out of range", nsz);
- return(-1);
- }
-
- /*
- * read the name and make sure it is not empty and is \0 terminated
- */
- if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
- (arcn->name[0] == '\0')) {
- paxwarn(1, "Cpio file name in header is corrupted");
- return(-1);
- }
- return(0);
-}
-
-/*
- * rd_ln_nm()
- * read in the link name for a file with links. The link name is stored
- * like file data (and is NOT \0 terminated!)
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-static int
-rd_ln_nm(ARCHD *arcn)
-{
- /*
- * check the length specified for bogus values
- */
- if ((arcn->sb.st_size == 0) ||
- (arcn->sb.st_size >= sizeof(arcn->ln_name))) {
-# ifdef LONG_OFF_T
- paxwarn(1, "Cpio link name length is invalid: %lu",
- arcn->sb.st_size);
-# else
- paxwarn(1, "Cpio link name length is invalid: %qu",
- arcn->sb.st_size);
-# endif
- return(-1);
- }
-
- /*
- * read in the link name and \0 terminate it
- */
- if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
- (int)arcn->sb.st_size) {
- paxwarn(1, "Cpio link name read error");
- return(-1);
- }
- arcn->ln_nlen = arcn->sb.st_size;
- arcn->ln_name[arcn->ln_nlen] = '\0';
-
- /*
- * watch out for those empty link names
- */
- if (arcn->ln_name[0] == '\0') {
- paxwarn(1, "Cpio link name is corrupt");
- return(-1);
- }
- return(0);
-}
-
-/*
- * Routines common to the extended byte oriented cpio format
- */
-
-/*
- * cpio_id()
- * determine if a block given to us is a valid extended byte oriented
- * cpio header
- * Return:
- * 0 if a valid header, -1 otherwise
- */
-
-int
-cpio_id(char *blk, int size)
-{
- if ((size < sizeof(HD_CPIO)) ||
- (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
- return(-1);
- return(0);
-}
-
-/*
- * cpio_rd()
- * determine if a buffer is a byte oriented extended cpio archive entry.
- * convert and store the values in the ARCHD parameter.
- * Return:
- * 0 if a valid header, -1 otherwise.
- */
-
-int
-cpio_rd(ARCHD *arcn, char *buf)
-{
- int nsz;
- HD_CPIO *hd;
-
- /*
- * check that this is a valid header, if not return -1
- */
- if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
- return(-1);
- hd = (HD_CPIO *)buf;
-
- /*
- * byte oriented cpio (posix) does not have padding! extract the octal
- * ascii fields from the header
- */
- arcn->pad = 0L;
- arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
- arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
- arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
- arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
- arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
- arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
- OCT);
- arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
- arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
- OCT);
- arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
-# ifdef LONG_OFF_T
- arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
- OCT);
-# else
- arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
- OCT);
-# endif
-
- /*
- * check name size and if valid, read in the name of this entry (name
- * follows header in the archive)
- */
- if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
- return(-1);
- arcn->nlen = nsz - 1;
- if (rd_nm(arcn, nsz) < 0)
- return(-1);
-
- if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
- /*
- * no link name to read for this file
- */
- arcn->ln_nlen = 0;
- arcn->ln_name[0] = '\0';
- return(com_rd(arcn));
- }
-
- /*
- * check link name size and read in the link name. Link names are
- * stored like file data.
- */
- if (rd_ln_nm(arcn) < 0)
- return(-1);
-
- /*
- * we have a valid header (with a link)
- */
- return(com_rd(arcn));
-}
-
-/*
- * cpio_endrd()
- * no cleanup needed here, just return size of the trailer (for append)
- * Return:
- * size of trailer header in this format
- */
-
-off_t
-cpio_endrd(void)
-{
- return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
-}
-
-/*
- * cpio_stwr()
- * start up the device mapping table
- * Return:
- * 0 if ok, -1 otherwise (what dev_start() returns)
- */
-
-int
-cpio_stwr(void)
-{
- return(dev_start());
-}
-
-/*
- * cpio_wr()
- * copy the data in the ARCHD to buffer in extended byte oriented cpio
- * format.
- * Return
- * 0 if file has data to be written after the header, 1 if file has NO
- * data to write after the header, -1 if archive write failed
- */
-
-int
-cpio_wr(ARCHD *arcn)
-{
- HD_CPIO *hd;
- int nsz;
- char hdblk[sizeof(HD_CPIO)];
-
- /*
- * check and repair truncated device and inode fields in the header
- */
- if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
- return(-1);
-
- arcn->pad = 0L;
- nsz = arcn->nlen + 1;
- hd = (HD_CPIO *)hdblk;
- if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
- arcn->sb.st_rdev = 0;
-
- switch (arcn->type) {
- case PAX_CTG:
- case PAX_REG:
- case PAX_HRG:
- /*
- * set data size for file data
- */
-# ifdef LONG_OFF_T
- if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
- sizeof(hd->c_filesize), OCT)) {
-# else
- if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
- sizeof(hd->c_filesize), OCT)) {
-# endif
- paxwarn(1,"File is too large for cpio format %s",
- arcn->org_name);
- return(1);
- }
- break;
- case PAX_SLK:
- /*
- * set data size to hold link name
- */
- if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
- sizeof(hd->c_filesize), OCT))
- goto out;
- break;
- default:
- /*
- * all other file types have no file data
- */
- if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
- OCT))
- goto out;
- break;
- }
-
- /*
- * copy the values to the header using octal ascii
- */
- if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
- ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
- OCT) ||
- ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
- OCT) ||
- ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
- goto out;
-
- /*
- * write the file name to the archive
- */
- if ((wr_rdbuf(hdblk, (int)sizeof(HD_CPIO)) < 0) ||
- (wr_rdbuf(arcn->name, nsz) < 0)) {
- paxwarn(1, "Unable to write cpio header for %s", arcn->org_name);
- return(-1);
- }
-
- /*
- * if this file has data, we are done. The caller will write the file
- * data, if we are link tell caller we are done, go to next file
- */
- if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
- (arcn->type == PAX_HRG))
- return(0);
- if (arcn->type != PAX_SLK)
- return(1);
-
- /*
- * write the link name to the archive, tell the caller to go to the
- * next file as we are done.
- */
- if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
- paxwarn(1,"Unable to write cpio link name for %s",arcn->org_name);
- return(-1);
- }
- return(1);
-
- out:
- /*
- * header field is out of range
- */
- paxwarn(1, "Cpio header field is too small to store file %s",
- arcn->org_name);
- return(1);
-}
-
-/*
- * Routines common to the system VR4 version of cpio (with/without file CRC)
- */
-
-/*
- * vcpio_id()
- * determine if a block given to us is a valid system VR4 cpio header
- * WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header
- * uses HEX
- * Return:
- * 0 if a valid header, -1 otherwise
- */
-
-int
-vcpio_id(char *blk, int size)
-{
- if ((size < sizeof(HD_VCPIO)) ||
- (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
- return(-1);
- return(0);
-}
-
-/*
- * crc_id()
- * determine if a block given to us is a valid system VR4 cpio header
- * WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
- * Return:
- * 0 if a valid header, -1 otherwise
- */
-
-int
-crc_id(char *blk, int size)
-{
- if ((size < sizeof(HD_VCPIO)) ||
- (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0))
- return(-1);
- return(0);
-}
-
-/*
- * crc_strd()
- w set file data CRC calculations. Fire up the hard link detection code
- * Return:
- * 0 if ok -1 otherwise (the return values of lnk_start())
- */
-
-int
-crc_strd(void)
-{
- docrc = 1;
- return(lnk_start());
-}
-
-/*
- * vcpio_rd()
- * determine if a buffer is a system VR4 archive entry. (with/without CRC)
- * convert and store the values in the ARCHD parameter.
- * Return:
- * 0 if a valid header, -1 otherwise.
- */
-
-int
-vcpio_rd(ARCHD *arcn, char *buf)
-{
- HD_VCPIO *hd;
- dev_t devminor;
- dev_t devmajor;
- int nsz;
-
- /*
- * during the id phase it was determined if we were using CRC, use the
- * proper id routine.
- */
- if (docrc) {
- if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
- return(-1);
- } else {
- if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
- return(-1);
- }
-
- hd = (HD_VCPIO *)buf;
- arcn->pad = 0L;
-
- /*
- * extract the hex ascii fields from the header
- */
- arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
- arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
- arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
- arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
- arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
- arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
-# ifdef LONG_OFF_T
- arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
- sizeof(hd->c_filesize), HEX);
-# else
- arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
- sizeof(hd->c_filesize), HEX);
-# endif
- arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
- HEX);
- devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
- devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
- arcn->sb.st_dev = TODEV(devmajor, devminor);
- devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
- devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
- arcn->sb.st_rdev = TODEV(devmajor, devminor);
- arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
-
- /*
- * check the length of the file name, if ok read it in, return -1 if
- * bogus
- */
- if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
- return(-1);
- arcn->nlen = nsz - 1;
- if (rd_nm(arcn, nsz) < 0)
- return(-1);
-
- /*
- * skip padding. header + filename is aligned to 4 byte boundaries
- */
- if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
- return(-1);
-
- /*
- * if not a link (or a file with no data), calculate pad size (for
- * padding which follows the file data), clear the link name and return
- */
- if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
- /*
- * we have a valid header (not a link)
- */
- arcn->ln_nlen = 0;
- arcn->ln_name[0] = '\0';
- arcn->pad = VCPIO_PAD(arcn->sb.st_size);
- return(com_rd(arcn));
- }
-
- /*
- * read in the link name and skip over the padding
- */
- if ((rd_ln_nm(arcn) < 0) ||
- (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
- return(-1);
-
- /*
- * we have a valid header (with a link)
- */
- return(com_rd(arcn));
-}
-
-/*
- * vcpio_endrd()
- * no cleanup needed here, just return size of the trailer (for append)
- * Return:
- * size of trailer header in this format
- */
-
-off_t
-vcpio_endrd(void)
-{
- return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
- (VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
-}
-
-/*
- * crc_stwr()
- * start up the device mapping table, enable crc file calculation
- * Return:
- * 0 if ok, -1 otherwise (what dev_start() returns)
- */
-
-int
-crc_stwr(void)
-{
- docrc = 1;
- return(dev_start());
-}
-
-/*
- * vcpio_wr()
- * copy the data in the ARCHD to buffer in system VR4 cpio
- * (with/without crc) format.
- * Return
- * 0 if file has data to be written after the header, 1 if file has
- * NO data to write after the header, -1 if archive write failed
- */
-
-int
-vcpio_wr(ARCHD *arcn)
-{
- HD_VCPIO *hd;
- unsigned int nsz;
- char hdblk[sizeof(HD_VCPIO)];
-
- /*
- * check and repair truncated device and inode fields in the cpio
- * header
- */
- if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
- return(-1);
- nsz = arcn->nlen + 1;
- hd = (HD_VCPIO *)hdblk;
- if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
- arcn->sb.st_rdev = 0;
-
- /*
- * add the proper magic value depending whether we were asked for
- * file data crc's, and the crc if needed.
- */
- if (docrc) {
- if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
- OCT) ||
- ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
- HEX))
- goto out;
- } else {
- if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
- OCT) ||
- ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
- goto out;
- }
-
- switch (arcn->type) {
- case PAX_CTG:
- case PAX_REG:
- case PAX_HRG:
- /*
- * caller will copy file data to the archive. tell him how
- * much to pad.
- */
- arcn->pad = VCPIO_PAD(arcn->sb.st_size);
-# ifdef LONG_OFF_T
- if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
- sizeof(hd->c_filesize), HEX)) {
-# else
- if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
- sizeof(hd->c_filesize), HEX)) {
-# endif
- paxwarn(1,"File is too large for sv4cpio format %s",
- arcn->org_name);
- return(1);
- }
- break;
- case PAX_SLK:
- /*
- * no file data for the caller to process, the file data has
- * the size of the link
- */
- arcn->pad = 0L;
- if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
- sizeof(hd->c_filesize), HEX))
- goto out;
- break;
- default:
- /*
- * no file data for the caller to process
- */
- arcn->pad = 0L;
- if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
- HEX))
- goto out;
- break;
- }
-
- /*
- * set the other fields in the header
- */
- if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
- HEX) ||
- ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
- HEX) ||
- ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
- HEX) ||
- ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
- HEX) ||
- ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
- HEX) ||
- ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
- HEX) ||
- ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
- HEX) ||
- ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
- HEX) ||
- ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
- HEX) ||
- ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
- HEX) ||
- ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
- goto out;
-
- /*
- * write the header, the file name and padding as required.
- */
- if ((wr_rdbuf(hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
- (wr_rdbuf(arcn->name, (int)nsz) < 0) ||
- (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
- paxwarn(1,"Could not write sv4cpio header for %s",arcn->org_name);
- return(-1);
- }
-
- /*
- * if we have file data, tell the caller we are done, copy the file
- */
- if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
- (arcn->type == PAX_HRG))
- return(0);
-
- /*
- * if we are not a link, tell the caller we are done, go to next file
- */
- if (arcn->type != PAX_SLK)
- return(1);
-
- /*
- * write the link name, tell the caller we are done.
- */
- if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
- (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
- paxwarn(1,"Could not write sv4cpio link name for %s",
- arcn->org_name);
- return(-1);
- }
- return(1);
-
- out:
- /*
- * header field is out of range
- */
- paxwarn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
- return(1);
-}
-
-/*
- * Routines common to the old binary header cpio
- */
-
-/*
- * bcpio_id()
- * determine if a block given to us is a old binary cpio header
- * (with/without header byte swapping)
- * Return:
- * 0 if a valid header, -1 otherwise
- */
-
-int
-bcpio_id(char *blk, int size)
-{
- if (size < sizeof(HD_BCPIO))
- return(-1);
-
- /*
- * check both normal and byte swapped magic cookies
- */
- if (((u_short)SHRT_EXT(blk)) == MAGIC)
- return(0);
- if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
- if (!swp_head)
- ++swp_head;
- return(0);
- }
- return(-1);
-}
-
-/*
- * bcpio_rd()
- * determine if a buffer is a old binary archive entry. (it may have byte
- * swapped header) convert and store the values in the ARCHD parameter.
- * This is a very old header format and should not really be used.
- * Return:
- * 0 if a valid header, -1 otherwise.
- */
-
-int
-bcpio_rd(ARCHD *arcn, char *buf)
-{
- HD_BCPIO *hd;
- int nsz;
-
- /*
- * check the header
- */
- if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
- return(-1);
-
- arcn->pad = 0L;
- hd = (HD_BCPIO *)buf;
- if (swp_head) {
- /*
- * header has swapped bytes on 16 bit boundaries
- */
- arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
- arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
- arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
- arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
- arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
- arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
- arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
- arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
- arcn->sb.st_mtime = (arcn->sb.st_mtime << 16) |
- ((time_t)(RSHRT_EXT(hd->h_mtime_2)));
- arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
- arcn->sb.st_size = (arcn->sb.st_size << 16) |
- ((off_t)(RSHRT_EXT(hd->h_filesize_2)));
- nsz = (int)(RSHRT_EXT(hd->h_namesize));
- } else {
- arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
- arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
- arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
- arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
- arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
- arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
- arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
- arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
- arcn->sb.st_mtime = (arcn->sb.st_mtime << 16) |
- ((time_t)(SHRT_EXT(hd->h_mtime_2)));
- arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
- arcn->sb.st_size = (arcn->sb.st_size << 16) |
- ((off_t)(SHRT_EXT(hd->h_filesize_2)));
- nsz = (int)(SHRT_EXT(hd->h_namesize));
- }
- arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
-
- /*
- * check the file name size, if bogus give up. otherwise read the file
- * name
- */
- if (nsz < 2)
- return(-1);
- arcn->nlen = nsz - 1;
- if (rd_nm(arcn, nsz) < 0)
- return(-1);
-
- /*
- * header + file name are aligned to 2 byte boundaries, skip if needed
- */
- if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
- return(-1);
-
- /*
- * if not a link (or a file with no data), calculate pad size (for
- * padding which follows the file data), clear the link name and return
- */
- if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
- /*
- * we have a valid header (not a link)
- */
- arcn->ln_nlen = 0;
- arcn->ln_name[0] = '\0';
- arcn->pad = BCPIO_PAD(arcn->sb.st_size);
- return(com_rd(arcn));
- }
-
- if ((rd_ln_nm(arcn) < 0) ||
- (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
- return(-1);
-
- /*
- * we have a valid header (with a link)
- */
- return(com_rd(arcn));
-}
-
-/*
- * bcpio_endrd()
- * no cleanup needed here, just return size of the trailer (for append)
- * Return:
- * size of trailer header in this format
- */
-
-off_t
-bcpio_endrd(void)
-{
- return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
- (BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
-}
-
-/*
- * bcpio_wr()
- * copy the data in the ARCHD to buffer in old binary cpio format
- * There is a real chance of field overflow with this critter. So we
- * always check the conversion is ok. nobody in their right mind
- * should write an archive in this format...
- * Return
- * 0 if file has data to be written after the header, 1 if file has NO
- * data to write after the header, -1 if archive write failed
- */
-
-int
-bcpio_wr(ARCHD *arcn)
-{
- HD_BCPIO *hd;
- int nsz;
- char hdblk[sizeof(HD_BCPIO)];
- off_t t_offt;
- int t_int;
- time_t t_timet;
-
- /*
- * check and repair truncated device and inode fields in the cpio
- * header
- */
- if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
- return(-1);
-
- if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
- arcn->sb.st_rdev = 0;
- hd = (HD_BCPIO *)hdblk;
-
- switch (arcn->type) {
- case PAX_CTG:
- case PAX_REG:
- case PAX_HRG:
- /*
- * caller will copy file data to the archive. tell him how
- * much to pad.
- */
- arcn->pad = BCPIO_PAD(arcn->sb.st_size);
- hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
- hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
- hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
- hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
- t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
- t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
- if (arcn->sb.st_size != t_offt) {
- paxwarn(1,"File is too large for bcpio format %s",
- arcn->org_name);
- return(1);
- }
- break;
- case PAX_SLK:
- /*
- * no file data for the caller to process, the file data has
- * the size of the link
- */
- arcn->pad = 0L;
- hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
- hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
- hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
- hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
- t_int = (int)(SHRT_EXT(hd->h_filesize_1));
- t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
- if (arcn->ln_nlen != t_int)
- goto out;
- break;
- default:
- /*
- * no file data for the caller to process
- */
- arcn->pad = 0L;
- hd->h_filesize_1[0] = (char)0;
- hd->h_filesize_1[1] = (char)0;
- hd->h_filesize_2[0] = (char)0;
- hd->h_filesize_2[1] = (char)0;
- break;
- }
-
- /*
- * build up the rest of the fields
- */
- hd->h_magic[0] = CHR_WR_2(MAGIC);
- hd->h_magic[1] = CHR_WR_3(MAGIC);
- hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
- hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
- if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
- goto out;
- hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
- hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
- if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
- goto out;
- hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
- hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
- if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
- goto out;
- hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
- hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
- if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
- goto out;
- hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
- hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
- if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
- goto out;
- hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
- hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
- if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
- goto out;
- hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
- hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
- if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
- goto out;
- hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
- hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
- hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
- hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
- t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
- t_timet = (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
- if (arcn->sb.st_mtime != t_timet)
- goto out;
- nsz = arcn->nlen + 1;
- hd->h_namesize[0] = CHR_WR_2(nsz);
- hd->h_namesize[1] = CHR_WR_3(nsz);
- if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
- goto out;
-
- /*
- * write the header, the file name and padding as required.
- */
- if ((wr_rdbuf(hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
- (wr_rdbuf(arcn->name, nsz) < 0) ||
- (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
- paxwarn(1, "Could not write bcpio header for %s", arcn->org_name);
- return(-1);
- }
-
- /*
- * if we have file data, tell the caller we are done
- */
- if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
- (arcn->type == PAX_HRG))
- return(0);
-
- /*
- * if we are not a link, tell the caller we are done, go to next file
- */
- if (arcn->type != PAX_SLK)
- return(1);
-
- /*
- * write the link name, tell the caller we are done.
- */
- if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
- (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
- paxwarn(1,"Could not write bcpio link name for %s",arcn->org_name);
- return(-1);
- }
- return(1);
-
- out:
- /*
- * header field is out of range
- */
- paxwarn(1,"Bcpio header field is too small for file %s", arcn->org_name);
- return(1);
-}
diff --git a/pax/cpio.h b/pax/cpio.h
@@ -1,150 +0,0 @@
-/* $OpenBSD: cpio.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */
-/* $NetBSD: cpio.h,v 1.3 1995/03/21 09:07:15 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)cpio.h 8.1 (Berkeley) 5/31/93
- */
-
-/*
- * Defines common to all versions of cpio
- */
-#define TRAILER "TRAILER!!!" /* name in last archive record */
-
-/*
- * Header encoding of the different file types
- */
-#define C_ISDIR 040000 /* Directory */
-#define C_ISFIFO 010000 /* FIFO */
-#define C_ISREG 0100000 /* Regular file */
-#define C_ISBLK 060000 /* Block special file */
-#define C_ISCHR 020000 /* Character special file */
-#define C_ISCTG 0110000 /* Reserved for contiguous files */
-#define C_ISLNK 0120000 /* Reserved for symbolic links */
-#define C_ISOCK 0140000 /* Reserved for sockets */
-#define C_IFMT 0170000 /* type of file */
-
-/*
- * Data Interchange Format - Extended cpio header format - POSIX 1003.1-1990
- */
-typedef struct {
- char c_magic[6]; /* magic cookie */
- char c_dev[6]; /* device number */
- char c_ino[6]; /* inode number */
- char c_mode[6]; /* file type/access */
- char c_uid[6]; /* owners uid */
- char c_gid[6]; /* owners gid */
- char c_nlink[6]; /* # of links at archive creation */
- char c_rdev[6]; /* block/char major/minor # */
- char c_mtime[11]; /* modification time */
- char c_namesize[6]; /* length of pathname */
- char c_filesize[11]; /* length of file in bytes */
-} HD_CPIO;
-
-#define MAGIC 070707 /* transportable archive id */
-
-#ifdef _PAX_
-#define AMAGIC "070707" /* ascii equivalent string of MAGIC */
-#define CPIO_MASK 0x3ffff /* bits valid in the dev/ino fields */
- /* used for dev/inode remaps */
-#endif /* _PAX_ */
-
-/*
- * Binary cpio header structure
- *
- * CAUTION! CAUTION! CAUTION!
- * Each field really represents a 16 bit short (NOT ASCII). Described as
- * an array of chars in an attempt to improve portability!!
- */
-typedef struct {
- u_char h_magic[2];
- u_char h_dev[2];
- u_char h_ino[2];
- u_char h_mode[2];
- u_char h_uid[2];
- u_char h_gid[2];
- u_char h_nlink[2];
- u_char h_rdev[2];
- u_char h_mtime_1[2];
- u_char h_mtime_2[2];
- u_char h_namesize[2];
- u_char h_filesize_1[2];
- u_char h_filesize_2[2];
-} HD_BCPIO;
-
-#ifdef _PAX_
-/*
- * extraction and creation macros for binary cpio
- */
-#define SHRT_EXT(ch) ((((unsigned)(ch)[0])<<8) | (((unsigned)(ch)[1])&0xff))
-#define RSHRT_EXT(ch) ((((unsigned)(ch)[1])<<8) | (((unsigned)(ch)[0])&0xff))
-#define CHR_WR_0(val) ((char)(((val) >> 24) & 0xff))
-#define CHR_WR_1(val) ((char)(((val) >> 16) & 0xff))
-#define CHR_WR_2(val) ((char)(((val) >> 8) & 0xff))
-#define CHR_WR_3(val) ((char)((val) & 0xff))
-
-/*
- * binary cpio masks and pads
- */
-#define BCPIO_PAD(x) ((2 - ((x) & 1)) & 1) /* pad to next 2 byte word */
-#define BCPIO_MASK 0xffff /* mask for dev/ino fields */
-#endif /* _PAX_ */
-
-/*
- * System VR4 cpio header structure (with/without file data crc)
- */
-typedef struct {
- char c_magic[6]; /* magic cookie */
- char c_ino[8]; /* inode number */
- char c_mode[8]; /* file type/access */
- char c_uid[8]; /* owners uid */
- char c_gid[8]; /* owners gid */
- char c_nlink[8]; /* # of links at archive creation */
- char c_mtime[8]; /* modification time */
- char c_filesize[8]; /* length of file in bytes */
- char c_maj[8]; /* block/char major # */
- char c_min[8]; /* block/char minor # */
- char c_rmaj[8]; /* special file major # */
- char c_rmin[8]; /* special file minor # */
- char c_namesize[8]; /* length of pathname */
- char c_chksum[8]; /* 0 OR CRC of bytes of FILE data */
-} HD_VCPIO;
-
-#define VMAGIC 070701 /* sVr4 new portable archive id */
-#define VCMAGIC 070702 /* sVr4 new portable archive id CRC */
-#ifdef _PAX_
-#define AVMAGIC "070701" /* ascii string of above */
-#define AVCMAGIC "070702" /* ascii string of above */
-#define VCPIO_PAD(x) ((4 - ((x) & 3)) & 3) /* pad to next 4 byte word */
-#define VCPIO_MASK 0xffffffff /* mask for dev/ino fields */
-#endif /* _PAX_ */
diff --git a/pax/extern.h b/pax/extern.h
@@ -1,308 +0,0 @@
-/* $OpenBSD: extern.h,v 1.34 2010/12/02 04:08:27 tedu Exp $ */
-/* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)extern.h 8.2 (Berkeley) 4/18/94
- */
-
-/*
- * External references from each source file
- */
-
-
-/*
- * ar_io.c
- */
-extern const char *arcname;
-extern const char *gzip_program;
-extern int force_one_volume;
-int ar_open(const char *);
-void ar_close(void);
-void ar_drain(void);
-int ar_set_wr(void);
-int ar_app_ok(void);
-int ar_read(char *, int);
-int ar_write(char *, int);
-int ar_rdsync(void);
-int ar_fow(off_t, off_t *);
-int ar_rev(off_t );
-int ar_next(void);
-
-/*
- * ar_subs.c
- */
-extern u_long flcnt;
-void list(void);
-void extract(void);
-void append(void);
-void archive(void);
-void copy(void);
-
-/*
- * buf_subs.c
- */
-extern int blksz;
-extern int wrblksz;
-extern int maxflt;
-extern int rdblksz;
-extern off_t wrlimit;
-extern off_t rdcnt;
-extern off_t wrcnt;
-int wr_start(void);
-int rd_start(void);
-void cp_start(void);
-int appnd_start(off_t);
-int rd_sync(void);
-void pback(char *, int);
-int rd_skip(off_t);
-void wr_fin(void);
-int wr_rdbuf(char *, int);
-int rd_wrbuf(char *, int);
-int wr_skip(off_t);
-int wr_rdfile(ARCHD *, int, off_t *);
-int rd_wrfile(ARCHD *, int, off_t *);
-void cp_file(ARCHD *, int, int);
-int buf_fill(void);
-int buf_flush(int);
-
-/*
- * cache.c
- */
-int uidtb_start(void);
-int gidtb_start(void);
-int usrtb_start(void);
-int grptb_start(void);
-char * name_uid(uid_t, int);
-char * name_gid(gid_t, int);
-int uid_name(char *, uid_t *);
-int gid_name(char *, gid_t *);
-
-/*
- * cpio.c
- */
-int cpio_strd(void);
-int cpio_trail(ARCHD *, char *, int, int *);
-int cpio_endwr(void);
-int cpio_id(char *, int);
-int cpio_rd(ARCHD *, char *);
-off_t cpio_endrd(void);
-int cpio_stwr(void);
-int cpio_wr(ARCHD *);
-int vcpio_id(char *, int);
-int crc_id(char *, int);
-int crc_strd(void);
-int vcpio_rd(ARCHD *, char *);
-off_t vcpio_endrd(void);
-int crc_stwr(void);
-int vcpio_wr(ARCHD *);
-int bcpio_id(char *, int);
-int bcpio_rd(ARCHD *, char *);
-off_t bcpio_endrd(void);
-int bcpio_wr(ARCHD *);
-
-/*
- * file_subs.c
- */
-extern char *gnu_name_string, *gnu_link_string;
-int file_creat(ARCHD *);
-void file_close(ARCHD *, int);
-int lnk_creat(ARCHD *);
-int cross_lnk(ARCHD *);
-int chk_same(ARCHD *);
-int node_creat(ARCHD *);
-int unlnk_exist(char *, int);
-int chk_path(char *, uid_t, gid_t);
-void set_ftime(char *fnm, time_t mtime, time_t atime, int frc);
-void fset_ftime(char *fnm, int, time_t mtime, time_t atime, int frc);
-int set_ids(char *, uid_t, gid_t);
-int fset_ids(char *, int, uid_t, gid_t);
-int set_lids(char *, uid_t, gid_t);
-void set_pmode(char *, mode_t);
-void fset_pmode(char *, int, mode_t);
-int file_write(int, char *, int, int *, int *, int, char *);
-void file_flush(int, char *, int);
-void rdfile_close(ARCHD *, int *);
-int set_crc(ARCHD *, int);
-
-/*
- * ftree.c
- */
-int ftree_start(void);
-int ftree_add(char *, int);
-void ftree_sel(ARCHD *);
-void ftree_skipped_newer(ARCHD *);
-void ftree_chk(void);
-int next_file(ARCHD *);
-
-/*
- * gen_subs.c
- */
-void ls_list(ARCHD *, time_t, FILE *);
-void ls_tty(ARCHD *);
-void safe_print(const char *, FILE *);
-u_long asc_ul(char *, int, int);
-int ul_asc(u_long, char *, int, int);
-#ifndef LONG_OFF_T
-u_quad_t asc_uqd(char *, int, int);
-int uqd_asc(u_quad_t, char *, int, int);
-#endif
-size_t fieldcpy(char *, size_t, const char *, size_t);
-
-/*
- * getoldopt.c
- */
-int getoldopt(int, char **, const char *);
-
-/*
- * options.c
- */
-extern FSUB fsub[];
-extern int ford[];
-void options(int, char **);
-OPLIST * opt_next(void);
-int opt_add(const char *);
-int bad_opt(void);
-char *chdname;
-
-/*
- * pat_rep.c
- */
-int rep_add(char *);
-int pat_add(char *, char *);
-void pat_chk(void);
-int pat_sel(ARCHD *);
-int pat_match(ARCHD *);
-int mod_name(ARCHD *);
-int set_dest(ARCHD *, char *, int);
-
-/*
- * pax.c
- */
-extern int act;
-extern FSUB *frmt;
-extern int cflag;
-extern int cwdfd;
-extern int dflag;
-extern int iflag;
-extern int kflag;
-extern int lflag;
-extern int nflag;
-extern int tflag;
-extern int uflag;
-extern int vflag;
-extern int Dflag;
-extern int Hflag;
-extern int Lflag;
-extern int Nflag;
-extern int Xflag;
-extern int Yflag;
-extern int Zflag;
-extern int zeroflag;
-extern int vfpart;
-extern int patime;
-extern int pmtime;
-extern int nodirs;
-extern int pmode;
-extern int pids;
-extern int rmleadslash;
-extern int exit_val;
-extern int docrc;
-extern char *dirptr;
-extern char *ltmfrmt;
-extern char *argv0;
-extern FILE *listf;
-extern char *tempfile;
-extern char *tempbase;
-extern int havechd;
-
-int main(int, char **);
-void sig_cleanup(int);
-
-/*
- * sel_subs.c
- */
-int sel_chk(ARCHD *);
-int grp_add(char *);
-int usr_add(char *);
-int trng_add(char *);
-
-/*
- * tables.c
- */
-int lnk_start(void);
-int chk_lnk(ARCHD *);
-void purg_lnk(ARCHD *);
-void lnk_end(void);
-int ftime_start(void);
-int chk_ftime(ARCHD *);
-int name_start(void);
-int add_name(char *, int, char *);
-void sub_name(char *, int *, size_t);
-int dev_start(void);
-int add_dev(ARCHD *);
-int map_dev(ARCHD *, u_long, u_long);
-int atdir_start(void);
-void atdir_end(void);
-void add_atdir(char *, dev_t, ino_t, time_t, time_t);
-int get_atdir(dev_t, ino_t, time_t *, time_t *);
-int dir_start(void);
-void add_dir(char *, struct stat *, int);
-void proc_dir(void);
-u_int st_hash(char *, int, int);
-
-/*
- * tar.c
- */
-extern char *gnu_hack_string;
-int tar_endwr(void);
-off_t tar_endrd(void);
-int tar_trail(ARCHD *, char *, int, int *);
-int tar_id(char *, int);
-int tar_opt(void);
-int tar_rd(ARCHD *, char *);
-int tar_wr(ARCHD *);
-int ustar_strd(void);
-int ustar_stwr(void);
-int ustar_id(char *, int);
-int ustar_rd(ARCHD *, char *);
-int ustar_wr(ARCHD *);
-
-/*
- * tty_subs.c
- */
-int tty_init(void);
-void tty_prnt(const char *, ...);
-int tty_read(char *, int);
-void paxwarn(int, const char *, ...);
-void syswarn(int, int, const char *, ...);
diff --git a/pax/file_subs.c b/pax/file_subs.c
@@ -1,1077 +0,0 @@
-/* $OpenBSD: file_subs.c,v 1.32 2009/12/22 12:08:30 jasper Exp $ */
-/* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "pax.h"
-#include "options.h"
-#include "extern.h"
-
-static int
-mk_link(char *, struct stat *, char *, int);
-
-/*
- * routines that deal with file operations such as: creating, removing;
- * and setting access modes, uid/gid and times of files
- */
-
-#define FILEBITS (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
-#define SETBITS (S_ISUID | S_ISGID)
-#define ABITS (FILEBITS | SETBITS)
-
-/*
- * file_creat()
- * Create and open a file.
- * Return:
- * file descriptor or -1 for failure
- */
-
-int
-file_creat(ARCHD *arcn)
-{
- int fd = -1;
- mode_t file_mode;
- int oerrno;
-
- /*
- * Assume file doesn't exist, so just try to create it, most times this
- * works. We have to take special handling when the file does exist. To
- * detect this, we use O_EXCL. For example when trying to create a
- * file and a character device or fifo exists with the same name, we
- * can accidently open the device by mistake (or block waiting to open).
- * If we find that the open has failed, then spend the effort to
- * figure out why. This strategy was found to have better average
- * performance in common use than checking the file (and the path)
- * first with lstat.
- */
- file_mode = arcn->sb.st_mode & FILEBITS;
- if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
- file_mode)) >= 0)
- return(fd);
-
- /*
- * the file seems to exist. First we try to get rid of it (found to be
- * the second most common failure when traced). If this fails, only
- * then we go to the expense to check and create the path to the file
- */
- if (unlnk_exist(arcn->name, arcn->type) != 0)
- return(-1);
-
- for (;;) {
- /*
- * try to open it again, if this fails, check all the nodes in
- * the path and give it a final try. if chk_path() finds that
- * it cannot fix anything, we will skip the last attempt
- */
- if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC,
- file_mode)) >= 0)
- break;
- oerrno = errno;
- if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
- syswarn(1, oerrno, "Unable to create %s", arcn->name);
- return(-1);
- }
- }
- return(fd);
-}
-
-/*
- * file_close()
- * Close file descriptor to a file just created by pax. Sets modes,
- * ownership and times as required.
- * Return:
- * 0 for success, -1 for failure
- */
-
-void
-file_close(ARCHD *arcn, int fd)
-{
- int res = 0;
-
- if (fd < 0)
- return;
-
- /*
- * set owner/groups first as this may strip off mode bits we want
- * then set file permission modes. Then set file access and
- * modification times.
- */
- if (pids)
- res = fset_ids(arcn->name, fd, arcn->sb.st_uid,
- arcn->sb.st_gid);
-
- /*
- * IMPORTANT SECURITY NOTE:
- * if not preserving mode or we cannot set uid/gid, then PROHIBIT
- * set uid/gid bits
- */
- if (!pmode || res)
- arcn->sb.st_mode &= ~(SETBITS);
- if (pmode)
- fset_pmode(arcn->name, fd, arcn->sb.st_mode);
- if (patime || pmtime)
- fset_ftime(arcn->name, fd, arcn->sb.st_mtime,
- arcn->sb.st_atime, 0);
- if (close(fd) < 0)
- syswarn(0, errno, "Unable to close file descriptor on %s",
- arcn->name);
-}
-
-/*
- * lnk_creat()
- * Create a hard link to arcn->ln_name from arcn->name. arcn->ln_name
- * must exist;
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-lnk_creat(ARCHD *arcn)
-{
- struct stat sb;
-
- /*
- * we may be running as root, so we have to be sure that link target
- * is not a directory, so we lstat and check
- */
- if (lstat(arcn->ln_name, &sb) < 0) {
- syswarn(1,errno,"Unable to link to %s from %s", arcn->ln_name,
- arcn->name);
- return(-1);
- }
-
- if (S_ISDIR(sb.st_mode)) {
- paxwarn(1, "A hard link to the directory %s is not allowed",
- arcn->ln_name);
- return(-1);
- }
-
- return(mk_link(arcn->ln_name, &sb, arcn->name, 0));
-}
-
-/*
- * cross_lnk()
- * Create a hard link to arcn->org_name from arcn->name. Only used in copy
- * with the -l flag. No warning or error if this does not succeed (we will
- * then just create the file)
- * Return:
- * 1 if copy() should try to create this file node
- * 0 if cross_lnk() ok, -1 for fatal flaw (like linking to self).
- */
-
-int
-cross_lnk(ARCHD *arcn)
-{
- /*
- * try to make a link to original file (-l flag in copy mode). make
- * sure we do not try to link to directories in case we are running as
- * root (and it might succeed).
- */
- if (arcn->type == PAX_DIR)
- return(1);
- return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1));
-}
-
-/*
- * chk_same()
- * In copy mode if we are not trying to make hard links between the src
- * and destinations, make sure we are not going to overwrite ourselves by
- * accident. This slows things down a little, but we have to protect all
- * those people who make typing errors.
- * Return:
- * 1 the target does not exist, go ahead and copy
- * 0 skip it file exists (-k) or may be the same as source file
- */
-
-int
-chk_same(ARCHD *arcn)
-{
- struct stat sb;
-
- /*
- * if file does not exist, return. if file exists and -k, skip it
- * quietly
- */
- if (lstat(arcn->name, &sb) < 0)
- return(1);
- if (kflag)
- return(0);
-
- /*
- * better make sure the user does not have src == dest by mistake
- */
- if ((arcn->sb.st_dev == sb.st_dev) && (arcn->sb.st_ino == sb.st_ino)) {
- paxwarn(1, "Unable to copy %s, file would overwrite itself",
- arcn->name);
- return(0);
- }
- return(1);
-}
-
-/*
- * mk_link()
- * try to make a hard link between two files. if ign set, we do not
- * complain.
- * Return:
- * 0 if successful (or we are done with this file but no error, such as
- * finding the from file exists and the user has set -k).
- * 1 when ign was set to indicates we could not make the link but we
- * should try to copy/extract the file as that might work (and is an
- * allowed option). -1 an error occurred.
- */
-
-static int
-mk_link(char *to, struct stat *to_sb, char *from, int ign)
-{
- struct stat sb;
- int oerrno;
-
- /*
- * if from file exists, it has to be unlinked to make the link. If the
- * file exists and -k is set, skip it quietly
- */
- if (lstat(from, &sb) == 0) {
- if (kflag)
- return(0);
-
- /*
- * make sure it is not the same file, protect the user
- */
- if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) {
- paxwarn(1, "Unable to link file %s to itself", to);
- return(-1);
- }
-
- /*
- * try to get rid of the file, based on the type
- */
- if (S_ISDIR(sb.st_mode)) {
- if (rmdir(from) < 0) {
- syswarn(1, errno, "Unable to remove %s", from);
- return(-1);
- }
- } else if (unlink(from) < 0) {
- if (!ign) {
- syswarn(1, errno, "Unable to remove %s", from);
- return(-1);
- }
- return(1);
- }
- }
-
- /*
- * from file is gone (or did not exist), try to make the hard link.
- * if it fails, check the path and try it again (if chk_path() says to
- * try again)
- */
- for (;;) {
- if (link(to, from) == 0)
- break;
- oerrno = errno;
- if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0)
- continue;
- if (!ign) {
- syswarn(1, oerrno, "Could not link to %s from %s", to,
- from);
- return(-1);
- }
- return(1);
- }
-
- /*
- * all right the link was made
- */
- return(0);
-}
-
-/*
- * node_creat()
- * create an entry in the file system (other than a file or hard link).
- * If successful, sets uid/gid modes and times as required.
- * Return:
- * 0 if ok, -1 otherwise
- */
-
-int
-node_creat(ARCHD *arcn)
-{
- int res;
- int ign = 0;
- int oerrno;
- int pass = 0;
- mode_t file_mode;
- struct stat sb;
- char target[MAXPATHLEN];
- char *nm = arcn->name;
- int len;
-
- /*
- * create node based on type, if that fails try to unlink the node and
- * try again. finally check the path and try again. As noted in the
- * file and link creation routines, this method seems to exhibit the
- * best performance in general use workloads.
- */
- file_mode = arcn->sb.st_mode & FILEBITS;
-
- for (;;) {
- switch (arcn->type) {
- case PAX_DIR:
- /*
- * If -h (or -L) was given in tar-mode, follow the
- * potential symlink chain before trying to create the
- * directory.
- */
- if (strcmp(NM_TAR, argv0) == 0 && Lflag) {
- while (lstat(nm, &sb) == 0 &&
- S_ISLNK(sb.st_mode)) {
- len = readlink(nm, target,
- sizeof target - 1);
- if (len == -1) {
- syswarn(0, errno,
- "cannot follow symlink %s in chain for %s",
- nm, arcn->name);
- res = -1;
- goto badlink;
- }
- target[len] = '\0';
- nm = target;
- }
- }
- res = mkdir(nm, file_mode);
-
-badlink:
- if (ign)
- res = 0;
- break;
- case PAX_CHR:
- file_mode |= S_IFCHR;
- res = mknod(nm, file_mode, arcn->sb.st_rdev);
- break;
- case PAX_BLK:
- file_mode |= S_IFBLK;
- res = mknod(nm, file_mode, arcn->sb.st_rdev);
- break;
- case PAX_FIF:
- res = mkfifo(nm, file_mode);
- break;
- case PAX_SCK:
- /*
- * Skip sockets, operation has no meaning under BSD
- */
- paxwarn(0,
- "%s skipped. Sockets cannot be copied or extracted",
- nm);
- return(-1);
- case PAX_SLK:
- res = symlink(arcn->ln_name, nm);
- break;
- case PAX_CTG:
- case PAX_HLK:
- case PAX_HRG:
- case PAX_REG:
- default:
- /*
- * we should never get here
- */
- paxwarn(0, "%s has an unknown file type, skipping",
- nm);
- return(-1);
- }
-
- /*
- * if we were able to create the node break out of the loop,
- * otherwise try to unlink the node and try again. if that
- * fails check the full path and try a final time.
- */
- if (res == 0)
- break;
-
- /*
- * we failed to make the node
- */
- oerrno = errno;
- if ((ign = unlnk_exist(nm, arcn->type)) < 0)
- return(-1);
-
- if (++pass <= 1)
- continue;
-
- if (nodirs || chk_path(nm,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
- syswarn(1, oerrno, "Could not create: %s", nm);
- return(-1);
- }
- }
-
- /*
- * we were able to create the node. set uid/gid, modes and times
- */
- if (pids)
- res = ((arcn->type == PAX_SLK) ?
- set_lids(nm, arcn->sb.st_uid, arcn->sb.st_gid) :
- set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid));
- else
- res = 0;
-
- /*
- * symlinks are done now.
- */
- if (arcn->type == PAX_SLK)
- return(0);
-
- /*
- * IMPORTANT SECURITY NOTE:
- * if not preserving mode or we cannot set uid/gid, then PROHIBIT any
- * set uid/gid bits
- */
- if (!pmode || res)
- arcn->sb.st_mode &= ~(SETBITS);
- if (pmode)
- set_pmode(nm, arcn->sb.st_mode);
-
- if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) {
- /*
- * Dirs must be processed again at end of extract to set times
- * and modes to agree with those stored in the archive. However
- * to allow extract to continue, we may have to also set owner
- * rights. This allows nodes in the archive that are children
- * of this directory to be extracted without failure. Both time
- * and modes will be fixed after the entire archive is read and
- * before pax exits.
- */
- if (access(nm, R_OK | W_OK | X_OK) < 0) {
- if (lstat(nm, &sb) < 0) {
- syswarn(0, errno,"Could not access %s (stat)",
- arcn->name);
- set_pmode(nm,file_mode | S_IRWXU);
- } else {
- /*
- * We have to add rights to the dir, so we make
- * sure to restore the mode. The mode must be
- * restored AS CREATED and not as stored if
- * pmode is not set.
- */
- set_pmode(nm,
- ((sb.st_mode & FILEBITS) | S_IRWXU));
- if (!pmode)
- arcn->sb.st_mode = sb.st_mode;
- }
-
- /*
- * we have to force the mode to what was set here,
- * since we changed it from the default as created.
- */
- add_dir(nm, &(arcn->sb), 1);
- } else if (pmode || patime || pmtime)
- add_dir(nm, &(arcn->sb), 0);
- }
-
- if (patime || pmtime)
- set_ftime(nm, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
- return(0);
-}
-
-/*
- * unlnk_exist()
- * Remove node from file system with the specified name. We pass the type
- * of the node that is going to replace it. When we try to create a
- * directory and find that it already exists, we allow processing to
- * continue as proper modes etc will always be set for it later on.
- * Return:
- * 0 is ok to proceed, no file with the specified name exists
- * -1 we were unable to remove the node, or we should not remove it (-k)
- * 1 we found a directory and we were going to create a directory.
- */
-
-int
-unlnk_exist(char *name, int type)
-{
- struct stat sb;
-
- /*
- * the file does not exist, or -k we are done
- */
- if (lstat(name, &sb) < 0)
- return(0);
- if (kflag)
- return(-1);
-
- if (S_ISDIR(sb.st_mode)) {
- /*
- * try to remove a directory, if it fails and we were going to
- * create a directory anyway, tell the caller (return a 1)
- */
- if (rmdir(name) < 0) {
- if (type == PAX_DIR)
- return(1);
- syswarn(1,errno,"Unable to remove directory %s", name);
- return(-1);
- }
- return(0);
- }
-
- /*
- * try to get rid of all non-directory type nodes
- */
- if (unlink(name) < 0) {
- syswarn(1, errno, "Could not unlink %s", name);
- return(-1);
- }
- return(0);
-}
-
-/*
- * chk_path()
- * We were trying to create some kind of node in the file system and it
- * failed. chk_path() makes sure the path up to the node exists and is
- * writeable. When we have to create a directory that is missing along the
- * path somewhere, the directory we create will be set to the same
- * uid/gid as the file has (when uid and gid are being preserved).
- * NOTE: this routine is a real performance loss. It is only used as a
- * last resort when trying to create entries in the file system.
- * Return:
- * -1 when it could find nothing it is allowed to fix.
- * 0 otherwise
- */
-
-int
-chk_path(char *name, uid_t st_uid, gid_t st_gid)
-{
- char *spt = name;
- struct stat sb;
- int retval = -1;
-
- /*
- * watch out for paths with nodes stored directly in / (e.g. /bozo)
- */
- if (*spt == '/')
- ++spt;
-
- for (;;) {
- /*
- * work forward from the first / and check each part of the path
- */
- spt = strchr(spt, '/');
- if (spt == NULL)
- break;
- *spt = '\0';
-
- /*
- * if it exists we assume it is a directory, it is not within
- * the spec (at least it seems to read that way) to alter the
- * file system for nodes NOT EXPLICITLY stored on the archive.
- * If that assumption is changed, you would test the node here
- * and figure out how to get rid of it (probably like some
- * recursive unlink()) or fix up the directory permissions if
- * required (do an access()).
- */
- if (lstat(name, &sb) == 0) {
- *(spt++) = '/';
- continue;
- }
-
- /*
- * the path fails at this point, see if we can create the
- * needed directory and continue on
- */
- if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
- *spt = '/';
- retval = -1;
- break;
- }
-
- /*
- * we were able to create the directory. We will tell the
- * caller that we found something to fix, and it is ok to try
- * and create the node again.
- */
- retval = 0;
- if (pids)
- (void)set_ids(name, st_uid, st_gid);
-
- /*
- * make sure the user doesn't have some strange umask that
- * causes this newly created directory to be unusable. We fix
- * the modes and restore them back to the creation default at
- * the end of pax
- */
- if ((access(name, R_OK | W_OK | X_OK) < 0) &&
- (lstat(name, &sb) == 0)) {
- set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));
- add_dir(name, &sb, 1);
- }
- *(spt++) = '/';
- continue;
- }
- return(retval);
-}
-
-/*
- * set_ftime()
- * Set the access time and modification time for a named file. If frc
- * is non-zero we force these times to be set even if the user did not
- * request access and/or modification time preservation (this is also
- * used by -t to reset access times).
- * When ign is zero, only those times the user has asked for are set, the
- * other ones are left alone. We do not assume the un-documented feature
- * of many utimes() implementations that consider a 0 time value as a do
- * not set request.
- */
-
-void
-set_ftime(char *fnm, time_t mtime, time_t atime, int frc)
-{
- static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}};
- struct stat sb;
-
- tv[0].tv_sec = (long)atime;
- tv[1].tv_sec = (long)mtime;
- if (!frc && (!patime || !pmtime)) {
- /*
- * if we are not forcing, only set those times the user wants
- * set. We get the current values of the times if we need them.
- */
- if (lstat(fnm, &sb) == 0) {
- if (!patime)
- tv[0].tv_sec = (long)sb.st_atime;
- if (!pmtime)
- tv[1].tv_sec = (long)sb.st_mtime;
- } else
- syswarn(0,errno,"Unable to obtain file stats %s", fnm);
- }
-
- /*
- * set the times
- */
- if (utimes(fnm, tv) < 0)
- syswarn(1, errno, "Access/modification time set failed on: %s",
- fnm);
- return;
-}
-
-void
-fset_ftime(char *fnm, int fd, time_t mtime, time_t atime, int frc)
-{
- static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}};
- struct stat sb;
-
- tv[0].tv_sec = (long)atime;
- tv[1].tv_sec = (long)mtime;
- if (!frc && (!patime || !pmtime)) {
- /*
- * if we are not forcing, only set those times the user wants
- * set. We get the current values of the times if we need them.
- */
- if (fstat(fd, &sb) == 0) {
- if (!patime)
- tv[0].tv_sec = (long)sb.st_atime;
- if (!pmtime)
- tv[1].tv_sec = (long)sb.st_mtime;
- } else
- syswarn(0,errno,"Unable to obtain file stats %s", fnm);
- }
- /*
- * set the times
- */
- if (futimes(fd, tv) < 0)
- syswarn(1, errno, "Access/modification time set failed on: %s",
- fnm);
- return;
-}
-
-/*
- * set_ids()
- * set the uid and gid of a file system node
- * Return:
- * 0 when set, -1 on failure
- */
-
-int
-set_ids(char *fnm, uid_t uid, gid_t gid)
-{
- if (chown(fnm, uid, gid) < 0) {
- /*
- * ignore EPERM unless in verbose mode or being run by root.
- * if running as pax, POSIX requires a warning.
- */
- if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
- geteuid() == 0)
- syswarn(1, errno, "Unable to set file uid/gid of %s",
- fnm);
- return(-1);
- }
- return(0);
-}
-
-int
-fset_ids(char *fnm, int fd, uid_t uid, gid_t gid)
-{
- if (fchown(fd, uid, gid) < 0) {
- /*
- * ignore EPERM unless in verbose mode or being run by root.
- * if running as pax, POSIX requires a warning.
- */
- if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
- geteuid() == 0)
- syswarn(1, errno, "Unable to set file uid/gid of %s",
- fnm);
- return(-1);
- }
- return(0);
-}
-
-/*
- * set_lids()
- * set the uid and gid of a file system node
- * Return:
- * 0 when set, -1 on failure
- */
-
-int
-set_lids(char *fnm, uid_t uid, gid_t gid)
-{
- if (lchown(fnm, uid, gid) < 0) {
- /*
- * ignore EPERM unless in verbose mode or being run by root.
- * if running as pax, POSIX requires a warning.
- */
- if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
- geteuid() == 0)
- syswarn(1, errno, "Unable to set file uid/gid of %s",
- fnm);
- return(-1);
- }
- return(0);
-}
-
-/*
- * set_pmode()
- * Set file access mode
- */
-
-void
-set_pmode(char *fnm, mode_t mode)
-{
- mode &= ABITS;
- if (chmod(fnm, mode) < 0)
- syswarn(1, errno, "Could not set permissions on %s", fnm);
- return;
-}
-
-void
-fset_pmode(char *fnm, int fd, mode_t mode)
-{
- mode &= ABITS;
- if (fchmod(fd, mode) < 0)
- syswarn(1, errno, "Could not set permissions on %s", fnm);
- return;
-}
-
-/*
- * file_write()
- * Write/copy a file (during copy or archive extract). This routine knows
- * how to copy files with lseek holes in it. (Which are read as file
- * blocks containing all 0's but do not have any file blocks associated
- * with the data). Typical examples of these are files created by dbm
- * variants (.pag files). While the file size of these files are huge, the
- * actual storage is quite small (the files are sparse). The problem is
- * the holes read as all zeros so are probably stored on the archive that
- * way (there is no way to determine if the file block is really a hole,
- * we only know that a file block of all zero's can be a hole).
- * At this writing, no major archive format knows how to archive files
- * with holes. However, on extraction (or during copy, -rw) we have to
- * deal with these files. Without detecting the holes, the files can
- * consume a lot of file space if just written to disk. This replacement
- * for write when passed the basic allocation size of a file system block,
- * uses lseek whenever it detects the input data is all 0 within that
- * file block. In more detail, the strategy is as follows:
- * While the input is all zero keep doing an lseek. Keep track of when we
- * pass over file block boundaries. Only write when we hit a non zero
- * input. once we have written a file block, we continue to write it to
- * the end (we stop looking at the input). When we reach the start of the
- * next file block, start checking for zero blocks again. Working on file
- * block boundaries significantly reduces the overhead when copying files
- * that are NOT very sparse. This overhead (when compared to a write) is
- * almost below the measurement resolution on many systems. Without it,
- * files with holes cannot be safely copied. It does has a side effect as
- * it can put holes into files that did not have them before, but that is
- * not a problem since the file contents are unchanged (in fact it saves
- * file space). (Except on paging files for diskless clients. But since we
- * cannot determine one of those file from here, we ignore them). If this
- * ever ends up on a system where CTG files are supported and the holes
- * are not desired, just do a conditional test in those routines that
- * call file_write() and have it call write() instead. BEFORE CLOSING THE
- * FILE, make sure to call file_flush() when the last write finishes with
- * an empty block. A lot of file systems will not create an lseek hole at
- * the end. In this case we drop a single 0 at the end to force the
- * trailing 0's in the file.
- * ---Parameters---
- * rem: how many bytes left in this file system block
- * isempt: have we written to the file block yet (is it empty)
- * sz: basic file block allocation size
- * cnt: number of bytes on this write
- * str: buffer to write
- * Return:
- * number of bytes written, -1 on write (or lseek) error.
- */
-
-int
-file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz,
- char *name)
-{
- char *pt;
- char *end;
- int wcnt;
- char *st = str;
- char **strp;
-
- /*
- * while we have data to process
- */
- while (cnt) {
- if (!*rem) {
- /*
- * We are now at the start of file system block again
- * (or what we think one is...). start looking for
- * empty blocks again
- */
- *isempt = 1;
- *rem = sz;
- }
-
- /*
- * only examine up to the end of the current file block or
- * remaining characters to write, whatever is smaller
- */
- wcnt = MIN(cnt, *rem);
- cnt -= wcnt;
- *rem -= wcnt;
- if (*isempt) {
- /*
- * have not written to this block yet, so we keep
- * looking for zero's
- */
- pt = st;
- end = st + wcnt;
-
- /*
- * look for a zero filled buffer
- */
- while ((pt < end) && (*pt == '\0'))
- ++pt;
-
- if (pt == end) {
- /*
- * skip, buf is empty so far
- */
- if (fd > -1 &&
- lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
- syswarn(1,errno,"File seek on %s",
- name);
- return(-1);
- }
- st = pt;
- continue;
- }
- /*
- * drat, the buf is not zero filled
- */
- *isempt = 0;
- }
-
- /*
- * have non-zero data in this file system block, have to write
- */
- switch (fd) {
- case -1:
- strp = &gnu_name_string;
- break;
- case -2:
- strp = &gnu_link_string;
- break;
- default:
- strp = NULL;
- break;
- }
- if (strp) {
- if (*strp)
- err(1, "WARNING! Major Internal Error! GNU hack Failing!");
- *strp = malloc(wcnt + 1);
- if (*strp == NULL) {
- paxwarn(1, "Out of memory");
- return(-1);
- }
- memcpy(*strp, st, wcnt);
- (*strp)[wcnt] = '\0';
- break;
- } else if (write(fd, st, wcnt) != wcnt) {
- syswarn(1, errno, "Failed write to file %s", name);
- return(-1);
- }
- st += wcnt;
- }
- return(st - str);
-}
-
-/*
- * file_flush()
- * when the last file block in a file is zero, many file systems will not
- * let us create a hole at the end. To get the last block with zeros, we
- * write the last BYTE with a zero (back up one byte and write a zero).
- */
-
-void
-file_flush(int fd, char *fname, int isempt)
-{
- static char blnk[] = "\0";
-
- /*
- * silly test, but make sure we are only called when the last block is
- * filled with all zeros.
- */
- if (!isempt)
- return;
-
- /*
- * move back one byte and write a zero
- */
- if (lseek(fd, (off_t)-1, SEEK_CUR) < 0) {
- syswarn(1, errno, "Failed seek on file %s", fname);
- return;
- }
-
- if (write(fd, blnk, 1) < 0)
- syswarn(1, errno, "Failed write to file %s", fname);
- return;
-}
-
-/*
- * rdfile_close()
- * close a file we have been reading (to copy or archive). If we have to
- * reset access time (tflag) do so (the times are stored in arcn).
- */
-
-void
-rdfile_close(ARCHD *arcn, int *fd)
-{
- /*
- * make sure the file is open
- */
- if (*fd < 0)
- return;
-
- (void)close(*fd);
- *fd = -1;
- if (!tflag)
- return;
-
- /*
- * user wants last access time reset
- */
- set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1);
- return;
-}
-
-/*
- * set_crc()
- * read a file to calculate its crc. This is a real drag. Archive formats
- * that have this, end up reading the file twice (we have to write the
- * header WITH the crc before writing the file contents. Oh well...
- * Return:
- * 0 if was able to calculate the crc, -1 otherwise
- */
-
-int
-set_crc(ARCHD *arcn, int fd)
-{
- int i;
- int res;
- off_t cpcnt = 0L;
- u_long size;
- u_int32_t crc = 0;
- char tbuf[FILEBLK];
- struct stat sb;
-
- if (fd < 0) {
- /*
- * hmm, no fd, should never happen. well no crc then.
- */
- arcn->crc = 0L;
- return(0);
- }
-
- if ((size = (u_long)arcn->sb.st_blksize) > (u_long)sizeof(tbuf))
- size = (u_long)sizeof(tbuf);
-
- /*
- * read all the bytes we think that there are in the file. If the user
- * is trying to archive an active file, forget this file.
- */
- for (;;) {
- if ((res = read(fd, tbuf, size)) <= 0)
- break;
- cpcnt += res;
- for (i = 0; i < res; ++i)
- crc += (tbuf[i] & 0xff);
- }
-
- /*
- * safety check. we want to avoid archiving files that are active as
- * they can create inconsistent archive copies.
- */
- if (cpcnt != arcn->sb.st_size)
- paxwarn(1, "File changed size %s", arcn->org_name);
- else if (fstat(fd, &sb) < 0)
- syswarn(1, errno, "Failed stat on %s", arcn->org_name);
- else if (arcn->sb.st_mtime != sb.st_mtime)
- paxwarn(1, "File %s was modified during read", arcn->org_name);
- else if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
- syswarn(1, errno, "File rewind failed on: %s", arcn->org_name);
- else {
- arcn->crc = crc;
- return(0);
- }
- return(-1);
-}
diff --git a/pax/ftree.c b/pax/ftree.c
@@ -1,557 +0,0 @@
-/* $OpenBSD: ftree.c,v 1.29 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fts.h>
-#include "pax.h"
-#include "ftree.h"
-#include "extern.h"
-
-/*
- * routines to interface with the fts library function.
- *
- * file args supplied to pax are stored on a single linked list (of type FTREE)
- * and given to fts to be processed one at a time. pax "selects" files from
- * the expansion of each arg into the corresponding file tree (if the arg is a
- * directory, otherwise the node itself is just passed to pax). The selection
- * is modified by the -n and -u flags. The user is informed when a specific
- * file arg does not generate any selected files. -n keeps expanding the file
- * tree arg until one of its files is selected, then skips to the next file
- * arg. when the user does not supply the file trees as command line args to
- * pax, they are read from stdin
- */
-
-static FTS *ftsp = NULL; /* current FTS handle */
-static int ftsopts; /* options to be used on fts_open */
-static char *farray[2]; /* array for passing each arg to fts */
-static FTREE *fthead = NULL; /* head of linked list of file args */
-static FTREE *fttail = NULL; /* tail of linked list of file args */
-static FTREE *ftcur = NULL; /* current file arg being processed */
-static FTSENT *ftent = NULL; /* current file tree entry */
-static int ftree_skip; /* when set skip to next file arg */
-
-static int ftree_arg(void);
-static char *getpathname(char *, int);
-
-/*
- * ftree_start()
- * initialize the options passed to fts_open() during this run of pax
- * options are based on the selection of pax options by the user
- * fts_start() also calls fts_arg() to open the first valid file arg. We
- * also attempt to reset directory access times when -t (tflag) is set.
- * Return:
- * 0 if there is at least one valid file arg to process, -1 otherwise
- */
-
-int
-ftree_start(void)
-{
- /*
- * set up the operation mode of fts, open the first file arg. We must
- * use FTS_NOCHDIR, as the user may have to open multiple archives and
- * if fts did a chdir off into the boondocks, we may create an archive
- * volume in an place where the user did not expect to.
- */
- ftsopts = FTS_NOCHDIR;
-
- /*
- * optional user flags that effect file traversal
- * -H command line symlink follow only (half follow)
- * -L follow sylinks (logical)
- * -P do not follow sylinks (physical). This is the default.
- * -X do not cross over mount points
- * -t preserve access times on files read.
- * -n select only the first member of a file tree when a match is found
- * -d do not extract subtrees rooted at a directory arg.
- */
- if (Lflag)
- ftsopts |= FTS_LOGICAL;
- else
- ftsopts |= FTS_PHYSICAL;
- if (Hflag)
- ftsopts |= FTS_COMFOLLOW;
- if (Xflag)
- ftsopts |= FTS_XDEV;
-
- if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) {
- paxwarn(1, "Unable to allocate memory for file name buffer");
- return(-1);
- }
-
- if (ftree_arg() < 0)
- return(-1);
- if (tflag && (atdir_start() < 0))
- return(-1);
- return(0);
-}
-
-/*
- * ftree_add()
- * add the arg to the linked list of files to process. Each will be
- * processed by fts one at a time
- * Return:
- * 0 if added to the linked list, -1 if failed
- */
-
-int
-ftree_add(char *str, int chflg)
-{
- FTREE *ft;
- int len;
-
- /*
- * simple check for bad args
- */
- if ((str == NULL) || (*str == '\0')) {
- paxwarn(0, "Invalid file name argument");
- return(-1);
- }
-
- /*
- * allocate FTREE node and add to the end of the linked list (args are
- * processed in the same order they were passed to pax). Get rid of any
- * trailing / the user may pass us. (watch out for / by itself).
- */
- if ((ft = (FTREE *)malloc(sizeof(FTREE))) == NULL) {
- paxwarn(0, "Unable to allocate memory for filename");
- return(-1);
- }
-
- if (((len = strlen(str) - 1) > 0) && (str[len] == '/'))
- str[len] = '\0';
- ft->fname = str;
- ft->refcnt = 0;
- ft->newercnt = 0;
- ft->chflg = chflg;
- ft->fow = NULL;
- if (fthead == NULL) {
- fttail = fthead = ft;
- return(0);
- }
- fttail->fow = ft;
- fttail = ft;
- return(0);
-}
-
-/*
- * ftree_sel()
- * this entry has been selected by pax. bump up reference count and handle
- * -n and -d processing.
- */
-
-void
-ftree_sel(ARCHD *arcn)
-{
- /*
- * set reference bit for this pattern. This linked list is only used
- * when file trees are supplied pax as args. The list is not used when
- * the trees are read from stdin.
- */
- if (ftcur != NULL)
- ftcur->refcnt = 1;
-
- /*
- * if -n we are done with this arg, force a skip to the next arg when
- * pax asks for the next file in next_file().
- * if -d we tell fts only to match the directory (if the arg is a dir)
- * and not the entire file tree rooted at that point.
- */
- if (nflag)
- ftree_skip = 1;
-
- if (!dflag || (arcn->type != PAX_DIR))
- return;
-
- if (ftent != NULL)
- (void)fts_set(ftsp, ftent, FTS_SKIP);
-}
-
-/*
- * ftree_skipped_newer()
- * file has been skipped because a newer file exists and -u/-D given
- */
-
-void
-ftree_skipped_newer(ARCHD *arcn)
-{
- /* skipped due to -u/-D, mark accordingly */
- if (ftcur != NULL)
- ftcur->newercnt = 1;
-}
-
-/*
- * ftree_chk()
- * called at end on pax execution. Prints all those file args that did not
- * have a selected member (reference count still 0)
- */
-
-void
-ftree_chk(void)
-{
- FTREE *ft;
- int wban = 0;
-
- /*
- * make sure all dir access times were reset.
- */
- if (tflag)
- atdir_end();
-
- /*
- * walk down list and check reference count. Print out those members
- * that never had a match
- */
- for (ft = fthead; ft != NULL; ft = ft->fow) {
- if ((ft->refcnt > 0) || ft->newercnt > 0 || ft->chflg)
- continue;
- if (wban == 0) {
- paxwarn(1,"WARNING! These file names were not selected:");
- ++wban;
- }
- (void)fprintf(stderr, "%s\n", ft->fname);
- }
-}
-
-/*
- * ftree_arg()
- * Get the next file arg for fts to process. Can be from either the linked
- * list or read from stdin when the user did not them as args to pax. Each
- * arg is processed until the first successful fts_open().
- * Return:
- * 0 when the next arg is ready to go, -1 if out of file args (or EOF on
- * stdin).
- */
-
-static int
-ftree_arg(void)
-{
-
- /*
- * close off the current file tree
- */
- if (ftsp != NULL) {
- (void)fts_close(ftsp);
- ftsp = NULL;
- }
-
- /*
- * keep looping until we get a valid file tree to process. Stop when we
- * reach the end of the list (or get an eof on stdin)
- */
- for (;;) {
- if (fthead == NULL) {
- /*
- * the user didn't supply any args, get the file trees
- * to process from stdin;
- */
- if (getpathname(farray[0], PAXPATHLEN+1) == NULL)
- return(-1);
- } else {
- /*
- * the user supplied the file args as arguments to pax
- */
- if (ftcur == NULL)
- ftcur = fthead;
- else if ((ftcur = ftcur->fow) == NULL)
- return(-1);
- if (ftcur->chflg) {
- /* First fchdir() back... */
- if (fchdir(cwdfd) < 0) {
- syswarn(1, errno,
- "Can't fchdir to starting directory");
- return(-1);
- }
- if (chdir(ftcur->fname) < 0) {
- syswarn(1, errno, "Can't chdir to %s",
- ftcur->fname);
- return(-1);
- }
- continue;
- } else
- farray[0] = ftcur->fname;
- }
-
- /*
- * watch it, fts wants the file arg stored in a array of char
- * ptrs, with the last one a null. we use a two element array
- * and set farray[0] to point at the buffer with the file name
- * in it. We cannot pass all the file args to fts at one shot
- * as we need to keep a handle on which file arg generates what
- * files (the -n and -d flags need this). If the open is
- * successful, return a 0.
- */
- if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL)
- break;
- }
- return(0);
-}
-
-/*
- * next_file()
- * supplies the next file to process in the supplied archd structure.
- * Return:
- * 0 when contents of arcn have been set with the next file, -1 when done.
- */
-
-int
-next_file(ARCHD *arcn)
-{
- int cnt;
- time_t atime;
- time_t mtime;
-
- /*
- * ftree_sel() might have set the ftree_skip flag if the user has the
- * -n option and a file was selected from this file arg tree. (-n says
- * only one member is matched for each pattern) ftree_skip being 1
- * forces us to go to the next arg now.
- */
- if (ftree_skip) {
- /*
- * clear and go to next arg
- */
- ftree_skip = 0;
- if (ftree_arg() < 0)
- return(-1);
- }
-
- /*
- * loop until we get a valid file to process
- */
- for (;;) {
- if ((ftent = fts_read(ftsp)) == NULL) {
- if (errno)
- syswarn(1, errno, "next_file");
- /*
- * out of files in this tree, go to next arg, if none
- * we are done
- */
- if (ftree_arg() < 0)
- return(-1);
- continue;
- }
-
- /*
- * handle each type of fts_read() flag
- */
- switch (ftent->fts_info) {
- case FTS_D:
- case FTS_DEFAULT:
- case FTS_F:
- case FTS_SL:
- case FTS_SLNONE:
- /*
- * these are all ok
- */
- break;
- case FTS_DP:
- /*
- * already saw this directory. If the user wants file
- * access times reset, we use this to restore the
- * access time for this directory since this is the
- * last time we will see it in this file subtree
- * remember to force the time (this is -t on a read
- * directory, not a created directory).
- */
- if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
- ftent->fts_statp->st_ino, &mtime, &atime) < 0))
- continue;
- set_ftime(ftent->fts_path, mtime, atime, 1);
- continue;
- case FTS_DC:
- /*
- * fts claims a file system cycle
- */
- paxwarn(1,"File system cycle found at %s",ftent->fts_path);
- continue;
- case FTS_DNR:
- syswarn(1, ftent->fts_errno,
- "Unable to read directory %s", ftent->fts_path);
- continue;
- case FTS_ERR:
- syswarn(1, ftent->fts_errno,
- "File system traversal error");
- continue;
- case FTS_NS:
- case FTS_NSOK:
- syswarn(1, ftent->fts_errno,
- "Unable to access %s", ftent->fts_path);
- continue;
- }
-
- /*
- * ok got a file tree node to process. copy info into arcn
- * structure (initialize as required)
- */
- arcn->skip = 0;
- arcn->pad = 0;
- arcn->ln_nlen = 0;
- arcn->ln_name[0] = '\0';
- memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb));
-
- /*
- * file type based set up and copy into the arcn struct
- * SIDE NOTE:
- * we try to reset the access time on all files and directories
- * we may read when the -t flag is specified. files are reset
- * when we close them after copying. we reset the directories
- * when we are done with their file tree (we also clean up at
- * end in case we cut short a file tree traversal). However
- * there is no way to reset access times on symlinks.
- */
- switch (S_IFMT & arcn->sb.st_mode) {
- case S_IFDIR:
- arcn->type = PAX_DIR;
- if (!tflag)
- break;
- add_atdir(ftent->fts_path, arcn->sb.st_dev,
- arcn->sb.st_ino, arcn->sb.st_mtime,
- arcn->sb.st_atime);
- break;
- case S_IFCHR:
- arcn->type = PAX_CHR;
- break;
- case S_IFBLK:
- arcn->type = PAX_BLK;
- break;
- case S_IFREG:
- /*
- * only regular files with have data to store on the
- * archive. all others will store a zero length skip.
- * the skip field is used by pax for actual data it has
- * to read (or skip over).
- */
- arcn->type = PAX_REG;
- arcn->skip = arcn->sb.st_size;
- break;
- case S_IFLNK:
- arcn->type = PAX_SLK;
- /*
- * have to read the symlink path from the file
- */
- if ((cnt = readlink(ftent->fts_path, arcn->ln_name,
- PAXPATHLEN)) < 0) {
- syswarn(1, errno, "Unable to read symlink %s",
- ftent->fts_path);
- continue;
- }
- /*
- * set link name length, watch out readlink does not
- * always NUL terminate the link path
- */
- arcn->ln_name[cnt] = '\0';
- arcn->ln_nlen = cnt;
- break;
- case S_IFSOCK:
- /*
- * under BSD storing a socket is senseless but we will
- * let the format specific write function make the
- * decision of what to do with it.
- */
- arcn->type = PAX_SCK;
- break;
- case S_IFIFO:
- arcn->type = PAX_FIF;
- break;
- }
- break;
- }
-
- /*
- * copy file name, set file name length
- */
- arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
- if (arcn->nlen >= sizeof(arcn->name))
- arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
- arcn->org_name = ftent->fts_path;
- return(0);
-}
-
-/*
- * getpathname()
- * Reads a pathname from stdin, handling NUL- or newline-termination.
- * Return:
- * NULL at end of file, otherwise the NUL-terminated buffer.
- */
-
-static char *
-getpathname(char *buf, int buflen)
-{
- char *bp, *ep;
- int ch, term;
-
- if (zeroflag) {
- /*
- * Read a NUL-terminated pathname, being especially
- * paranoid about proper termination and pathname length.
- */
- for (bp = buf, ep = buf + buflen; bp < ep; bp++) {
- if ((ch = getchar()) == EOF) {
- if (bp != buf)
- paxwarn(1, "Ignoring unterminated "
- "pathname at EOF");
- return(NULL);
- }
- if ((*bp = ch) == '\0')
- return(buf);
- }
- /* Too long - skip this path */
- *--bp = '\0';
- term = '\0';
- } else {
- if (fgets(buf, buflen, stdin) == NULL)
- return(NULL);
- if ((bp = strchr(buf, '\n')) != NULL || feof(stdin)) {
- if (bp != NULL)
- *bp = '\0';
- return(buf);
- }
- /* Too long - skip this path */
- term = '\n';
- }
- while ((ch = getchar()) != term && ch != EOF)
- ;
- paxwarn(1, "Ignoring too-long pathname: %s", buf);
- return(NULL);
-}
diff --git a/pax/ftree.h b/pax/ftree.h
@@ -1,51 +0,0 @@
-/* $OpenBSD: ftree.h,v 1.5 2008/05/06 06:54:28 henning Exp $ */
-/* $NetBSD: ftree.h,v 1.3 1995/03/21 09:07:23 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)ftree.h 8.1 (Berkeley) 5/31/93
- */
-
-/*
- * Data structure used by the ftree.c routines to store the file args to be
- * handed to fts(). It keeps a reference count of which args generated a
- * "selected" member
- */
-
-typedef struct ftree {
- char *fname; /* file tree name */
- int refcnt; /* has tree had a selected file? */
- int newercnt; /* skipped due to -u/-D */
- int chflg; /* change directory flag */
- struct ftree *fow; /* pointer to next entry on list */
-} FTREE;
diff --git a/pax/gen_subs.c b/pax/gen_subs.c
@@ -1,425 +0,0 @@
-/* $OpenBSD: gen_subs.c,v 1.20 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdio.h>
-#include <tzfile.h>
-#include <utmp.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <vis.h>
-#include "pax.h"
-#include "extern.h"
-
-/*
- * a collection of general purpose subroutines used by pax
- */
-
-/*
- * constants used by ls_list() when printing out archive members
- */
-#define MODELEN 20
-#define DATELEN 64
-#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
-#define CURFRMT "%b %e %H:%M"
-#define OLDFRMT "%b %e %Y"
-#define NAME_WIDTH 8
-
-/*
- * ls_list()
- * list the members of an archive in ls format
- */
-
-void
-ls_list(ARCHD *arcn, time_t now, FILE *fp)
-{
- struct stat *sbp;
- char f_mode[MODELEN];
- char f_date[DATELEN];
- const char *timefrmt;
- int term;
-
- term = zeroflag ? '\0' : '\n'; /* path termination character */
-
- /*
- * if not verbose, just print the file name
- */
- if (!vflag) {
- if (zeroflag)
- (void)fputs(arcn->name, fp);
- else
- safe_print(arcn->name, fp);
- (void)putc(term, fp);
- (void)fflush(fp);
- return;
- }
-
- /*
- * user wants long mode
- */
- sbp = &(arcn->sb);
- strmode(sbp->st_mode, f_mode);
-
- if (ltmfrmt == NULL) {
- /*
- * no locale specified format. time format based on age
- * compared to the time pax was started.
- */
- if ((sbp->st_mtime + SIXMONTHS) <= now)
- timefrmt = OLDFRMT;
- else
- timefrmt = CURFRMT;
- } else
- timefrmt = ltmfrmt;
-
- /*
- * print file mode, link count, uid, gid and time
- */
- if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
- f_date[0] = '\0';
- (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode, sbp->st_nlink,
- NAME_WIDTH, UT_NAMESIZE, name_uid(sbp->st_uid, 1),
- NAME_WIDTH, UT_NAMESIZE, name_gid(sbp->st_gid, 1));
-
- /*
- * print device id's for devices, or sizes for other nodes
- */
- if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
-# ifdef LONG_OFF_T
- (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
-# else
- (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
-# endif
- (unsigned long)MINOR(sbp->st_rdev));
- else {
-# ifdef LONG_OFF_T
- (void)fprintf(fp, "%9lu ", sbp->st_size);
-# else
- (void)fprintf(fp, "%9qu ", sbp->st_size);
-# endif
- }
-
- /*
- * print name and link info for hard and soft links
- */
- (void)fputs(f_date, fp);
- (void)putc(' ', fp);
- safe_print(arcn->name, fp);
- if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
- fputs(" == ", fp);
- safe_print(arcn->ln_name, fp);
- } else if (arcn->type == PAX_SLK) {
- fputs(" -> ", fp);
- safe_print(arcn->ln_name, fp);
- }
- (void)putc(term, fp);
- (void)fflush(fp);
- return;
-}
-
-/*
- * tty_ls()
- * print a short summary of file to tty.
- */
-
-void
-ls_tty(ARCHD *arcn)
-{
- char f_date[DATELEN];
- char f_mode[MODELEN];
- const char *timefrmt;
-
- if (ltmfrmt == NULL) {
- /*
- * no locale specified format
- */
- if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
- timefrmt = OLDFRMT;
- else
- timefrmt = CURFRMT;
- } else
- timefrmt = ltmfrmt;
-
- /*
- * convert time to string, and print
- */
- if (strftime(f_date, DATELEN, timefrmt,
- localtime(&(arcn->sb.st_mtime))) == 0)
- f_date[0] = '\0';
- strmode(arcn->sb.st_mode, f_mode);
- tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
- return;
-}
-
-void
-safe_print(const char *str, FILE *fp)
-{
- char visbuf[5];
- const char *cp;
-
- /*
- * if printing to a tty, use vis(3) to print special characters.
- */
- if (isatty(fileno(fp))) {
- for (cp = str; *cp; cp++) {
- (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
- (void)fputs(visbuf, fp);
- }
- } else {
- (void)fputs(str, fp);
- }
-}
-
-/*
- * asc_ul()
- * convert hex/octal character string into a u_long. We do not have to
- * check for overflow! (the headers in all supported formats are not large
- * enough to create an overflow).
- * NOTE: strings passed to us are NOT TERMINATED.
- * Return:
- * unsigned long value
- */
-
-u_long
-asc_ul(char *str, int len, int base)
-{
- char *stop;
- u_long tval = 0;
-
- stop = str + len;
-
- /*
- * skip over leading blanks and zeros
- */
- while ((str < stop) && ((*str == ' ') || (*str == '0')))
- ++str;
-
- /*
- * for each valid digit, shift running value (tval) over to next digit
- * and add next digit
- */
- if (base == HEX) {
- while (str < stop) {
- if ((*str >= '0') && (*str <= '9'))
- tval = (tval << 4) + (*str++ - '0');
- else if ((*str >= 'A') && (*str <= 'F'))
- tval = (tval << 4) + 10 + (*str++ - 'A');
- else if ((*str >= 'a') && (*str <= 'f'))
- tval = (tval << 4) + 10 + (*str++ - 'a');
- else
- break;
- }
- } else {
- while ((str < stop) && (*str >= '0') && (*str <= '7'))
- tval = (tval << 3) + (*str++ - '0');
- }
- return(tval);
-}
-
-/*
- * ul_asc()
- * convert an unsigned long into an hex/oct ascii string. pads with LEADING
- * ascii 0's to fill string completely
- * NOTE: the string created is NOT TERMINATED.
- */
-
-int
-ul_asc(u_long val, char *str, int len, int base)
-{
- char *pt;
- u_long digit;
-
- /*
- * WARNING str is not '\0' terminated by this routine
- */
- pt = str + len - 1;
-
- /*
- * do a tailwise conversion (start at right most end of string to place
- * least significant digit). Keep shifting until conversion value goes
- * to zero (all digits were converted)
- */
- if (base == HEX) {
- while (pt >= str) {
- if ((digit = (val & 0xf)) < 10)
- *pt-- = '0' + (char)digit;
- else
- *pt-- = 'a' + (char)(digit - 10);
- if ((val = (val >> 4)) == (u_long)0)
- break;
- }
- } else {
- while (pt >= str) {
- *pt-- = '0' + (char)(val & 0x7);
- if ((val = (val >> 3)) == (u_long)0)
- break;
- }
- }
-
- /*
- * pad with leading ascii ZEROS. We return -1 if we ran out of space.
- */
- while (pt >= str)
- *pt-- = '0';
- if (val != (u_long)0)
- return(-1);
- return(0);
-}
-
-#ifndef LONG_OFF_T
-/*
- * asc_uqd()
- * convert hex/octal character string into a u_quad_t. We do not have to
- * check for overflow! (the headers in all supported formats are not large
- * enough to create an overflow).
- * NOTE: strings passed to us are NOT TERMINATED.
- * Return:
- * u_quad_t value
- */
-
-u_quad_t
-asc_uqd(char *str, int len, int base)
-{
- char *stop;
- u_quad_t tval = 0;
-
- stop = str + len;
-
- /*
- * skip over leading blanks and zeros
- */
- while ((str < stop) && ((*str == ' ') || (*str == '0')))
- ++str;
-
- /*
- * for each valid digit, shift running value (tval) over to next digit
- * and add next digit
- */
- if (base == HEX) {
- while (str < stop) {
- if ((*str >= '0') && (*str <= '9'))
- tval = (tval << 4) + (*str++ - '0');
- else if ((*str >= 'A') && (*str <= 'F'))
- tval = (tval << 4) + 10 + (*str++ - 'A');
- else if ((*str >= 'a') && (*str <= 'f'))
- tval = (tval << 4) + 10 + (*str++ - 'a');
- else
- break;
- }
- } else {
- while ((str < stop) && (*str >= '0') && (*str <= '7'))
- tval = (tval << 3) + (*str++ - '0');
- }
- return(tval);
-}
-
-/*
- * uqd_asc()
- * convert an u_quad_t into a hex/oct ascii string. pads with LEADING
- * ascii 0's to fill string completely
- * NOTE: the string created is NOT TERMINATED.
- */
-
-int
-uqd_asc(u_quad_t val, char *str, int len, int base)
-{
- char *pt;
- u_quad_t digit;
-
- /*
- * WARNING str is not '\0' terminated by this routine
- */
- pt = str + len - 1;
-
- /*
- * do a tailwise conversion (start at right most end of string to place
- * least significant digit). Keep shifting until conversion value goes
- * to zero (all digits were converted)
- */
- if (base == HEX) {
- while (pt >= str) {
- if ((digit = (val & 0xf)) < 10)
- *pt-- = '0' + (char)digit;
- else
- *pt-- = 'a' + (char)(digit - 10);
- if ((val = (val >> 4)) == (u_quad_t)0)
- break;
- }
- } else {
- while (pt >= str) {
- *pt-- = '0' + (char)(val & 0x7);
- if ((val = (val >> 3)) == (u_quad_t)0)
- break;
- }
- }
-
- /*
- * pad with leading ascii ZEROS. We return -1 if we ran out of space.
- */
- while (pt >= str)
- *pt-- = '0';
- if (val != (u_quad_t)0)
- return(-1);
- return(0);
-}
-#endif
-
-/*
- * Copy at max min(bufz, fieldsz) chars from field to buf, stopping
- * at the first NUL char. NUL terminate buf if there is room left.
- */
-size_t
-fieldcpy(char *buf, size_t bufsz, const char *field, size_t fieldsz)
-{
- char *p = buf;
- const char *q = field;
- size_t i = 0;
-
- if (fieldsz > bufsz)
- fieldsz = bufsz;
- while (i < fieldsz && *q != '\0') {
- *p++ = *q++;
- i++;
- }
- if (i < bufsz)
- *p = '\0';
- return(i);
-}
diff --git a/pax/getoldopt.c b/pax/getoldopt.c
@@ -1,69 +0,0 @@
-/* $OpenBSD: getoldopt.c,v 1.9 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: getoldopt.c,v 1.3 1995/03/21 09:07:28 cgd Exp $ */
-
-/*
- * Plug-compatible replacement for getopt() for parsing tar-like
- * arguments. If the first argument begins with "-", it uses getopt;
- * otherwise, it uses the old rules used by tar, dump, and ps.
- *
- * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu) and placed
- * in the Public Domain for your edification and enjoyment.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include "pax.h"
-#include "extern.h"
-
-int
-getoldopt(int argc, char **argv, const char *optstring)
-{
- static char *key; /* Points to next keyletter */
- static char use_getopt; /* !=0 if argv[1][0] was '-' */
- char c;
- char *place;
-
- optarg = NULL;
-
- if (key == NULL) { /* First time */
- if (argc < 2)
- return (-1);
- key = argv[1];
- if (*key == '-')
- use_getopt++;
- else
- optind = 2;
- }
-
- if (use_getopt)
- return (getopt(argc, argv, optstring));
-
- c = *key++;
- if (c == '\0') {
- key--;
- return (-1);
- }
- place = strchr(optstring, c);
-
- if (place == NULL || c == ':') {
- fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
- return ('?');
- }
-
- place++;
- if (*place == ':') {
- if (optind < argc) {
- optarg = argv[optind];
- optind++;
- } else {
- fprintf(stderr, "%s: %c argument missing\n",
- argv[0], c);
- return ('?');
- }
- }
-
- return (c);
-}
diff --git a/pax/mkfile b/pax/mkfile
@@ -1,12 +0,0 @@
-BIN = pax
-pax_OBJ = ar_io.o ar_subs.o buf_subs.o cache.o cpio.o file_subs.o ftree.o \
- gen_subs.o getoldopt.o options.o pat_rep.o pax.o sel_subs.o tables.o \
- tar.o tty_subs.o
-INSTALL_BIN = pax
-INSTALL_SYMLINK = \
- pax /bin/tar \
- pax /bin/cpio
-INSTALL_MAN1 = pax.1 tar.1 cpio.1
-DEPS = libcommon
-
-<$mkbuild/mk.default
diff --git a/pax/options.c b/pax/options.c
@@ -1,1609 +0,0 @@
-/* $OpenBSD: options.c,v 1.75 2012/03/04 04:05:15 fgsch Exp $ */
-/* $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/mtio.h>
-#include <sys/param.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <paths.h>
-#include "pax.h"
-#include "options.h"
-#include "cpio.h"
-#include "tar.h"
-#include "extern.h"
-
-/*
- * Routines which handle command line options
- */
-
-static char flgch[] = FLGCH; /* list of all possible flags */
-static OPLIST *ophead = NULL; /* head for format specific options -x */
-static OPLIST *optail = NULL; /* option tail */
-
-static int no_op(void);
-static void printflg(unsigned int);
-static int c_frmt(const void *, const void *);
-static off_t str_offt(char *);
-static char *get_line(FILE *fp);
-static void pax_options(int, char **);
-static void pax_usage(void);
-static void tar_options(int, char **);
-static void tar_usage(void);
-static void cpio_options(int, char **);
-static void cpio_usage(void);
-
-/* errors from get_line */
-#define GETLINE_FILE_CORRUPT 1
-#define GETLINE_OUT_OF_MEM 2
-static int getline_error;
-
-
-#define GZIP_CMD "gzip" /* command to run as gzip */
-#define COMPRESS_CMD "compress" /* command to run as compress */
-#define BZIP2_CMD "bzip2" /* command to run as bzip2 */
-
-/*
- * Format specific routine table - MUST BE IN SORTED ORDER BY NAME
- * (see pax.h for description of each function)
- *
- * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read,
- * read, end_read, st_write, write, end_write, trail,
- * rd_data, wr_data, options
- */
-
-FSUB fsub[] = {
-/* 0: OLD BINARY CPIO */
- {"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
- bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail,
- rd_wrfile, wr_rdfile, bad_opt},
-
-/* 1: OLD OCTAL CHARACTER CPIO */
- {"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
- cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail,
- rd_wrfile, wr_rdfile, bad_opt},
-
-/* 2: SVR4 HEX CPIO */
- {"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
- vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail,
- rd_wrfile, wr_rdfile, bad_opt},
-
-/* 3: SVR4 HEX CPIO WITH CRC */
- {"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
- vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail,
- rd_wrfile, wr_rdfile, bad_opt},
-
-/* 4: OLD TAR */
- {"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
- tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
- rd_wrfile, wr_rdfile, tar_opt},
-
-/* 5: POSIX USTAR */
- {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd,
- ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail,
- rd_wrfile, wr_rdfile, bad_opt},
-};
-#define F_OCPIO 0 /* format when called as cpio -6 */
-#define F_ACPIO 1 /* format when called as cpio -c */
-#define F_CPIO 3 /* format when called as cpio */
-#define F_OTAR 4 /* format when called as tar -o */
-#define F_TAR 5 /* format when called as tar */
-#define DEFLT 5 /* default write format from list above */
-
-/*
- * ford is the archive search order used by get_arc() to determine what kind
- * of archive we are dealing with. This helps to properly id archive formats
- * some formats may be subsets of others....
- */
-int ford[] = {5, 4, 3, 2, 1, 0, -1 };
-
-/*
- * Do we have -C anywhere?
- */
-int havechd = 0;
-
-/*
- * options()
- * figure out if we are pax, tar or cpio. Call the appropriate options
- * parser
- */
-
-void
-options(int argc, char **argv)
-{
-
- /*
- * Are we acting like pax, tar or cpio (based on argv[0])
- */
- if ((argv0 = strrchr(argv[0], '/')) != NULL)
- argv0++;
- else
- argv0 = argv[0];
-
- if (strcmp(NM_TAR, argv0) == 0) {
- tar_options(argc, argv);
- return;
- } else if (strcmp(NM_CPIO, argv0) == 0) {
- cpio_options(argc, argv);
- return;
- }
- /*
- * assume pax as the default
- */
- argv0 = NM_PAX;
- pax_options(argc, argv);
-}
-
-/*
- * pax_options()
- * look at the user specified flags. set globals as required and check if
- * the user specified a legal set of flags. If not, complain and exit
- */
-
-static void
-pax_options(int argc, char **argv)
-{
- int c;
- int i;
- unsigned int flg = 0;
- unsigned int bflg = 0;
- char *pt;
- FSUB tmp;
-
- /*
- * process option flags
- */
- while ((c=getopt(argc,argv,"ab:cdf:ijklno:p:rs:tuvwx:zB:DE:G:HLOPT:U:XYZ0"))
- != -1) {
- switch (c) {
- case 'a':
- /*
- * append
- */
- flg |= AF;
- break;
- case 'b':
- /*
- * specify blocksize
- */
- flg |= BF;
- if ((wrblksz = (int)str_offt(optarg)) <= 0) {
- paxwarn(1, "Invalid block size %s", optarg);
- pax_usage();
- }
- break;
- case 'c':
- /*
- * inverse match on patterns
- */
- cflag = 1;
- flg |= CF;
- break;
- case 'd':
- /*
- * match only dir on extract, not the subtree at dir
- */
- dflag = 1;
- flg |= DF;
- break;
- case 'f':
- /*
- * filename where the archive is stored
- */
- arcname = optarg;
- flg |= FF;
- break;
- case 'i':
- /*
- * interactive file rename
- */
- iflag = 1;
- flg |= IF;
- break;
- case 'j':
- /*
- * use bzip2. Non standard option.
- */
- gzip_program = BZIP2_CMD;
- break;
- case 'k':
- /*
- * do not clobber files that exist
- */
- kflag = 1;
- flg |= KF;
- break;
- case 'l':
- /*
- * try to link src to dest with copy (-rw)
- */
- lflag = 1;
- flg |= LF;
- break;
- case 'n':
- /*
- * select first match for a pattern only
- */
- nflag = 1;
- flg |= NF;
- break;
- case 'o':
- /*
- * pass format specific options
- */
- flg |= OF;
- if (opt_add(optarg) < 0)
- pax_usage();
- break;
- case 'p':
- /*
- * specify file characteristic options
- */
- for (pt = optarg; *pt != '\0'; ++pt) {
- switch (*pt) {
- case 'a':
- /*
- * do not preserve access time
- */
- patime = 0;
- break;
- case 'e':
- /*
- * preserve user id, group id, file
- * mode, access/modification times
- */
- pids = 1;
- pmode = 1;
- patime = 1;
- pmtime = 1;
- break;
- case 'm':
- /*
- * do not preserve modification time
- */
- pmtime = 0;
- break;
- case 'o':
- /*
- * preserve uid/gid
- */
- pids = 1;
- break;
- case 'p':
- /*
- * preserve file mode bits
- */
- pmode = 1;
- break;
- default:
- paxwarn(1, "Invalid -p string: %c", *pt);
- pax_usage();
- break;
- }
- }
- flg |= PF;
- break;
- case 'r':
- /*
- * read the archive
- */
- flg |= RF;
- break;
- case 's':
- /*
- * file name substitution name pattern
- */
- if (rep_add(optarg) < 0) {
- pax_usage();
- break;
- }
- flg |= SF;
- break;
- case 't':
- /*
- * preserve access time on filesystem nodes we read
- */
- tflag = 1;
- flg |= TF;
- break;
- case 'u':
- /*
- * ignore those older files
- */
- uflag = 1;
- flg |= UF;
- break;
- case 'v':
- /*
- * verbose operation mode
- */
- vflag = 1;
- flg |= VF;
- break;
- case 'w':
- /*
- * write an archive
- */
- flg |= WF;
- break;
- case 'x':
- /*
- * specify an archive format on write
- */
- tmp.name = optarg;
- if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
- sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) {
- flg |= XF;
- break;
- }
- paxwarn(1, "Unknown -x format: %s", optarg);
- (void)fputs("pax: Known -x formats are:", stderr);
- for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
- (void)fprintf(stderr, " %s", fsub[i].name);
- (void)fputs("\n\n", stderr);
- pax_usage();
- break;
- case 'z':
- /*
- * use gzip. Non standard option.
- */
- gzip_program = GZIP_CMD;
- break;
- case 'B':
- /*
- * non-standard option on number of bytes written on a
- * single archive volume.
- */
- if ((wrlimit = str_offt(optarg)) <= 0) {
- paxwarn(1, "Invalid write limit %s", optarg);
- pax_usage();
- }
- if (wrlimit % BLKMULT) {
- paxwarn(1, "Write limit is not a %d byte multiple",
- BLKMULT);
- pax_usage();
- }
- flg |= CBF;
- break;
- case 'D':
- /*
- * On extraction check file inode change time before the
- * modification of the file name. Non standard option.
- */
- Dflag = 1;
- flg |= CDF;
- break;
- case 'E':
- /*
- * non-standard limit on read faults
- * 0 indicates stop after first error, values
- * indicate a limit, "NONE" try forever
- */
- flg |= CEF;
- if (strcmp(NONE, optarg) == 0)
- maxflt = -1;
- else if ((maxflt = atoi(optarg)) < 0) {
- paxwarn(1, "Error count value must be positive");
- pax_usage();
- }
- break;
- case 'G':
- /*
- * non-standard option for selecting files within an
- * archive by group (gid or name)
- */
- if (grp_add(optarg) < 0) {
- pax_usage();
- break;
- }
- flg |= CGF;
- break;
- case 'H':
- /*
- * follow command line symlinks only
- */
- Hflag = 1;
- flg |= CHF;
- break;
- case 'L':
- /*
- * follow symlinks
- */
- Lflag = 1;
- flg |= CLF;
- break;
- case 'O':
- /*
- * Force one volume. Non standard option.
- */
- force_one_volume = 1;
- break;
- case 'P':
- /*
- * do NOT follow symlinks (default)
- */
- Lflag = 0;
- flg |= CPF;
- break;
- case 'T':
- /*
- * non-standard option for selecting files within an
- * archive by modification time range (lower,upper)
- */
- if (trng_add(optarg) < 0) {
- pax_usage();
- break;
- }
- flg |= CTF;
- break;
- case 'U':
- /*
- * non-standard option for selecting files within an
- * archive by user (uid or name)
- */
- if (usr_add(optarg) < 0) {
- pax_usage();
- break;
- }
- flg |= CUF;
- break;
- case 'X':
- /*
- * do not pass over mount points in the file system
- */
- Xflag = 1;
- flg |= CXF;
- break;
- case 'Y':
- /*
- * On extraction check file inode change time after the
- * modification of the file name. Non standard option.
- */
- Yflag = 1;
- flg |= CYF;
- break;
- case 'Z':
- /*
- * On extraction check modification time after the
- * modification of the file name. Non standard option.
- */
- Zflag = 1;
- flg |= CZF;
- break;
- case '0':
- /*
- * Use \0 as pathname terminator.
- * (For use with the -print0 option of find(1).)
- */
- zeroflag = 1;
- flg |= C0F;
- break;
- default:
- pax_usage();
- break;
- }
- }
-
- /*
- * figure out the operation mode of pax read,write,extract,copy,append
- * or list. check that we have not been given a bogus set of flags
- * for the operation mode.
- */
- if (ISLIST(flg)) {
- act = LIST;
- listf = stdout;
- bflg = flg & BDLIST;
- } else if (ISEXTRACT(flg)) {
- act = EXTRACT;
- bflg = flg & BDEXTR;
- } else if (ISARCHIVE(flg)) {
- act = ARCHIVE;
- bflg = flg & BDARCH;
- } else if (ISAPPND(flg)) {
- act = APPND;
- bflg = flg & BDARCH;
- } else if (ISCOPY(flg)) {
- act = COPY;
- bflg = flg & BDCOPY;
- } else
- pax_usage();
- if (bflg) {
- printflg(flg);
- pax_usage();
- }
-
- /*
- * if we are writing (ARCHIVE) we use the default format if the user
- * did not specify a format. when we write during an APPEND, we will
- * adopt the format of the existing archive if none was supplied.
- */
- if (!(flg & XF) && (act == ARCHIVE))
- frmt = &(fsub[DEFLT]);
-
- /*
- * process the args as they are interpreted by the operation mode
- */
- switch (act) {
- case LIST:
- case EXTRACT:
- for (; optind < argc; optind++)
- if (pat_add(argv[optind], NULL) < 0)
- pax_usage();
- break;
- case COPY:
- if (optind >= argc) {
- paxwarn(0, "Destination directory was not supplied");
- pax_usage();
- }
- --argc;
- dirptr = argv[argc];
- /* FALL THROUGH */
- case ARCHIVE:
- case APPND:
- for (; optind < argc; optind++)
- if (ftree_add(argv[optind], 0) < 0)
- pax_usage();
- /*
- * no read errors allowed on updates/append operation!
- */
- maxflt = 0;
- break;
- }
-}
-
-
-/*
- * tar_options()
- * look at the user specified flags. set globals as required and check if
- * the user specified a legal set of flags. If not, complain and exit
- */
-
-static void
-tar_options(int argc, char **argv)
-{
- int c;
- int fstdin = 0;
- int Oflag = 0;
- int nincfiles = 0;
- int incfiles_max = 0;
- struct incfile {
- char *file;
- char *dir;
- };
- struct incfile *incfiles = NULL;
-
- /*
- * Set default values.
- */
- rmleadslash = 1;
-
- /*
- * process option flags
- */
- while ((c = getoldopt(argc, argv,
- "b:cef:hjmopqruts:vwxzBC:HI:LNOPXZ014578")) != -1) {
- switch (c) {
- case 'b':
- /*
- * specify blocksize in 512-byte blocks
- */
- if ((wrblksz = (int)str_offt(optarg)) <= 0) {
- paxwarn(1, "Invalid block size %s", optarg);
- tar_usage();
- }
- wrblksz *= 512; /* XXX - check for int oflow */
- break;
- case 'c':
- /*
- * create an archive
- */
- act = ARCHIVE;
- break;
- case 'e':
- /*
- * stop after first error
- */
- maxflt = 0;
- break;
- case 'f':
- /*
- * filename where the archive is stored
- */
- if ((optarg[0] == '-') && (optarg[1]== '\0')) {
- /*
- * treat a - as stdin
- */
- fstdin = 1;
- arcname = NULL;
- break;
- }
- fstdin = 0;
- arcname = optarg;
- break;
- case 'h':
- /*
- * follow symlinks
- */
- Lflag = 1;
- break;
- case 'j':
- /*
- * use bzip2. Non standard option.
- */
- gzip_program = BZIP2_CMD;
- break;
- case 'm':
- /*
- * do not preserve modification time
- */
- pmtime = 0;
- break;
- case 'O':
- Oflag = 1;
- break;
- case 'o':
- Oflag = 2;
- break;
- case 'p':
- /*
- * preserve uid/gid and file mode, regardless of umask
- */
- pmode = 1;
- pids = 1;
- break;
- case 'q':
- /*
- * select first match for a pattern only
- */
- nflag = 1;
- break;
- case 'r':
- case 'u':
- /*
- * append to the archive
- */
- act = APPND;
- break;
- case 's':
- /*
- * file name substitution name pattern
- */
- if (rep_add(optarg) < 0) {
- tar_usage();
- break;
- }
- break;
- case 't':
- /*
- * list contents of the tape
- */
- act = LIST;
- break;
- case 'v':
- /*
- * verbose operation mode
- */
- vflag++;
- break;
- case 'w':
- /*
- * interactive file rename
- */
- iflag = 1;
- break;
- case 'x':
- /*
- * extract an archive, preserving mode,
- * and mtime if possible.
- */
- act = EXTRACT;
- pmtime = 1;
- break;
- case 'z':
- /*
- * use gzip. Non standard option.
- */
- gzip_program = GZIP_CMD;
- break;
- case 'B':
- /*
- * Nothing to do here, this is pax default
- */
- break;
- case 'C':
- havechd++;
- chdname = optarg;
- break;
- case 'H':
- /*
- * follow command line symlinks only
- */
- Hflag = 1;
- break;
- case 'I':
- if (++nincfiles > incfiles_max) {
- size_t n = nincfiles + 3;
- struct incfile *p;
-
- p = realloc(incfiles,
- sizeof(*incfiles) * n);
- if (p == NULL) {
- free(incfiles);
- incfiles = NULL;
- paxwarn(0, "Unable to allocate space "
- "for option list");
- exit(1);
- }
- incfiles = p;
- incfiles_max = n;
- }
- incfiles[nincfiles - 1].file = optarg;
- incfiles[nincfiles - 1].dir = chdname;
- break;
- case 'L':
- /*
- * follow symlinks
- */
- Lflag = 1;
- break;
- case 'N':
- /* numeric uid and gid only */
- Nflag = 1;
- break;
- case 'P':
- /*
- * do not remove leading '/' from pathnames
- */
- rmleadslash = 0;
- break;
- case 'X':
- /*
- * do not pass over mount points in the file system
- */
- Xflag = 1;
- break;
- case 'Z':
- /*
- * use compress.
- */
- gzip_program = COMPRESS_CMD;
- break;
- case '0':
- arcname = DEV_0;
- break;
- case '1':
- arcname = DEV_1;
- break;
- case '4':
- arcname = DEV_4;
- break;
- case '5':
- arcname = DEV_5;
- break;
- case '7':
- arcname = DEV_7;
- break;
- case '8':
- arcname = DEV_8;
- break;
- default:
- tar_usage();
- break;
- }
- }
- argc -= optind;
- argv += optind;
-
- /* Traditional tar behaviour (pax uses stderr unless in list mode) */
- if (fstdin == 1 && act == ARCHIVE)
- listf = stderr;
- else
- listf = stdout;
-
- /* Traditional tar behaviour (pax wants to read file list from stdin) */
- if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0)
- exit(0);
-
- /*
- * process the args as they are interpreted by the operation mode
- */
- switch (act) {
- case LIST:
- case EXTRACT:
- default:
- {
- int sawpat = 0;
- char *file, *dir;
-
- while (nincfiles || *argv != NULL) {
- /*
- * If we queued up any include files,
- * pull them in now. Otherwise, check
- * for -I and -C positional flags.
- * Anything else must be a file to
- * extract.
- */
- if (nincfiles) {
- file = incfiles->file;
- dir = incfiles->dir;
- incfiles++;
- nincfiles--;
- } else if (strcmp(*argv, "-I") == 0) {
- if (*++argv == NULL)
- break;
- file = *argv++;
- dir = chdname;
- } else
- file = NULL;
- if (file != NULL) {
- FILE *fp;
- char *str;
-
- if (strcmp(file, "-") == 0)
- fp = stdin;
- else if ((fp = fopen(file, "r")) == NULL) {
- paxwarn(1, "Unable to open file '%s' for read", file);
- tar_usage();
- }
- while ((str = get_line(fp)) != NULL) {
- if (pat_add(str, dir) < 0)
- tar_usage();
- sawpat = 1;
- }
- if (strcmp(file, "-") != 0)
- fclose(fp);
- if (getline_error) {
- paxwarn(1, "Problem with file '%s'", file);
- tar_usage();
- }
- } else if (strcmp(*argv, "-C") == 0) {
- if (*++argv == NULL)
- break;
- chdname = *argv++;
- havechd++;
- } else if (pat_add(*argv++, chdname) < 0)
- tar_usage();
- else
- sawpat = 1;
- }
- /*
- * if patterns were added, we are doing chdir()
- * on a file-by-file basis, else, just one
- * global chdir (if any) after opening input.
- */
- if (sawpat > 0)
- chdname = NULL;
- }
- break;
- case ARCHIVE:
- case APPND:
- frmt = &(fsub[Oflag ? F_OTAR : F_TAR]);
-
- if (Oflag == 2 && opt_add("write_opt=nodir") < 0)
- tar_usage();
-
- if (chdname != NULL) { /* initial chdir() */
- if (ftree_add(chdname, 1) < 0)
- tar_usage();
- }
-
- while (nincfiles || *argv != NULL) {
- char *file, *dir;
-
- /*
- * If we queued up any include files, pull them in
- * now. Otherwise, check for -I and -C positional
- * flags. Anything else must be a file to include
- * in the archive.
- */
- if (nincfiles) {
- file = incfiles->file;
- dir = incfiles->dir;
- incfiles++;
- nincfiles--;
- } else if (strcmp(*argv, "-I") == 0) {
- if (*++argv == NULL)
- break;
- file = *argv++;
- dir = NULL;
- } else
- file = NULL;
- if (file != NULL) {
- FILE *fp;
- char *str;
-
- /* Set directory if needed */
- if (dir) {
- if (ftree_add(dir, 1) < 0)
- tar_usage();
- }
-
- if (strcmp(file, "-") == 0)
- fp = stdin;
- else if ((fp = fopen(file, "r")) == NULL) {
- paxwarn(1, "Unable to open file '%s' for read", file);
- tar_usage();
- }
- while ((str = get_line(fp)) != NULL) {
- if (ftree_add(str, 0) < 0)
- tar_usage();
- }
- if (strcmp(file, "-") != 0)
- fclose(fp);
- if (getline_error) {
- paxwarn(1, "Problem with file '%s'",
- file);
- tar_usage();
- }
- } else if (strcmp(*argv, "-C") == 0) {
- if (*++argv == NULL)
- break;
- if (ftree_add(*argv++, 1) < 0)
- tar_usage();
- havechd++;
- } else if (ftree_add(*argv++, 0) < 0)
- tar_usage();
- }
- /*
- * no read errors allowed on updates/append operation!
- */
- maxflt = 0;
- break;
- }
- if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) {
- arcname = getenv("TAPE");
- if ((arcname == NULL) || (*arcname == '\0'))
- arcname = _PATH_DEFTAPE;
- }
-}
-
-int mkpath(char *);
-
-int
-mkpath(path)
- char *path;
-{
- struct stat sb;
- char *slash;
- int done = 0;
-
- slash = path;
-
- while (!done) {
- slash += strspn(slash, "/");
- slash += strcspn(slash, "/");
-
- done = (*slash == '\0');
- *slash = '\0';
-
- if (stat(path, &sb)) {
- if (errno != ENOENT || mkdir(path, 0777)) {
- paxwarn(1, "%s", path);
- return (-1);
- }
- } else if (!S_ISDIR(sb.st_mode)) {
- syswarn(1, ENOTDIR, "%s", path);
- return (-1);
- }
-
- if (!done)
- *slash = '/';
- }
-
- return (0);
-}
-/*
- * cpio_options()
- * look at the user specified flags. set globals as required and check if
- * the user specified a legal set of flags. If not, complain and exit
- */
-
-static void
-cpio_options(int argc, char **argv)
-{
- int c, i;
- char *str;
- FSUB tmp;
- FILE *fp;
-
- kflag = 1;
- pids = 1;
- pmode = 1;
- pmtime = 0;
- arcname = NULL;
- dflag = 1;
- act = -1;
- nodirs = 1;
- while ((c=getopt(argc,argv,"abcdfijklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1)
- switch (c) {
- case 'a':
- /*
- * preserve access time on files read
- */
- tflag = 1;
- break;
- case 'b':
- /*
- * swap bytes and half-words when reading data
- */
- break;
- case 'c':
- /*
- * ASCII cpio header
- */
- frmt = &(fsub[F_ACPIO]);
- break;
- case 'd':
- /*
- * create directories as needed
- */
- nodirs = 0;
- break;
- case 'f':
- /*
- * invert meaning of pattern list
- */
- cflag = 1;
- break;
- case 'i':
- /*
- * restore an archive
- */
- act = EXTRACT;
- break;
- case 'j':
- /*
- * use bzip2. Non standard option.
- */
- gzip_program = BZIP2_CMD;
- break;
- case 'k':
- break;
- case 'l':
- /*
- * use links instead of copies when possible
- */
- lflag = 1;
- break;
- case 'm':
- /*
- * preserve modification time
- */
- pmtime = 1;
- break;
- case 'o':
- /*
- * create an archive
- */
- act = ARCHIVE;
- frmt = &(fsub[F_CPIO]);
- break;
- case 'p':
- /*
- * copy-pass mode
- */
- act = COPY;
- break;
- case 'r':
- /*
- * interactively rename files
- */
- iflag = 1;
- break;
- case 's':
- /*
- * swap bytes after reading data
- */
- break;
- case 't':
- /*
- * list contents of archive
- */
- act = LIST;
- listf = stdout;
- break;
- case 'u':
- /*
- * replace newer files
- */
- kflag = 0;
- break;
- case 'v':
- /*
- * verbose operation mode
- */
- vflag = 1;
- break;
- case 'z':
- /*
- * use gzip. Non standard option.
- */
- gzip_program = GZIP_CMD;
- break;
- case 'A':
- /*
- * append mode
- */
- act = APPND;
- break;
- case 'B':
- /*
- * Use 5120 byte block size
- */
- wrblksz = 5120;
- break;
- case 'C':
- /*
- * set block size in bytes
- */
- wrblksz = atoi(optarg);
- break;
- case 'E':
- /*
- * file with patterns to extract or list
- */
- if ((fp = fopen(optarg, "r")) == NULL) {
- paxwarn(1, "Unable to open file '%s' for read", optarg);
- cpio_usage();
- }
- while ((str = get_line(fp)) != NULL) {
- pat_add(str, NULL);
- }
- fclose(fp);
- if (getline_error) {
- paxwarn(1, "Problem with file '%s'", optarg);
- cpio_usage();
- }
- break;
- case 'F':
- case 'I':
- case 'O':
- /*
- * filename where the archive is stored
- */
- if ((optarg[0] == '-') && (optarg[1]== '\0')) {
- /*
- * treat a - as stdin
- */
- arcname = NULL;
- break;
- }
- arcname = optarg;
- break;
- case 'H':
- /*
- * specify an archive format on write
- */
- tmp.name = optarg;
- if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
- sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL)
- break;
- paxwarn(1, "Unknown -H format: %s", optarg);
- (void)fputs("cpio: Known -H formats are:", stderr);
- for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
- (void)fprintf(stderr, " %s", fsub[i].name);
- (void)fputs("\n\n", stderr);
- cpio_usage();
- break;
- case 'L':
- /*
- * follow symbolic links
- */
- Lflag = 1;
- break;
- case 'S':
- /*
- * swap halfwords after reading data
- */
- break;
- case 'Z':
- /*
- * use compress. Non standard option.
- */
- gzip_program = COMPRESS_CMD;
- break;
- case '6':
- /*
- * process Version 6 cpio format
- */
- frmt = &(fsub[F_OCPIO]);
- break;
- case '?':
- default:
- cpio_usage();
- break;
- }
- argc -= optind;
- argv += optind;
-
- /*
- * process the args as they are interpreted by the operation mode
- */
- switch (act) {
- case LIST:
- case EXTRACT:
- while (*argv != NULL)
- if (pat_add(*argv++, NULL) < 0)
- cpio_usage();
- break;
- case COPY:
- if (*argv == NULL) {
- paxwarn(0, "Destination directory was not supplied");
- cpio_usage();
- }
- dirptr = *argv;
- if (mkpath(dirptr) < 0)
- cpio_usage();
- --argc;
- ++argv;
- /* FALL THROUGH */
- case ARCHIVE:
- case APPND:
- if (*argv != NULL)
- cpio_usage();
- /*
- * no read errors allowed on updates/append operation!
- */
- maxflt = 0;
- while ((str = get_line(stdin)) != NULL) {
- ftree_add(str, 0);
- }
- if (getline_error) {
- paxwarn(1, "Problem while reading stdin");
- cpio_usage();
- }
- break;
- default:
- cpio_usage();
- break;
- }
-}
-
-/*
- * printflg()
- * print out those invalid flag sets found to the user
- */
-
-static void
-printflg(unsigned int flg)
-{
- int nxt;
- int pos = 0;
-
- (void)fprintf(stderr,"%s: Invalid combination of options:", argv0);
- while ((nxt = ffs(flg)) != 0) {
- flg = flg >> nxt;
- pos += nxt;
- (void)fprintf(stderr, " -%c", flgch[pos-1]);
- }
- (void)putc('\n', stderr);
-}
-
-/*
- * c_frmt()
- * comparison routine used by bsearch to find the format specified
- * by the user
- */
-
-static int
-c_frmt(const void *a, const void *b)
-{
- return(strcmp(((FSUB *)a)->name, ((FSUB *)b)->name));
-}
-
-/*
- * opt_next()
- * called by format specific options routines to get each format specific
- * flag and value specified with -o
- * Return:
- * pointer to next OPLIST entry or NULL (end of list).
- */
-
-OPLIST *
-opt_next(void)
-{
- OPLIST *opt;
-
- if ((opt = ophead) != NULL)
- ophead = ophead->fow;
- return(opt);
-}
-
-/*
- * bad_opt()
- * generic routine used to complain about a format specific options
- * when the format does not support options.
- */
-
-int
-bad_opt(void)
-{
- OPLIST *opt;
-
- if (ophead == NULL)
- return(0);
- /*
- * print all we were given
- */
- paxwarn(1,"These format options are not supported");
- while ((opt = opt_next()) != NULL)
- (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
- pax_usage();
- return(0);
-}
-
-/*
- * opt_add()
- * breaks the value supplied to -o into a option name and value. options
- * are given to -o in the form -o name-value,name=value
- * multiple -o may be specified.
- * Return:
- * 0 if format in name=value format, -1 if -o is passed junk
- */
-
-int
-opt_add(const char *str)
-{
- OPLIST *opt;
- char *frpt;
- char *pt;
- char *endpt;
- char *dstr;
-
- if ((str == NULL) || (*str == '\0')) {
- paxwarn(0, "Invalid option name");
- return(-1);
- }
- if ((dstr = strdup(str)) == NULL) {
- paxwarn(0, "Unable to allocate space for option list");
- return(-1);
- }
- frpt = endpt = dstr;
-
- /*
- * break into name and values pieces and stuff each one into a
- * OPLIST structure. When we know the format, the format specific
- * option function will go through this list
- */
- while ((frpt != NULL) && (*frpt != '\0')) {
- if ((endpt = strchr(frpt, ',')) != NULL)
- *endpt = '\0';
- if ((pt = strchr(frpt, '=')) == NULL) {
- paxwarn(0, "Invalid options format");
- free(dstr);
- return(-1);
- }
- if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
- paxwarn(0, "Unable to allocate space for option list");
- free(dstr);
- return(-1);
- }
- dstr = NULL; /* parts of string going onto the OPLIST */
- *pt++ = '\0';
- opt->name = frpt;
- opt->value = pt;
- opt->fow = NULL;
- if (endpt != NULL)
- frpt = endpt + 1;
- else
- frpt = NULL;
- if (ophead == NULL) {
- optail = ophead = opt;
- continue;
- }
- optail->fow = opt;
- optail = opt;
- }
- free(dstr);
- return(0);
-}
-
-/*
- * str_offt()
- * Convert an expression of the following forms to an off_t > 0.
- * 1) A positive decimal number.
- * 2) A positive decimal number followed by a b (mult by 512).
- * 3) A positive decimal number followed by a k (mult by 1024).
- * 4) A positive decimal number followed by a m (mult by 512).
- * 5) A positive decimal number followed by a w (mult by sizeof int)
- * 6) Two or more positive decimal numbers (with/without k,b or w).
- * separated by x (also * for backwards compatibility), specifying
- * the product of the indicated values.
- * Return:
- * 0 for an error, a positive value o.w.
- */
-
-static off_t
-str_offt(char *val)
-{
- char *expr;
- off_t num, t;
-
-# ifdef LONG_OFF_T
- num = strtol(val, &expr, 0);
- if ((num == LONG_MAX) || (num <= 0) || (expr == val))
-# else
- num = strtoll(val, &expr, 0);
- if ((num == QUAD_MAX) || (num <= 0) || (expr == val))
-# endif
- return(0);
-
- switch (*expr) {
- case 'b':
- t = num;
- num *= 512;
- if (t > num)
- return(0);
- ++expr;
- break;
- case 'k':
- t = num;
- num *= 1024;
- if (t > num)
- return(0);
- ++expr;
- break;
- case 'm':
- t = num;
- num *= 1048576;
- if (t > num)
- return(0);
- ++expr;
- break;
- case 'w':
- t = num;
- num *= sizeof(int);
- if (t > num)
- return(0);
- ++expr;
- break;
- }
-
- switch (*expr) {
- case '\0':
- break;
- case '*':
- case 'x':
- t = num;
- num *= str_offt(expr + 1);
- if (t > num)
- return(0);
- break;
- default:
- return(0);
- }
- return(num);
-}
-
-char *
-get_line(FILE *f)
-{
- char *name, *temp;
- size_t len;
-
- name = fgetln(f, &len);
- if (!name) {
- getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0;
- return(0);
- }
- if (name[len-1] != '\n')
- len++;
- temp = malloc(len);
- if (!temp) {
- getline_error = GETLINE_OUT_OF_MEM;
- return(0);
- }
- memcpy(temp, name, len-1);
- temp[len-1] = 0;
- return(temp);
-}
-
-/*
- * no_op()
- * for those option functions where the archive format has nothing to do.
- * Return:
- * 0
- */
-
-static int
-no_op(void)
-{
- return(0);
-}
-
-/*
- * pax_usage()
- * print the usage summary to the user
- */
-
-void
-pax_usage(void)
-{
- (void)fputs(
- "usage: pax [-0cdjnOvz] [-E limit] [-f archive] [-G group] [-s replstr]\n"
- " [-T range] [-U user] [pattern ...]\n"
- " pax -r [-0cDdijknOuvYZz] [-E limit] [-f archive] [-G group] [-o options]\n"
- " [-p string] [-s replstr] [-T range] [-U user] [pattern ...]\n"
- " pax -w [-0adHijLOPtuvXz] [-B bytes] [-b blocksize] [-f archive]\n"
- " [-G group] [-o options] [-s replstr] [-T range] [-U user]\n"
- " [-x format] [file ...]\n"
- " pax -rw [-0DdHikLlnOPtuvXYZ] [-G group] [-p string] [-s replstr]\n"
- " [-T range] [-U user] [file ...] directory\n",
- stderr);
- exit(1);
-}
-
-/*
- * tar_usage()
- * print the usage summary to the user
- */
-
-void
-tar_usage(void)
-{
- (void)fputs(
- "usage: tar {crtux}[014578befHhjLmNOoPpqsvwXZz]\n"
- " [blocking-factor | archive | replstr] [-C directory] [-I file]\n"
- " [file ...]\n"
- " tar {-crtux} [-014578eHhjLmNOoPpqvwXZz] [-b blocking-factor]\n"
- " [-C directory] [-f archive] [-I file] [-s replstr] [file ...]\n",
- stderr);
- exit(1);
-}
-
-/*
- * cpio_usage()
- * print the usage summary to the user
- */
-
-void
-cpio_usage(void)
-{
- (void)fputs(
- "usage: cpio -o [-AaBcjLvZz] [-C bytes] [-F archive] [-H format]\n"
- " [-O archive] < name-list [> archive]\n"
- " cpio -i [-6BbcdfjmrSstuvZz] [-C bytes] [-E file] [-F archive] [-H format]\n"
- " [-I archive] [pattern ...] [< archive]\n"
- " cpio -p [-adLlmuv] destination-directory < name-list\n",
- stderr);
- exit(1);
-}
diff --git a/pax/options.h b/pax/options.h
@@ -1,113 +0,0 @@
-/* $OpenBSD: options.h,v 1.4 2003/06/13 17:51:14 millert Exp $ */
-/* $NetBSD: options.h,v 1.3 1995/03/21 09:07:32 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)options.h 8.2 (Berkeley) 4/18/94
- */
-
-/*
- * argv[0] names. Used for tar and cpio emulation
- */
-
-#define NM_TAR "tar"
-#define NM_CPIO "cpio"
-#define NM_PAX "pax"
-
-/*
- * Constants used to specify the legal sets of flags in pax. For each major
- * operation mode of pax, a set of illegal flags is defined. If any one of
- * those illegal flags are found set, we scream and exit
- */
-#define NONE "none"
-
-/*
- * flags (one for each option).
- */
-#define AF 0x00000001
-#define BF 0x00000002
-#define CF 0x00000004
-#define DF 0x00000008
-#define FF 0x00000010
-#define IF 0x00000020
-#define KF 0x00000040
-#define LF 0x00000080
-#define NF 0x00000100
-#define OF 0x00000200
-#define PF 0x00000400
-#define RF 0x00000800
-#define SF 0x00001000
-#define TF 0x00002000
-#define UF 0x00004000
-#define VF 0x00008000
-#define WF 0x00010000
-#define XF 0x00020000
-#define CBF 0x00040000 /* nonstandard extension */
-#define CDF 0x00080000 /* nonstandard extension */
-#define CEF 0x00100000 /* nonstandard extension */
-#define CGF 0x00200000 /* nonstandard extension */
-#define CHF 0x00400000 /* nonstandard extension */
-#define CLF 0x00800000 /* nonstandard extension */
-#define CPF 0x01000000 /* nonstandard extension */
-#define CTF 0x02000000 /* nonstandard extension */
-#define CUF 0x04000000 /* nonstandard extension */
-#define CXF 0x08000000
-#define CYF 0x10000000 /* nonstandard extension */
-#define CZF 0x20000000 /* nonstandard extension */
-#define C0F 0x40000000 /* nonstandard extension */
-
-/*
- * ascii string indexed by bit position above (alter the above and you must
- * alter this string) used to tell the user what flags caused us to complain
- */
-#define FLGCH "abcdfiklnoprstuvwxBDEGHLPTUXYZ0"
-
-/*
- * legal pax operation bit patterns
- */
-
-#define ISLIST(x) (((x) & (RF|WF)) == 0)
-#define ISEXTRACT(x) (((x) & (RF|WF)) == RF)
-#define ISARCHIVE(x) (((x) & (AF|RF|WF)) == WF)
-#define ISAPPND(x) (((x) & (AF|RF|WF)) == (AF|WF))
-#define ISCOPY(x) (((x) & (RF|WF)) == (RF|WF))
-#define ISWRITE(x) (((x) & (RF|WF)) == WF)
-
-/*
- * Illegal option flag subsets based on pax operation
- */
-
-#define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CPF|CXF)
-#define BDARCH (CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF)
-#define BDCOPY (AF|BF|FF|OF|XF|CBF|CEF)
-#define BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF)
diff --git a/pax/pat_rep.c b/pax/pat_rep.c
@@ -1,1053 +0,0 @@
-/* $OpenBSD: pat_rep.c,v 1.31 2009/10/27 23:59:22 deraadt Exp $ */
-/* $NetBSD: pat_rep.c,v 1.4 1995/03/21 09:07:33 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <regex.h>
-#include "pax.h"
-#include "pat_rep.h"
-#include "extern.h"
-
-/*
- * routines to handle pattern matching, name modification (regular expression
- * substitution and interactive renames), and destination name modification for
- * copy (-rw). Both file name and link names are adjusted as required in these
- * routines.
- */
-
-#define MAXSUBEXP 10 /* max subexpressions, DO NOT CHANGE */
-static PATTERN *pathead = NULL; /* file pattern match list head */
-static PATTERN *pattail = NULL; /* file pattern match list tail */
-static REPLACE *rephead = NULL; /* replacement string list head */
-static REPLACE *reptail = NULL; /* replacement string list tail */
-
-static int rep_name(char *, size_t, int *, int);
-static int tty_rename(ARCHD *);
-static int fix_path(char *, int *, char *, int);
-static int fn_match(char *, char *, char **);
-static char * range_match(char *, int);
-static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *);
-
-/*
- * rep_add()
- * parses the -s replacement string; compiles the regular expression
- * and stores the compiled value and it's replacement string together in
- * replacement string list. Input to this function is of the form:
- * /old/new/pg
- * The first char in the string specifies the delimiter used by this
- * replacement string. "Old" is a regular expression in "ed" format which
- * is compiled by regcomp() and is applied to filenames. "new" is the
- * substitution string; p and g are options flags for printing and global
- * replacement (over the single filename)
- * Return:
- * 0 if a proper replacement string and regular expression was added to
- * the list of replacement patterns; -1 otherwise.
- */
-
-int
-rep_add(char *str)
-{
- char *pt1;
- char *pt2;
- REPLACE *rep;
- int res;
- char rebuf[BUFSIZ];
-
- /*
- * throw out the bad parameters
- */
- if ((str == NULL) || (*str == '\0')) {
- paxwarn(1, "Empty replacement string");
- return(-1);
- }
-
- /*
- * first character in the string specifies what the delimiter is for
- * this expression
- */
- for (pt1 = str+1; *pt1; pt1++) {
- if (*pt1 == '\\') {
- pt1++;
- continue;
- }
- if (*pt1 == *str)
- break;
- }
- if (*pt1 == '\0') {
- paxwarn(1, "Invalid replacement string %s", str);
- return(-1);
- }
-
- /*
- * allocate space for the node that handles this replacement pattern
- * and split out the regular expression and try to compile it
- */
- if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
- paxwarn(1, "Unable to allocate memory for replacement string");
- return(-1);
- }
-
- *pt1 = '\0';
- if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
- regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
- paxwarn(1, "%s while compiling regular expression %s", rebuf, str);
- (void)free((char *)rep);
- return(-1);
- }
-
- /*
- * put the delimiter back in case we need an error message and
- * locate the delimiter at the end of the replacement string
- * we then point the node at the new substitution string
- */
- *pt1++ = *str;
- for (pt2 = pt1; *pt2; pt2++) {
- if (*pt2 == '\\') {
- pt2++;
- continue;
- }
- if (*pt2 == *str)
- break;
- }
- if (*pt2 == '\0') {
- regfree(&(rep->rcmp));
- (void)free((char *)rep);
- paxwarn(1, "Invalid replacement string %s", str);
- return(-1);
- }
-
- *pt2 = '\0';
- rep->nstr = pt1;
- pt1 = pt2++;
- rep->flgs = 0;
-
- /*
- * set the options if any
- */
- while (*pt2 != '\0') {
- switch (*pt2) {
- case 'g':
- case 'G':
- rep->flgs |= GLOB;
- break;
- case 'p':
- case 'P':
- rep->flgs |= PRNT;
- break;
- default:
- regfree(&(rep->rcmp));
- (void)free((char *)rep);
- *pt1 = *str;
- paxwarn(1, "Invalid replacement string option %s", str);
- return(-1);
- }
- ++pt2;
- }
-
- /*
- * all done, link it in at the end
- */
- rep->fow = NULL;
- if (rephead == NULL) {
- reptail = rephead = rep;
- return(0);
- }
- reptail->fow = rep;
- reptail = rep;
- return(0);
-}
-
-/*
- * pat_add()
- * add a pattern match to the pattern match list. Pattern matches are used
- * to select which archive members are extracted. (They appear as
- * arguments to pax in the list and read modes). If no patterns are
- * supplied to pax, all members in the archive will be selected (and the
- * pattern match list is empty).
- * Return:
- * 0 if the pattern was added to the list, -1 otherwise
- */
-
-int
-pat_add(char *str, char *chdname)
-{
- PATTERN *pt;
-
- /*
- * throw out the junk
- */
- if ((str == NULL) || (*str == '\0')) {
- paxwarn(1, "Empty pattern string");
- return(-1);
- }
-
- /*
- * allocate space for the pattern and store the pattern. the pattern is
- * part of argv so do not bother to copy it, just point at it. Add the
- * node to the end of the pattern list
- */
- if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
- paxwarn(1, "Unable to allocate memory for pattern string");
- return(-1);
- }
-
- pt->pstr = str;
- pt->pend = NULL;
- pt->plen = strlen(str);
- pt->fow = NULL;
- pt->flgs = 0;
- pt->chdname = chdname;
-
- if (pathead == NULL) {
- pattail = pathead = pt;
- return(0);
- }
- pattail->fow = pt;
- pattail = pt;
- return(0);
-}
-
-/*
- * pat_chk()
- * complain if any the user supplied pattern did not result in a match to
- * a selected archive member.
- */
-
-void
-pat_chk(void)
-{
- PATTERN *pt;
- int wban = 0;
-
- /*
- * walk down the list checking the flags to make sure MTCH was set,
- * if not complain
- */
- for (pt = pathead; pt != NULL; pt = pt->fow) {
- if (pt->flgs & MTCH)
- continue;
- if (!wban) {
- paxwarn(1, "WARNING! These patterns were not matched:");
- ++wban;
- }
- (void)fprintf(stderr, "%s\n", pt->pstr);
- }
-}
-
-/*
- * pat_sel()
- * the archive member which matches a pattern was selected. Mark the
- * pattern as having selected an archive member. arcn->pat points at the
- * pattern that was matched. arcn->pat is set in pat_match()
- *
- * NOTE: When the -c option is used, we are called when there was no match
- * by pat_match() (that means we did match before the inverted sense of
- * the logic). Now this seems really strange at first, but with -c we
- * need to keep track of those patterns that cause an archive member to NOT
- * be selected (it found an archive member with a specified pattern)
- * Return:
- * 0 if the pattern pointed at by arcn->pat was tagged as creating a
- * match, -1 otherwise.
- */
-
-int
-pat_sel(ARCHD *arcn)
-{
- PATTERN *pt;
- PATTERN **ppt;
- int len;
-
- /*
- * if no patterns just return
- */
- if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
- return(0);
-
- /*
- * when we are NOT limited to a single match per pattern mark the
- * pattern and return
- */
- if (!nflag) {
- pt->flgs |= MTCH;
- return(0);
- }
-
- /*
- * we reach this point only when we allow a single selected match per
- * pattern, if the pattern matches a directory and we do not have -d
- * (dflag) we are done with this pattern. We may also be handed a file
- * in the subtree of a directory. in that case when we are operating
- * with -d, this pattern was already selected and we are done
- */
- if (pt->flgs & DIR_MTCH)
- return(0);
-
- if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {
- /*
- * ok we matched a directory and we are allowing
- * subtree matches but because of the -n only its children will
- * match. This is tagged as a DIR_MTCH type.
- * WATCH IT, the code assumes that pt->pend points
- * into arcn->name and arcn->name has not been modified.
- * If not we will have a big mess. Yup this is another kludge
- */
-
- /*
- * if this was a prefix match, remove trailing part of path
- * so we can copy it. Future matches will be exact prefix match
- */
- if (pt->pend != NULL)
- *pt->pend = '\0';
-
- if ((pt->pstr = strdup(arcn->name)) == NULL) {
- paxwarn(1, "Pattern select out of memory");
- if (pt->pend != NULL)
- *pt->pend = '/';
- pt->pend = NULL;
- return(-1);
- }
-
- /*
- * put the trailing / back in the source string
- */
- if (pt->pend != NULL) {
- *pt->pend = '/';
- pt->pend = NULL;
- }
- pt->plen = strlen(pt->pstr);
-
- /*
- * strip off any trailing /, this should really never happen
- */
- len = pt->plen - 1;
- if (*(pt->pstr + len) == '/') {
- *(pt->pstr + len) = '\0';
- pt->plen = len;
- }
- pt->flgs = DIR_MTCH | MTCH;
- arcn->pat = pt;
- return(0);
- }
-
- /*
- * we are then done with this pattern, so we delete it from the list
- * because it can never be used for another match.
- * Seems kind of strange to do for a -c, but the pax spec is really
- * vague on the interaction of -c, -n and -d. We assume that when -c
- * and the pattern rejects a member (i.e. it matched it) it is done.
- * In effect we place the order of the flags as having -c last.
- */
- pt = pathead;
- ppt = &pathead;
- while ((pt != NULL) && (pt != arcn->pat)) {
- ppt = &(pt->fow);
- pt = pt->fow;
- }
-
- if (pt == NULL) {
- /*
- * should never happen....
- */
- paxwarn(1, "Pattern list inconsistent");
- return(-1);
- }
- *ppt = pt->fow;
- (void)free((char *)pt);
- arcn->pat = NULL;
- return(0);
-}
-
-/*
- * pat_match()
- * see if this archive member matches any supplied pattern, if a match
- * is found, arcn->pat is set to point at the potential pattern. Later if
- * this archive member is "selected" we process and mark the pattern as
- * one which matched a selected archive member (see pat_sel())
- * Return:
- * 0 if this archive member should be processed, 1 if it should be
- * skipped and -1 if we are done with all patterns (and pax should quit
- * looking for more members)
- */
-
-int
-pat_match(ARCHD *arcn)
-{
- PATTERN *pt;
-
- arcn->pat = NULL;
-
- /*
- * if there are no more patterns and we have -n (and not -c) we are
- * done. otherwise with no patterns to match, matches all
- */
- if (pathead == NULL) {
- if (nflag && !cflag)
- return(-1);
- return(0);
- }
-
- /*
- * have to search down the list one at a time looking for a match.
- */
- pt = pathead;
- while (pt != NULL) {
- /*
- * check for a file name match unless we have DIR_MTCH set in
- * this pattern then we want a prefix match
- */
- if (pt->flgs & DIR_MTCH) {
- /*
- * this pattern was matched before to a directory
- * as we must have -n set for this (but not -d). We can
- * only match CHILDREN of that directory so we must use
- * an exact prefix match (no wildcards).
- */
- if ((arcn->name[pt->plen] == '/') &&
- (strncmp(pt->pstr, arcn->name, pt->plen) == 0))
- break;
- } else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)
- break;
- pt = pt->fow;
- }
-
- /*
- * return the result, remember that cflag (-c) inverts the sense of a
- * match
- */
- if (pt == NULL)
- return(cflag ? 0 : 1);
-
- /*
- * we had a match, now when we invert the sense (-c) we reject this
- * member. However we have to tag the pattern a being successful, (in a
- * match, not in selecting a archive member) so we call pat_sel() here.
- */
- arcn->pat = pt;
- if (!cflag)
- return(0);
-
- if (pat_sel(arcn) < 0)
- return(-1);
- arcn->pat = NULL;
- return(1);
-}
-
-/*
- * fn_match()
- * Return:
- * 0 if this archive member should be processed, 1 if it should be
- * skipped and -1 if we are done with all patterns (and pax should quit
- * looking for more members)
- * Note: *pend may be changed to show where the prefix ends.
- */
-
-static int
-fn_match(char *pattern, char *string, char **pend)
-{
- char c;
- char test;
-
- *pend = NULL;
- for (;;) {
- switch (c = *pattern++) {
- case '\0':
- /*
- * Ok we found an exact match
- */
- if (*string == '\0')
- return(0);
-
- /*
- * Check if it is a prefix match
- */
- if ((dflag == 1) || (*string != '/'))
- return(-1);
-
- /*
- * It is a prefix match, remember where the trailing
- * / is located
- */
- *pend = string;
- return(0);
- case '?':
- if ((test = *string++) == '\0')
- return (-1);
- break;
- case '*':
- c = *pattern;
- /*
- * Collapse multiple *'s.
- */
- while (c == '*')
- c = *++pattern;
-
- /*
- * Optimized hack for pattern with a * at the end
- */
- if (c == '\0')
- return (0);
-
- /*
- * General case, use recursion.
- */
- while ((test = *string) != '\0') {
- if (!fn_match(pattern, string, pend))
- return (0);
- ++string;
- }
- return (-1);
- case '[':
- /*
- * range match
- */
- if (((test = *string++) == '\0') ||
- ((pattern = range_match(pattern, test)) == NULL))
- return (-1);
- break;
- case '\\':
- default:
- if (c != *string++)
- return (-1);
- break;
- }
- }
- /* NOTREACHED */
-}
-
-static char *
-range_match(char *pattern, int test)
-{
- char c;
- char c2;
- int negate;
- int ok = 0;
-
- if ((negate = (*pattern == '!')) != 0)
- ++pattern;
-
- while ((c = *pattern++) != ']') {
- /*
- * Illegal pattern
- */
- if (c == '\0')
- return (NULL);
-
- if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') &&
- (c2 != ']')) {
- if ((c <= test) && (test <= c2))
- ok = 1;
- pattern += 2;
- } else if (c == test)
- ok = 1;
- }
- return (ok == negate ? NULL : pattern);
-}
-
-/*
- * mod_name()
- * modify a selected file name. first attempt to apply replacement string
- * expressions, then apply interactive file rename. We apply replacement
- * string expressions to both filenames and file links (if we didn't the
- * links would point to the wrong place, and we could never be able to
- * move an archive that has a file link in it). When we rename files
- * interactively, we store that mapping (old name to user input name) so
- * if we spot any file links to the old file name in the future, we will
- * know exactly how to fix the file link.
- * Return:
- * 0 continue to process file, 1 skip this file, -1 pax is finished
- */
-
-int
-mod_name(ARCHD *arcn)
-{
- int res = 0;
-
- /*
- * Strip off leading '/' if appropriate.
- * Currently, this option is only set for the tar format.
- */
- while (rmleadslash && arcn->name[0] == '/') {
- if (arcn->name[1] == '\0') {
- arcn->name[0] = '.';
- } else {
- (void)memmove(arcn->name, &arcn->name[1],
- strlen(arcn->name));
- arcn->nlen--;
- }
- if (rmleadslash < 2) {
- rmleadslash = 2;
- paxwarn(0, "Removing leading / from absolute path names in the archive");
- }
- }
- while (rmleadslash && arcn->ln_name[0] == '/' &&
- (arcn->type == PAX_HLK || arcn->type == PAX_HRG)) {
- if (arcn->ln_name[1] == '\0') {
- arcn->ln_name[0] = '.';
- } else {
- (void)memmove(arcn->ln_name, &arcn->ln_name[1],
- strlen(arcn->ln_name));
- arcn->ln_nlen--;
- }
- if (rmleadslash < 2) {
- rmleadslash = 2;
- paxwarn(0, "Removing leading / from absolute path names in the archive");
- }
- }
-
- /*
- * IMPORTANT: We have a problem. what do we do with symlinks?
- * Modifying a hard link name makes sense, as we know the file it
- * points at should have been seen already in the archive (and if it
- * wasn't seen because of a read error or a bad archive, we lose
- * anyway). But there are no such requirements for symlinks. On one
- * hand the symlink that refers to a file in the archive will have to
- * be modified to so it will still work at its new location in the
- * file system. On the other hand a symlink that points elsewhere (and
- * should continue to do so) should not be modified. There is clearly
- * no perfect solution here. So we handle them like hardlinks. Clearly
- * a replacement made by the interactive rename mapping is very likely
- * to be correct since it applies to a single file and is an exact
- * match. The regular expression replacements are a little harder to
- * justify though. We claim that the symlink name is only likely
- * to be replaced when it points within the file tree being moved and
- * in that case it should be modified. what we really need to do is to
- * call an oracle here. :)
- */
- if (rephead != NULL) {
- /*
- * we have replacement strings, modify the name and the link
- * name if any.
- */
- if ((res = rep_name(arcn->name, sizeof(arcn->name), &(arcn->nlen), 1)) != 0)
- return(res);
-
- if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
- (arcn->type == PAX_HRG)) &&
- ((res = rep_name(arcn->ln_name, sizeof(arcn->ln_name), &(arcn->ln_nlen), 0)) != 0))
- return(res);
- }
-
- if (iflag) {
- /*
- * perform interactive file rename, then map the link if any
- */
- if ((res = tty_rename(arcn)) != 0)
- return(res);
- if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
- (arcn->type == PAX_HRG))
- sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name));
- }
- return(res);
-}
-
-/*
- * tty_rename()
- * Prompt the user for a replacement file name. A "." keeps the old name,
- * a empty line skips the file, and an EOF on reading the tty, will cause
- * pax to stop processing and exit. Otherwise the file name input, replaces
- * the old one.
- * Return:
- * 0 process this file, 1 skip this file, -1 we need to exit pax
- */
-
-static int
-tty_rename(ARCHD *arcn)
-{
- char tmpname[PAXPATHLEN+2];
- int res;
-
- /*
- * prompt user for the replacement name for a file, keep trying until
- * we get some reasonable input. Archives may have more than one file
- * on them with the same name (from updates etc). We print verbose info
- * on the file so the user knows what is up.
- */
- tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0);
-
- for (;;) {
- ls_tty(arcn);
- tty_prnt("Input new name, or a \".\" to keep the old name, ");
- tty_prnt("or a \"return\" to skip this file.\n");
- tty_prnt("Input > ");
- if (tty_read(tmpname, sizeof(tmpname)) < 0)
- return(-1);
- if (strcmp(tmpname, "..") == 0) {
- tty_prnt("Try again, illegal file name: ..\n");
- continue;
- }
- if (strlen(tmpname) > PAXPATHLEN) {
- tty_prnt("Try again, file name too long\n");
- continue;
- }
- break;
- }
-
- /*
- * empty file name, skips this file. a "." leaves it alone
- */
- if (tmpname[0] == '\0') {
- tty_prnt("Skipping file.\n");
- return(1);
- }
- if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
- tty_prnt("Processing continues, name unchanged.\n");
- return(0);
- }
-
- /*
- * ok the name changed. We may run into links that point at this
- * file later. we have to remember where the user sent the file
- * in order to repair any links.
- */
- tty_prnt("Processing continues, name changed to: %s\n", tmpname);
- res = add_name(arcn->name, arcn->nlen, tmpname);
- arcn->nlen = strlcpy(arcn->name, tmpname, sizeof(arcn->name));
- if (arcn->nlen >= sizeof(arcn->name))
- arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
- if (res < 0)
- return(-1);
- return(0);
-}
-
-/*
- * set_dest()
- * fix up the file name and the link name (if any) so this file will land
- * in the destination directory (used during copy() -rw).
- * Return:
- * 0 if ok, -1 if failure (name too long)
- */
-
-int
-set_dest(ARCHD *arcn, char *dest_dir, int dir_len)
-{
- if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
- return(-1);
-
- /*
- * It is really hard to deal with symlinks here, we cannot be sure
- * if the name they point was moved (or will be moved). It is best to
- * leave them alone.
- */
- if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG))
- return(0);
-
- if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
- return(-1);
- return(0);
-}
-
-/*
- * fix_path
- * concatenate dir_name and or_name and store the result in or_name (if
- * it fits). This is one ugly function.
- * Return:
- * 0 if ok, -1 if the final name is too long
- */
-
-static int
-fix_path(char *or_name, int *or_len, char *dir_name, int dir_len)
-{
- char *src;
- char *dest;
- char *start;
- int len;
-
- /*
- * we shift the or_name to the right enough to tack in the dir_name
- * at the front. We make sure we have enough space for it all before
- * we start. since dest always ends in a slash, we skip of or_name
- * if it also starts with one.
- */
- start = or_name;
- src = start + *or_len;
- dest = src + dir_len;
- if (*start == '/') {
- ++start;
- --dest;
- }
- if ((len = dest - or_name) > PAXPATHLEN) {
- paxwarn(1, "File name %s/%s, too long", dir_name, start);
- return(-1);
- }
- *or_len = len;
-
- /*
- * enough space, shift
- */
- while (src >= start)
- *dest-- = *src--;
- src = dir_name + dir_len - 1;
-
- /*
- * splice in the destination directory name
- */
- while (src >= dir_name)
- *dest-- = *src--;
-
- *(or_name + len) = '\0';
- return(0);
-}
-
-/*
- * rep_name()
- * walk down the list of replacement strings applying each one in order.
- * when we find one with a successful substitution, we modify the name
- * as specified. if required, we print the results. if the resulting name
- * is empty, we will skip this archive member. We use the regexp(3)
- * routines (regexp() ought to win a prize as having the most cryptic
- * library function manual page).
- * --Parameters--
- * name is the file name we are going to apply the regular expressions to
- * (and may be modified)
- * nsize is the size of the name buffer.
- * nlen is the length of this name (and is modified to hold the length of
- * the final string).
- * prnt is a flag that says whether to print the final result.
- * Return:
- * 0 if substitution was successful, 1 if we are to skip the file (the name
- * ended up empty)
- */
-
-static int
-rep_name(char *name, size_t nsize, int *nlen, int prnt)
-{
- REPLACE *pt;
- char *inpt;
- char *outpt;
- char *endpt;
- char *rpt;
- int found = 0;
- int res;
- regmatch_t pm[MAXSUBEXP];
- char nname[PAXPATHLEN+1]; /* final result of all replacements */
- char buf1[PAXPATHLEN+1]; /* where we work on the name */
-
- /*
- * copy the name into buf1, where we will work on it. We need to keep
- * the orig string around so we can print out the result of the final
- * replacement. We build up the final result in nname. inpt points at
- * the string we apply the regular expression to. prnt is used to
- * suppress printing when we handle replacements on the link field
- * (the user already saw that substitution go by)
- */
- pt = rephead;
- (void)strlcpy(buf1, name, sizeof(buf1));
- inpt = buf1;
- outpt = nname;
- endpt = outpt + PAXPATHLEN;
-
- /*
- * try each replacement string in order
- */
- while (pt != NULL) {
- do {
- char *oinpt = inpt;
- /*
- * check for a successful substitution, if not go to
- * the next pattern, or cleanup if we were global
- */
- if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
- break;
-
- /*
- * ok we found one. We have three parts, the prefix
- * which did not match, the section that did and the
- * tail (that also did not match). Copy the prefix to
- * the final output buffer (watching to make sure we
- * do not create a string too long).
- */
- found = 1;
- rpt = inpt + pm[0].rm_so;
-
- while ((inpt < rpt) && (outpt < endpt))
- *outpt++ = *inpt++;
- if (outpt == endpt)
- break;
-
- /*
- * for the second part (which matched the regular
- * expression) apply the substitution using the
- * replacement string and place it the prefix in the
- * final output. If we have problems, skip it.
- */
- if ((res = resub(&(pt->rcmp),pm,pt->nstr,oinpt,outpt,endpt))
- < 0) {
- if (prnt)
- paxwarn(1, "Replacement name error %s",
- name);
- return(1);
- }
- outpt += res;
-
- /*
- * we set up to look again starting at the first
- * character in the tail (of the input string right
- * after the last character matched by the regular
- * expression (inpt always points at the first char in
- * the string to process). If we are not doing a global
- * substitution, we will use inpt to copy the tail to
- * the final result. Make sure we do not overrun the
- * output buffer
- */
- inpt += pm[0].rm_eo - pm[0].rm_so;
-
- if ((outpt == endpt) || (*inpt == '\0'))
- break;
-
- /*
- * if the user wants global we keep trying to
- * substitute until it fails, then we are done.
- */
- } while (pt->flgs & GLOB);
-
- if (found)
- break;
-
- /*
- * a successful substitution did NOT occur, try the next one
- */
- pt = pt->fow;
- }
-
- if (found) {
- /*
- * we had a substitution, copy the last tail piece (if there is
- * room) to the final result
- */
- while ((outpt < endpt) && (*inpt != '\0'))
- *outpt++ = *inpt++;
-
- *outpt = '\0';
- if ((outpt == endpt) && (*inpt != '\0')) {
- if (prnt)
- paxwarn(1,"Replacement name too long %s >> %s",
- name, nname);
- return(1);
- }
-
- /*
- * inform the user of the result if wanted
- */
- if (prnt && (pt->flgs & PRNT)) {
- if (*nname == '\0')
- (void)fprintf(stderr,"%s >> <empty string>\n",
- name);
- else
- (void)fprintf(stderr,"%s >> %s\n", name, nname);
- }
-
- /*
- * if empty inform the caller this file is to be skipped
- * otherwise copy the new name over the orig name and return
- */
- if (*nname == '\0')
- return(1);
- *nlen = strlcpy(name, nname, nsize);
- }
- return(0);
-}
-
-/*
- * resub()
- * apply the replacement to the matched expression. expand out the old
- * style ed(1) subexpression expansion.
- * Return:
- * -1 if error, or the number of characters added to the destination.
- */
-
-static int
-resub(regex_t *rp, regmatch_t *pm, char *src, char *inpt, char *dest,
- char *destend)
-{
- char *spt;
- char *dpt;
- char c;
- regmatch_t *pmpt;
- int len;
- int subexcnt;
-
- spt = src;
- dpt = dest;
- subexcnt = rp->re_nsub;
- while ((dpt < destend) && ((c = *spt++) != '\0')) {
- /*
- * see if we just have an ordinary replacement character
- * or we refer to a subexpression.
- */
- if (c == '&') {
- pmpt = pm;
- } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
- /*
- * make sure there is a subexpression as specified
- */
- if ((len = *spt++ - '0') > subexcnt)
- return(-1);
- pmpt = pm + len;
- } else {
- /*
- * Ordinary character, just copy it
- */
- if ((c == '\\') && (*spt != '\0'))
- c = *spt++;
- *dpt++ = c;
- continue;
- }
-
- /*
- * continue if the subexpression is bogus
- */
- if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
- ((len = pmpt->rm_eo - pmpt->rm_so) <= 0))
- continue;
-
- /*
- * copy the subexpression to the destination.
- * fail if we run out of space or the match string is damaged
- */
- if (len > (destend - dpt))
- return (-1);
- strncpy(dpt, inpt + pmpt->rm_so, len);
- dpt += len;
- }
- return(dpt - dest);
-}
diff --git a/pax/pat_rep.h b/pax/pat_rep.h
@@ -1,49 +0,0 @@
-/* $OpenBSD: pat_rep.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */
-/* $NetBSD: pat_rep.h,v 1.3 1995/03/21 09:07:35 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)pat_rep.h 8.1 (Berkeley) 5/31/93
- */
-
-/*
- * data structure for storing user supplied replacement strings (-s)
- */
-typedef struct replace {
- char *nstr; /* the new string we will substitute with */
- regex_t rcmp; /* compiled regular expression used to match */
- int flgs; /* print conversions? global in operation? */
-#define PRNT 0x1
-#define GLOB 0x2
- struct replace *fow; /* pointer to next pattern */
-} REPLACE;
diff --git a/pax/pax.1 b/pax/pax.1
@@ -1,1165 +0,0 @@
-.\" $OpenBSD: pax.1,v 1.61 2010/09/19 20:55:25 jmc Exp $
-.\" $NetBSD: pax.1,v 1.3 1995/03/21 09:07:37 cgd Exp $
-.\"
-.\" Copyright (c) 1992 Keith Muller.
-.\" Copyright (c) 1992, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Keith Muller of the University of California, San Diego.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" @(#)pax.1 8.4 (Berkeley) 4/18/94
-.\"
-.Dd $Mdocdate: September 19 2010 $
-.Dt PAX 1
-.Os
-.Sh NAME
-.Nm pax
-.Nd read and write file archives and copy directory hierarchies
-.Sh SYNOPSIS
-.Bk -words
-.Nm pax
-.Op Fl 0cdjnOvz
-.Op Fl E Ar limit
-.Op Fl f Ar archive
-.Op Fl G Ar group
-.Op Fl s Ar replstr
-.Op Fl T Ar range
-.Op Fl U Ar user
-.Op Ar pattern ...
-.Nm pax
-.Fl r
-.Op Fl 0cDdijknOuvYZz
-.Op Fl E Ar limit
-.Op Fl f Ar archive
-.Op Fl G Ar group
-.Op Fl o Ar options
-.Op Fl p Ar string
-.Op Fl s Ar replstr
-.Op Fl T Ar range
-.Op Fl U Ar user
-.Op Ar pattern ...
-.Nm pax
-.Fl w
-.Op Fl 0adHijLOPtuvXz
-.Op Fl B Ar bytes
-.Op Fl b Ar blocksize
-.Op Fl f Ar archive
-.Op Fl G Ar group
-.Op Fl o Ar options
-.Op Fl s Ar replstr
-.Op Fl T Ar range
-.Op Fl U Ar user
-.Op Fl x Ar format
-.Op Ar
-.Nm pax
-.Fl rw
-.Op Fl 0DdHijkLlnOPtuvXYZ
-.Op Fl G Ar group
-.Op Fl p Ar string
-.Op Fl s Ar replstr
-.Op Fl T Ar range
-.Op Fl U Ar user
-.Op Ar
-.Ar directory
-.Ek
-.Sh DESCRIPTION
-.Nm
-will read, write, and list the members of an archive file
-and will copy directory hierarchies.
-.Nm
-operation is independent of the specific archive format
-and supports a wide variety of different archive formats.
-A list of supported archive formats can be found under the description of the
-.Fl x
-option.
-.Pp
-The presence of the
-.Fl r
-and the
-.Fl w
-options specifies which of the following functional modes
-.Nm
-will operate under:
-.Em list , read , write ,
-and
-.Em copy .
-.Bl -tag -width 6n
-.It \*(Ltnone\*(Gt
-.Em List .
-.Nm
-will write to standard output
-a table of contents of the members of the archive file read from
-standard input, whose pathnames match the specified
-.Ar pattern
-arguments.
-The table of contents contains one filename per line
-and is written using single line buffering.
-.It Fl r
-.Em Read .
-.Nm
-extracts the members of the archive file read from the standard input,
-with pathnames matching the specified
-.Ar pattern
-arguments.
-The archive format and blocking is automatically determined on input.
-When an extracted file is a directory, the entire file hierarchy
-rooted at that directory is extracted.
-All extracted files are created relative to the current file hierarchy.
-The setting of ownership, access and modification times, and file mode of
-the extracted files are discussed in more detail under the
-.Fl p
-option.
-.It Fl w
-.Em Write .
-.Nm
-writes an archive containing the
-.Ar file
-operands to standard output
-using the specified archive format.
-When no
-.Ar file
-operands are specified, a list of files to copy with one per line is read from
-standard input.
-When a
-.Ar file
-operand is also a directory, the entire file hierarchy rooted
-at that directory will be included.
-.It Fl rw
-.Em Copy .
-.Nm
-copies the
-.Ar file
-operands to the destination
-.Ar directory .
-When no
-.Ar file
-operands are specified, a list of files to copy with one per line is read from
-the standard input.
-When a
-.Ar file
-operand is also a directory the entire file
-hierarchy rooted at that directory will be included.
-The effect of the
-.Em copy
-is as if the copied files were written to an archive file and then
-subsequently extracted, except that there may be hard links between
-the original and the copied files (see the
-.Fl l
-option below).
-.Pp
-.Sy Warning :
-The destination
-.Ar directory
-must not be one of the
-.Ar file
-operands or a member of a file hierarchy rooted at one of the
-.Ar file
-operands.
-The result of a
-.Em copy
-under these conditions is unpredictable.
-.El
-.Pp
-While processing a damaged archive during a
-.Em read
-or
-.Em list
-operation,
-.Nm
-will attempt to recover from media defects and will search through the archive
-to locate and process the largest number of archive members possible (see the
-.Fl E
-option for more details on error handling).
-.Pp
-The
-.Ar directory
-operand specifies a destination directory pathname.
-If the
-.Ar directory
-operand does not exist, or it is not writable by the user,
-or it is not of type directory,
-.Nm
-will exit with a non-zero exit status.
-.Pp
-The
-.Ar pattern
-operand is used to select one or more pathnames of archive members.
-Archive members are selected using the pattern matching notation described
-by
-.Xr glob 3 .
-When the
-.Ar pattern
-operand is not supplied, all members of the archive will be selected.
-When a
-.Ar pattern
-matches a directory, the entire file hierarchy rooted at that directory will
-be selected.
-When a
-.Ar pattern
-operand does not select at least one archive member,
-.Nm
-will write these
-.Ar pattern
-operands in a diagnostic message to standard error
-and then exit with a non-zero exit status.
-.Pp
-The
-.Ar file
-operand specifies the pathname of a file to be copied or archived.
-When a
-.Ar file
-operand does not select at least one archive member,
-.Nm
-will write these
-.Ar file
-operand pathnames in a diagnostic message to standard error
-and then exit with a non-zero exit status.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl 0
-Use the NUL
-.Pq Ql \e0
-character as a pathname terminator, instead of newline
-.Pq Ql \en .
-This applies only to the pathnames read from standard input in
-the write and copy modes,
-and to the pathnames written to standard output in list mode.
-This option is expected to be used in concert with the
-.Fl print0
-function in
-.Xr find 1
-or the
-.Fl 0
-flag in
-.Xr xargs 1 .
-.It Fl a
-Append the given
-.Ar file
-operands
-to the end of an archive that was previously written.
-If an archive format is not specified with a
-.Fl x
-option, the format currently being used in the archive will be selected.
-Any attempt to append to an archive in a format different from the
-format already used in the archive will cause
-.Nm
-to exit immediately
-with a non-zero exit status.
-The blocking size used in the archive volume where writing starts
-will continue to be used for the remainder of that archive volume.
-.Pp
-.Sy Warning :
-Many storage devices are not able to support the operations necessary
-to perform an append operation.
-Any attempt to append to an archive stored on such a device may damage the
-archive or have other unpredictable results.
-Tape drives in particular are more likely to not support an append operation.
-An archive stored in a regular file system file or on a disk device will
-usually support an append operation.
-.It Fl B Ar bytes
-Limit the number of bytes written to a single archive volume to
-.Ar bytes .
-The
-.Ar bytes
-limit can end with
-.Sq Li m ,
-.Sq Li k ,
-or
-.Sq Li b
-to specify multiplication by 1048576 (1M), 1024 (1K) or 512, respectively.
-A pair of
-.Ar bytes
-limits can be separated by
-.Sq Li x
-to indicate a product.
-.Pp
-.Em Warning :
-Only use this option when writing an archive to a device which supports
-an end of file read condition based on last (or largest) write offset
-(such as a regular file or a tape drive).
-The use of this option with a floppy or hard disk is not recommended.
-.It Fl b Ar blocksize
-When
-.Em writing
-an archive,
-block the output at a positive decimal integer number of
-bytes per write to the archive file.
-The
-.Ar blocksize
-must be a multiple of 512 bytes with a maximum of 64512 bytes.
-Archive block sizes larger than 32256 bytes violate the
-.Tn POSIX
-standard and will not be portable to all systems.
-A
-.Ar blocksize
-can end with
-.Sq Li k
-or
-.Sq Li b
-to specify multiplication by 1024 (1K) or 512, respectively.
-A pair of
-.Ar blocksizes
-can be separated by
-.Sq Li x
-to indicate a product.
-A specific archive device may impose additional restrictions on the size
-of blocking it will support.
-When blocking is not specified, the default
-.Ar blocksize
-is dependent on the specific archive format being used (see the
-.Fl x
-option).
-.It Fl c
-Match all file or archive members
-.Em except
-those specified by the
-.Ar pattern
-and
-.Ar file
-operands.
-.It Fl D
-This option is the same as the
-.Fl u
-option, except that the file inode change time is checked instead of the
-file modification time.
-The file inode change time can be used to select files whose inode information
-(e.g., UID, GID, etc.) is newer than a copy of the file in the destination
-.Ar directory .
-.It Fl d
-Cause files of type directory being copied or archived, or archive members of
-type directory being extracted, to match only the directory file or archive
-member and not the file hierarchy rooted at the directory.
-.It Fl E Ar limit
-Limit the number of consecutive read faults while trying to read a flawed
-archive to
-.Ar limit .
-With a positive
-.Ar limit ,
-.Nm
-will attempt to recover from an archive read error and will
-continue processing starting with the next file stored in the archive.
-A
-.Ar limit
-of 0 will cause
-.Nm
-to stop operation after the first read error is detected on an archive volume.
-A
-.Ar limit
-of
-.Li NONE
-will cause
-.Nm
-to attempt to recover from read errors forever.
-The default
-.Ar limit
-is a small positive number of retries.
-.Pp
-.Em Warning :
-Using this option with
-.Li NONE
-should be used with extreme caution as
-.Nm
-may get stuck in an infinite loop on a very badly flawed archive.
-.It Fl f Ar archive
-Specify
-.Ar archive
-as the pathname of the input or output archive, overriding the default
-standard input (for
-.Em list
-and
-.Em read )
-or standard output
-(for
-.Em write ) .
-A single archive may span multiple files and different archive devices.
-When required,
-.Nm
-will prompt for the pathname of the file or device of the next volume in the
-archive.
-.It Fl G Ar group
-Select a file based on its
-.Ar group
-name, or when starting with a
-.Cm # ,
-a numeric GID.
-A
-.Ql \e
-can be used to escape the
-.Cm # .
-Multiple
-.Fl G
-options may be supplied and checking stops with the first match.
-.It Fl H
-Follow only command-line symbolic links while performing a physical file
-system traversal.
-.It Fl i
-Interactively rename files or archive members.
-For each archive member matching a
-.Ar pattern
-operand or each file matching a
-.Ar file
-operand,
-.Nm
-will prompt to
-.Pa /dev/tty
-giving the name of the file, its file mode, and its modification time.
-.Nm
-will then read a line from
-.Pa /dev/tty .
-If this line is blank, the file or archive member is skipped.
-If this line consists of a single period, the
-file or archive member is processed with no modification to its name.
-Otherwise, its name is replaced with the contents of the line.
-.Nm
-will immediately exit with a non-zero exit status if
-.Dv EOF
-is encountered when reading a response or if
-.Pa /dev/tty
-cannot be opened for reading and writing.
-.It Fl j
-Use bzip2 to compress (decompress) the archive while writing (reading).
-The bzip2 utility must be installed separately.
-Incompatible with
-.Fl a .
-.It Fl k
-Do not overwrite existing files.
-.It Fl L
-Follow all symbolic links to perform a logical file system traversal.
-.It Fl l
-(The lowercase letter
-.Dq ell . )
-Link files.
-In the
-.Em copy
-mode
-.Pq Fl r Fl w ,
-hard links are made between the source and destination file hierarchies
-whenever possible.
-.It Fl n
-Select the first archive member that matches each
-.Ar pattern
-operand.
-No more than one archive member is matched for each
-.Ar pattern .
-When members of type directory are matched, the file hierarchy rooted at that
-directory is also matched (unless
-.Fl d
-is also specified).
-.It Fl O
-Force the archive to be one volume.
-If a volume ends prematurely,
-.Nm
-will not prompt for a new volume.
-This option can be useful for
-automated tasks where error recovery cannot be performed by a human.
-.It Fl o Ar options
-Information to modify the algorithm for extracting or writing archive files
-which is specific to the archive format specified by
-.Fl x .
-In general,
-.Ar options
-take the form:
-.Ar name Ns = Ns Ar value .
-.Pp
-The following options are available for the old
-.Bx
-.Em tar
-format:
-.Pp
-.Bl -tag -width Ds -compact
-.It Cm nodir
-.It Cm write_opt=nodir
-When writing archives, omit the storage of directories.
-.El
-.It Fl P
-Do not follow symbolic links, perform a physical file system traversal.
-This is the default mode.
-.It Fl p Ar string
-Specify one or more file characteristic options (privileges).
-The
-.Ar string
-option-argument is a string specifying file characteristics to be retained or
-discarded on extraction.
-The string consists of the specification characters
-.Cm a , e , m , o ,
-and
-.Cm p .
-Multiple characteristics can be concatenated within the same string
-and multiple
-.Fl p
-options can be specified.
-The meanings of the specification characters are as follows:
-.Bl -tag -width 2n
-.It Cm a
-Do not preserve file access times.
-By default, file access times are preserved whenever possible.
-.It Cm e
-.Dq Preserve everything ,
-the user ID, group ID, file mode bits,
-file access time, and file modification time.
-This is intended to be used by
-.Em root ,
-someone with all the appropriate privileges, in order to preserve all
-aspects of the files as they are recorded in the archive.
-The
-.Cm e
-flag is the sum of the
-.Cm o
-and
-.Cm p
-flags.
-.It Cm m
-Do not preserve file modification times.
-By default, file modification times are preserved whenever possible.
-.It Cm o
-Preserve the user ID and group ID.
-.It Cm p
-.Dq Preserve
-the file mode bits.
-This is intended to be used by a
-.Em user
-with regular privileges who wants to preserve all aspects of the file other
-than the ownership.
-The file times are preserved by default, but two other flags are offered to
-disable this and use the time of extraction instead.
-.El
-.Pp
-In the preceding list,
-.Sq preserve
-indicates that an attribute stored in the archive is given to the
-extracted file, subject to the permissions of the invoking
-process.
-Otherwise the attribute of the extracted file is determined as
-part of the normal file creation action.
-If neither the
-.Cm e
-nor the
-.Cm o
-specification character is specified, or the user ID and group ID are not
-preserved for any reason,
-.Nm
-will not set the
-.Dv S_ISUID
-.Em ( setuid )
-and
-.Dv S_ISGID
-.Em ( setgid )
-bits of the file mode.
-If the preservation of any of these items fails for any reason,
-.Nm
-will write a diagnostic message to standard error.
-Failure to preserve these items will affect the final exit status,
-but will not cause the extracted file to be deleted.
-If the file characteristic letters in any of the string option-arguments are
-duplicated or conflict with each other, the one(s) given last will take
-precedence.
-For example, if
-.Fl p Ar eme
-is specified, file modification times are still preserved.
-.It Fl r
-Read an archive file from standard input
-and extract the specified
-.Ar file
-operands.
-If any intermediate directories are needed in order to extract an archive
-member, these directories will be created as if
-.Xr mkdir 2
-was called with the bitwise inclusive
-.Tn OR
-of
-.Dv S_IRWXU , S_IRWXG ,
-and
-.Dv S_IRWXO
-as the mode argument.
-When the selected archive format supports the specification of linked
-files and these files cannot be linked while the archive is being extracted,
-.Nm
-will write a diagnostic message to standard error
-and exit with a non-zero exit status at the completion of operation.
-.It Fl s Ar replstr
-Modify the archive member names according to the substitution expression
-.Ar replstr ,
-using the syntax of the
-.Xr ed 1
-utility regular expressions.
-.Ar file
-or
-.Ar pattern
-arguments may be given to restrict the list of archive members to those
-specified.
-.Pp
-The format of these regular expressions is:
-.Pp
-.Dl /old/new/[gp]
-.Pp
-As in
-.Xr ed 1 ,
-.Ar old
-is a basic regular expression (see
-.Xr re_format 7 )
-and
-.Ar new
-can contain an ampersand
-.Pq Ql & ,
-.Ql \e Ns Em n
-(where
-.Em n
-is a digit) back-references,
-or subexpression matching.
-The
-.Ar old
-string may also contain newline characters.
-Any non-null character can be used as a delimiter
-.Po
-.Ql /
-is shown here
-.Pc .
-Multiple
-.Fl s
-expressions can be specified.
-The expressions are applied in the order they are specified on the
-command line, terminating with the first successful substitution.
-.Pp
-The optional trailing
-.Cm g
-continues to apply the substitution expression to the pathname substring,
-which starts with the first character following the end of the last successful
-substitution.
-The first unsuccessful substitution stops the operation of the
-.Cm g
-option.
-The optional trailing
-.Cm p
-will cause the final result of a successful substitution to be written to
-standard error in the following format:
-.Pp
-.D1 Em original-pathname No \*(Gt\*(Gt Em new-pathname
-.Pp
-File or archive member names that substitute to the empty string
-are not selected and will be skipped.
-.It Fl T Ar range
-Allow files to be selected based on a file modification or inode change
-time falling within the specified time range.
-The range has the format:
-.Sm off
-.Bd -filled -offset indent
-.Op Ar from_date
-.Op \&, Ar to_date
-.Op / Oo Cm c Oc Op Cm m
-.Ed
-.Sm on
-.Pp
-The dates specified by
-.Ar from_date
-to
-.Ar to_date
-are inclusive.
-If only a
-.Ar from_date
-is supplied, all files with a modification or inode change time
-equal to or younger are selected.
-If only a
-.Ar to_date
-is supplied, all files with a modification or inode change time
-equal to or older will be selected.
-When the
-.Ar from_date
-is equal to the
-.Ar to_date ,
-only files with a modification or inode change time of exactly that
-time will be selected.
-.Pp
-When
-.Nm
-is in the
-.Em write
-or
-.Em copy
-mode, the optional trailing field
-.Oo Cm c Oc Ns Op Cm m
-can be used to determine which file time (inode change, file modification or
-both) are used in the comparison.
-If neither is specified, the default is to use file modification time only.
-The
-.Cm m
-specifies the comparison of file modification time (the time when
-the file was last written).
-The
-.Cm c
-specifies the comparison of inode change time (the time when the file
-inode was last changed; e.g., a change of owner, group, mode, etc).
-When
-.Cm c
-and
-.Cm m
-are both specified, then the modification and inode change times are
-both compared.
-.Pp
-The inode change time comparison is useful in selecting files whose
-attributes were recently changed or selecting files which were recently
-created and had their modification time reset to an older time (as what
-happens when a file is extracted from an archive and the modification time
-is preserved).
-Time comparisons using both file times is useful when
-.Nm
-is used to create a time based incremental archive (only files that were
-changed during a specified time range will be archived).
-.Pp
-A time range is made up of six different fields and each field must contain two
-digits.
-The format is:
-.Pp
-.Dl [[[[[cc]yy]mm]dd]HH]MM[.SS]
-.Pp
-Where
-.Ar cc
-is the first two digits of the year (the century),
-.Ar yy
-is the last two digits of the year,
-the first
-.Ar mm
-is the month (from 01 to 12),
-.Ar dd
-is the day of the month (from 01 to 31),
-.Ar HH
-is the hour of the day (from 00 to 23),
-.Ar MM
-is the minute (from 00 to 59),
-and
-.Ar SS
-is the seconds (from 00 to 59).
-The minute field
-.Ar MM
-is required, while the other fields are optional and must be added in the
-following order:
-.Ar HH , dd , mm ,
-.Ar yy , cc .
-.Pp
-The
-.Ar SS
-field may be added independently of the other fields.
-Time ranges are relative to the current time, so
-.Ic -T 1234/cm
-would select all files with a modification or inode change time
-of 12:34 PM today or later.
-Multiple
-.Fl T
-time range can be supplied and checking stops with the first match.
-.It Fl t
-Reset the access times of any file or directory read or accessed by
-.Nm
-to be the same as they were before being read or accessed by
-.Nm pax .
-.It Fl U Ar user
-Select a file based on its
-.Ar user
-name, or when starting with a
-.Cm # ,
-a numeric UID.
-A
-.Ql \e
-can be used to escape the
-.Cm # .
-Multiple
-.Fl U
-options may be supplied and checking stops with the first match.
-.It Fl u
-Ignore files that are older (having a less recent file modification time)
-than a pre-existing file or archive member with the same name.
-During
-.Em read ,
-an archive member with the same name as a file in the file system will be
-extracted if the archive member is newer than the file.
-During
-.Em write ,
-a file system member with the same name as an archive member will be
-written to the archive if it is newer than the archive member.
-During
-.Em copy ,
-the file in the destination hierarchy is replaced by the file in the source
-hierarchy or by a link to the file in the source hierarchy if the file in
-the source hierarchy is newer.
-.It Fl v
-During a
-.Em list
-operation, produce a verbose table of contents using the format of the
-.Xr ls 1
-utility with the
-.Fl l
-option.
-For pathnames representing a hard link to a previous member of the archive,
-the output has the format:
-.Pp
-.Dl Em ls -l listing Li == Em link-name
-.Pp
-For pathnames representing a symbolic link, the output has the format:
-.Pp
-.Dl Em ls -l listing Li =\*(Gt Em link-name
-.Pp
-Where
-.Em ls -l listing
-is the output format specified by the
-.Xr ls 1
-utility when used with the
-.Fl l
-option.
-Otherwise for all the other operational modes
-.Po Em read , write , No and Em copy
-.Pc ,
-pathnames are written and flushed to standard error
-without a trailing newline
-as soon as processing begins on that file or
-archive member.
-The trailing newline
-is not buffered and is written only after the file has been read or written.
-.It Fl w
-Write files to the standard output
-in the specified archive format.
-When no
-.Ar file
-operands are specified, standard input
-is read for a list of pathnames with one per line without any leading or
-trailing
-.Aq blanks .
-.It Fl X
-When traversing the file hierarchy specified by a pathname,
-do not descend into directories that have a different device ID.
-See the
-.Li st_dev
-field as described in
-.Xr stat 2
-for more information about device IDs.
-.It Fl x Ar format
-Specify the output archive format, with the default format being
-.Cm ustar .
-.Nm
-currently supports the following formats:
-.Bl -tag -width "sv4cpio"
-.It Cm bcpio
-The old binary cpio format.
-The default blocksize for this format is 5120 bytes.
-This format is not very portable and should not be used when other formats
-are available.
-Inode and device information about a file (used for detecting file hard links
-by this format), which may be truncated by this format, is detected by
-.Nm
-and is repaired.
-.It Cm cpio
-The extended cpio interchange format specified in the
-.St -p1003.2
-standard.
-The default blocksize for this format is 5120 bytes.
-Inode and device information about a file (used for detecting file hard links
-by this format), which may be truncated by this format, is detected by
-.Nm
-and is repaired.
-.It Cm sv4cpio
-The System V release 4 cpio.
-The default blocksize for this format is 5120 bytes.
-Inode and device information about a file (used for detecting file hard links
-by this format), which may be truncated by this format, is detected by
-.Nm
-and is repaired.
-.It Cm sv4crc
-The System V release 4 cpio with file CRC checksums.
-The default blocksize for this format is 5120 bytes.
-Inode and device information about a file (used for detecting file hard links
-by this format), which may be truncated by this format, is detected by
-.Nm
-and is repaired.
-.It Cm tar
-The old
-.Bx
-tar format as found in
-.Bx 4.3 .
-The default blocksize for this format is 10240 bytes.
-Pathnames stored by this format must be 100 characters or less in length.
-Only
-.Em regular
-files,
-.Em hard links , soft links ,
-and
-.Em directories
-will be archived (other file system types are not supported).
-For backwards compatibility with even older tar formats, a
-.Fl o
-option can be used when writing an archive to omit the storage of directories.
-This option takes the form:
-.Pp
-.Dl Fl o Cm write_opt=nodir
-.It Cm ustar
-The extended tar interchange format specified in the
-.St -p1003.2
-standard.
-The default blocksize for this format is 10240 bytes.
-Filenames stored by this format must be 100 characters or less in length;
-the total pathname must be 256 characters or less.
-.El
-.Pp
-.Nm
-will detect and report any file that it is unable to store or extract
-as the result of any specific archive format restrictions.
-The individual archive formats may impose additional restrictions on use.
-Typical archive format restrictions include (but are not limited to):
-file pathname length, file size, link pathname length, and the type of the
-file.
-.It Fl Y
-This option is the same as the
-.Fl D
-option, except that the inode change time is checked using the
-pathname created after all the file name modifications have completed.
-.It Fl Z
-This option is the same as the
-.Fl u
-option, except that the modification time is checked using the
-pathname created after all the file name modifications have completed.
-.It Fl z
-Use
-.Xr gzip 1
-to compress (decompress) the archive while writing (reading).
-Incompatible with
-.Fl a .
-.El
-.Pp
-The options that operate on the names of files or archive members
-.Po Fl c ,
-.Fl i ,
-.Fl j ,
-.Fl n ,
-.Fl s ,
-.Fl u ,
-.Fl v ,
-.Fl D ,
-.Fl G ,
-.Fl T ,
-.Fl U ,
-.Fl Y ,
-and
-.Fl Z
-.Pc
-interact as follows.
-.Pp
-When extracting files during a
-.Em read
-operation, archive members are
-.Sq selected ,
-based only on the user specified pattern operands as modified by the
-.Fl c ,
-.Fl n ,
-.Fl u ,
-.Fl D ,
-.Fl G ,
-.Fl T ,
-.Fl U
-options.
-Then any
-.Fl s
-and
-.Fl i
-options will modify in that order, the names of these selected files.
-Then the
-.Fl Y
-and
-.Fl Z
-options will be applied based on the final pathname.
-Finally, the
-.Fl v
-option will write the names resulting from these modifications.
-.Pp
-When archiving files during a
-.Em write
-operation, or copying files during a
-.Em copy
-operation, archive members are
-.Sq selected ,
-based only on the user specified pathnames as modified by the
-.Fl n ,
-.Fl u ,
-.Fl D ,
-.Fl G ,
-.Fl T ,
-and
-.Fl U
-options (the
-.Fl D
-option only applies during a copy operation).
-Then any
-.Fl s
-and
-.Fl i
-options will modify in that order, the names of these selected files.
-Then during a
-.Em copy
-operation the
-.Fl Y
-and the
-.Fl Z
-options will be applied based on the final pathname.
-Finally, the
-.Fl v
-option will write the names resulting from these modifications.
-.Pp
-When one or both of the
-.Fl u
-or
-.Fl D
-options are specified along with the
-.Fl n
-option, a file is not considered selected unless it is newer
-than the file to which it is compared.
-.Sh ENVIRONMENT
-.Bl -tag -width Fl
-.It Ev TMPDIR
-Path in which to store temporary files.
-.El
-.Sh EXIT STATUS
-The
-.Nm
-utility exits with one of the following values:
-.Pp
-.Bl -tag -width Ds -offset indent -compact
-.It 0
-All files were processed successfully.
-.It 1
-An error occurred.
-.El
-.Sh EXAMPLES
-Copy the contents of the current directory to the device
-.Pa /dev/rst0 :
-.Pp
-.Dl $ pax -w -f /dev/rst0 \&.
-.Pp
-Give the verbose table of contents for an archive stored in
-.Pa filename :
-.Pp
-.Dl $ pax -v -f filename
-.Pp
-This sequence of commands will copy the entire
-.Pa olddir
-directory hierarchy to
-.Pa newdir :
-.Bd -literal -offset indent
-$ mkdir newdir
-$ cd olddir
-$ pax -rw . ../newdir
-.Ed
-.Pp
-Extract files from the archive
-.Pa a.pax .
-Files rooted in
-.Pa /usr
-are extracted relative to the current working directory;
-all other files are extracted to their unmodified path.
-.Pp
-.Dl $ pax -r -s ',^/usr/,,' -f a.pax
-.Pp
-This can be used to interactively select the files to copy from the
-current directory to
-.Pa dest_dir :
-.Pp
-.Dl $ pax -rw -i \&. dest_dir
-.Pp
-Extract all files from the archive
-.Pa a.pax
-which are owned by
-.Em root
-with group
-.Em bin
-and preserve all file permissions:
-.Pp
-.Dl "$ pax -r -pe -U root -G bin -f a.pax"
-.Pp
-Update (and list) only those files in the destination directory
-.Pa /backup
-which are older (less recent inode change or file modification times) than
-files with the same name found in the source file tree
-.Pa home :
-.Pp
-.Dl "$ pax -r -w -v -Y -Z home /backup"
-.Sh DIAGNOSTICS
-Whenever
-.Nm
-cannot create a file or a link when reading an archive or cannot
-find a file when writing an archive, or cannot preserve the user ID,
-group ID, or file mode when the
-.Fl p
-option is specified, a diagnostic message is written to standard error
-and a non-zero exit status will be returned, but processing will continue.
-In the case where
-.Nm
-cannot create a link to a file,
-.Nm
-will not create a second copy of the file.
-.Pp
-If the extraction of a file from an archive is prematurely terminated by
-a signal or error,
-.Nm
-may have only partially extracted a file the user wanted.
-Additionally, the file modes of extracted files and directories
-may have incorrect file bits, and the modification and access times may be
-wrong.
-.Pp
-If the creation of an archive is prematurely terminated by a signal or error,
-.Nm
-may have only partially created the archive, which may violate the specific
-archive format specification.
-.Pp
-If while doing a
-.Em copy ,
-.Nm
-detects a file is about to overwrite itself, the file is not copied,
-a diagnostic message is written to standard error
-and when
-.Nm
-completes it will exit with a non-zero exit status.
-.Sh SEE ALSO
-.Xr cpio 1 ,
-.Xr tar 1
-.Sh STANDARDS
-The
-.Nm
-utility is compliant with the
-.St -p1003.1-2008
-specification.
-.Pp
-The flags
-.Op Fl 0BDEGjOPTUYZz ,
-the archive formats
-.Em bcpio ,
-.Em sv4cpio ,
-.Em sv4crc ,
-.Em tar ,
-and the flawed archive handling during
-.Em list
-and
-.Em read
-operations
-are extensions to that specification.
-.Sh AUTHORS
-Keith Muller at the University of California, San Diego.
diff --git a/pax/pax.c b/pax/pax.c
@@ -1,429 +0,0 @@
-/* $OpenBSD: pax.c,v 1.33 2012/04/19 04:26:46 deraadt Exp $ */
-/* $NetBSD: pax.c,v 1.5 1996/03/26 23:54:20 mrg Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <err.h>
-#include <fcntl.h>
-#include <paths.h>
-#include "pax.h"
-#include "extern.h"
-static int gen_init(void);
-
-/*
- * PAX main routines, general globals and some simple start up routines
- */
-
-/*
- * Variables that can be accessed by any routine within pax
- */
-int act = DEFOP; /* read/write/append/copy */
-FSUB *frmt = NULL; /* archive format type */
-int cflag; /* match all EXCEPT pattern/file */
-int cwdfd; /* starting cwd */
-int dflag; /* directory member match only */
-int iflag; /* interactive file/archive rename */
-int kflag; /* do not overwrite existing files */
-int lflag; /* use hard links when possible */
-int nflag; /* select first archive member match */
-int tflag; /* restore access time after read */
-int uflag; /* ignore older modification time files */
-int vflag; /* produce verbose output */
-int Dflag; /* same as uflag except inode change time */
-int Hflag; /* follow command line symlinks (write only) */
-int Lflag; /* follow symlinks when writing */
-int Nflag; /* only use numeric uid and gid */
-int Xflag; /* archive files with same device id only */
-int Yflag; /* same as Dflag except after name mode */
-int Zflag; /* same as uflag except after name mode */
-int zeroflag; /* use \0 as pathname terminator */
-int vfpart; /* is partial verbose output in progress */
-int patime = 1; /* preserve file access time */
-int pmtime = 1; /* preserve file modification times */
-int nodirs; /* do not create directories as needed */
-int pmode; /* preserve file mode bits */
-int pids; /* preserve file uid/gid */
-int rmleadslash = 0; /* remove leading '/' from pathnames */
-int exit_val; /* exit value */
-int docrc; /* check/create file crc */
-char *dirptr; /* destination dir in a copy */
-char *ltmfrmt; /* -v locale time format (if any) */
-char *argv0; /* root of argv[0] */
-sigset_t s_mask; /* signal mask for cleanup critical sect */
-FILE *listf; /* file pointer to print file list to */
-char *tempfile; /* tempfile to use for mkstemp(3) */
-char *tempbase; /* basename of tempfile to use for mkstemp(3) */
-
-/*
- * PAX - Portable Archive Interchange
- *
- * A utility to read, write, and write lists of the members of archive
- * files and copy directory hierarchies. A variety of archive formats
- * are supported (some are described in POSIX 1003.1 10.1):
- *
- * ustar - 10.1.1 extended tar interchange format
- * cpio - 10.1.2 extended cpio interchange format
- * tar - old BSD 4.3 tar format
- * binary cpio - old cpio with binary header format
- * sysVR4 cpio - with and without CRC
- *
- * This version is a superset of IEEE Std 1003.2b-d3
- *
- * Summary of Extensions to the IEEE Standard:
- *
- * 1 READ ENHANCEMENTS
- * 1.1 Operations which read archives will continue to operate even when
- * processing archives which may be damaged, truncated, or fail to meet
- * format specs in several different ways. Damaged sections of archives
- * are detected and avoided if possible. Attempts will be made to resync
- * archive read operations even with badly damaged media.
- * 1.2 Blocksize requirements are not strictly enforced on archive read.
- * Tapes which have variable sized records can be read without errors.
- * 1.3 The user can specify via the non-standard option flag -E if error
- * resync operation should stop on a media error, try a specified number
- * of times to correct, or try to correct forever.
- * 1.4 Sparse files (lseek holes) stored on the archive (but stored with blocks
- * of all zeros will be restored with holes appropriate for the target
- * filesystem
- * 1.5 The user is notified whenever something is found during archive
- * read operations which violates spec (but the read will continue).
- * 1.6 Multiple archive volumes can be read and may span over different
- * archive devices
- * 1.7 Rigidly restores all file attributes exactly as they are stored on the
- * archive.
- * 1.8 Modification change time ranges can be specified via multiple -T
- * options. These allow a user to select files whose modification time
- * lies within a specific time range.
- * 1.9 Files can be selected based on owner (user name or uid) via one or more
- * -U options.
- * 1.10 Files can be selected based on group (group name or gid) via one o
- * more -G options.
- * 1.11 File modification time can be checked against existing file after
- * name modification (-Z)
- *
- * 2 WRITE ENHANCEMENTS
- * 2.1 Write operation will stop instead of allowing a user to create a flawed
- * flawed archive (due to any problem).
- * 2.2 Archives written by pax are forced to strictly conform to both the
- * archive and pax the specific format specifications.
- * 2.3 Blocking size and format is rigidly enforced on writes.
- * 2.4 Formats which may exhibit header overflow problems (they have fields
- * too small for large file systems, such as inode number storage), use
- * routines designed to repair this problem. These techniques still
- * conform to both pax and format specifications, but no longer truncate
- * these fields. This removes any restrictions on using these archive
- * formats on large file systems.
- * 2.5 Multiple archive volumes can be written and may span over different
- * archive devices
- * 2.6 A archive volume record limit allows the user to specify the number
- * of bytes stored on an archive volume. When reached the user is
- * prompted for the next archive volume. This is specified with the
- * non-standard -B flag. The limit is rounded up to the next blocksize.
- * 2.7 All archive padding during write use zero filled sections. This makes
- * it much easier to pull data out of flawed archive during read
- * operations.
- * 2.8 Access time reset with the -t applies to all file nodes (including
- * directories).
- * 2.9 Symbolic links can be followed with -L (optional in the spec).
- * 2.10 Modification or inode change time ranges can be specified via
- * multiple -T options. These allow a user to select files whose
- * modification or inode change time lies within a specific time range.
- * 2.11 Files can be selected based on owner (user name or uid) via one or more
- * -U options.
- * 2.12 Files can be selected based on group (group name or gid) via one o
- * more -G options.
- * 2.13 Symlinks which appear on the command line can be followed (without
- * following other symlinks; -H flag)
- *
- * 3 COPY ENHANCEMENTS
- * 3.1 Sparse files (lseek holes) can be copied without expanding the holes
- * into zero filled blocks. The file copy is created with holes which are
- * appropriate for the target filesystem
- * 3.2 Access time as well as modification time on copied file trees can be
- * preserved with the appropriate -p options.
- * 3.3 Access time reset with the -t applies to all file nodes (including
- * directories).
- * 3.4 Symbolic links can be followed with -L (optional in the spec).
- * 3.5 Modification or inode change time ranges can be specified via
- * multiple -T options. These allow a user to select files whose
- * modification or inode change time lies within a specific time range.
- * 3.6 Files can be selected based on owner (user name or uid) via one or more
- * -U options.
- * 3.7 Files can be selected based on group (group name or gid) via one o
- * more -G options.
- * 3.8 Symlinks which appear on the command line can be followed (without
- * following other symlinks; -H flag)
- * 3.9 File inode change time can be checked against existing file before
- * name modification (-D)
- * 3.10 File inode change time can be checked against existing file after
- * name modification (-Y)
- * 3.11 File modification time can be checked against existing file after
- * name modification (-Z)
- *
- * 4 GENERAL ENHANCEMENTS
- * 4.1 Internal structure is designed to isolate format dependent and
- * independent functions. Formats are selected via a format driver table.
- * This encourages the addition of new archive formats by only having to
- * write those routines which id, read and write the archive header.
- */
-
-/*
- * main()
- * parse options, set up and operate as specified by the user.
- * any operational flaw will set exit_val to non-zero
- * Return: 0 if ok, 1 otherwise
- */
-
-int
-main(int argc, char **argv)
-{
- char *tmpdir;
- size_t tdlen;
- listf = stderr;
-
- /*
- * Keep a reference to cwd, so we can always come back home.
- */
- cwdfd = open(".", O_RDONLY);
- if (cwdfd < 0) {
- syswarn(1, errno, "Can't open current working directory.");
- return(exit_val);
- }
-
- /*
- * Where should we put temporary files?
- */
- if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
- tmpdir = _PATH_TMP;
- tdlen = strlen(tmpdir);
- while (tdlen > 0 && tmpdir[tdlen - 1] == '/')
- tdlen--;
- tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE));
- if (tempfile == NULL) {
- paxwarn(1, "Cannot allocate memory for temp file name.");
- return(exit_val);
- }
- if (tdlen)
- memcpy(tempfile, tmpdir, tdlen);
- tempbase = tempfile + tdlen;
- *tempbase++ = '/';
-
- /*
- * parse options, determine operational mode, general init
- */
- options(argc, argv);
- if ((gen_init() < 0) || (tty_init() < 0))
- return(exit_val);
-
- /*
- * select a primary operation mode
- */
- switch (act) {
- case EXTRACT:
- extract();
- break;
- case ARCHIVE:
- archive();
- break;
- case APPND:
- if (gzip_program != NULL)
- errx(1, "can not gzip while appending");
- append();
- break;
- case COPY:
- copy();
- break;
- default:
- case LIST:
- list();
- break;
- }
- return(exit_val);
-}
-
-/*
- * sig_cleanup()
- * when interrupted we try to do whatever delayed processing we can.
- * This is not critical, but we really ought to limit our damage when we
- * are aborted by the user.
- * Return:
- * never....
- */
-
-void
-sig_cleanup(int which_sig)
-{
- char errbuf[80];
-
- /*
- * restore modes and times for any dirs we may have created
- * or any dirs we may have read. Set vflag and vfpart so the user
- * will clearly see the message on a line by itself.
- */
- vflag = vfpart = 1;
-
- /* paxwarn() uses stdio; fake it as well as we can */
- if (which_sig == SIGXCPU)
- strlcpy(errbuf, "CPU time limit reached, cleaning up.\n",
- sizeof errbuf);
- else
- strlcpy(errbuf, "Signal caught, cleaning up.\n",
- sizeof errbuf);
- (void) write(STDERR_FILENO, errbuf, strlen(errbuf));
-
- ar_close(); /* XXX signal race */
- proc_dir(); /* XXX signal race */
- if (tflag)
- atdir_end(); /* XXX signal race */
- _exit(1);
-}
-
-/*
- * gen_init()
- * general setup routines. Not all are required, but they really help
- * when dealing with a medium to large sized archives.
- */
-
-static int
-gen_init(void)
-{
- struct rlimit reslimit;
- struct sigaction n_hand;
- struct sigaction o_hand;
-
- /*
- * Really needed to handle large archives. We can run out of memory for
- * internal tables really fast when we have a whole lot of files...
- */
- if (getrlimit(RLIMIT_DATA , &reslimit) == 0){
- reslimit.rlim_cur = reslimit.rlim_max;
- (void)setrlimit(RLIMIT_DATA , &reslimit);
- }
-
- /*
- * should file size limits be waived? if the os limits us, this is
- * needed if we want to write a large archive
- */
- if (getrlimit(RLIMIT_FSIZE , &reslimit) == 0){
- reslimit.rlim_cur = reslimit.rlim_max;
- (void)setrlimit(RLIMIT_FSIZE , &reslimit);
- }
-
- /*
- * increase the size the stack can grow to
- */
- if (getrlimit(RLIMIT_STACK , &reslimit) == 0){
- reslimit.rlim_cur = reslimit.rlim_max;
- (void)setrlimit(RLIMIT_STACK , &reslimit);
- }
-
- /*
- * not really needed, but doesn't hurt
- */
- if (getrlimit(RLIMIT_RSS , &reslimit) == 0){
- reslimit.rlim_cur = reslimit.rlim_max;
- (void)setrlimit(RLIMIT_RSS , &reslimit);
- }
-
- /*
- * Handle posix locale
- *
- * set user defines time printing format for -v option
- */
- ltmfrmt = getenv("LC_TIME");
-
- /*
- * signal handling to reset stored directory times and modes. Since
- * we deal with broken pipes via failed writes we ignore it. We also
- * deal with any file size limit through failed writes. Cpu time
- * limits are caught and a cleanup is forced.
- */
- if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) ||
- (sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) ||
- (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) ||
- (sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0)) {
- paxwarn(1, "Unable to set up signal mask");
- return(-1);
- }
- memset(&n_hand, 0, sizeof n_hand);
- n_hand.sa_mask = s_mask;
- n_hand.sa_flags = 0;
- n_hand.sa_handler = sig_cleanup;
-
- if ((sigaction(SIGHUP, &n_hand, &o_hand) < 0) ||
- (o_hand.sa_handler == SIG_IGN) &&
- (sigaction(SIGHUP, &o_hand, &o_hand) < 0))
- goto out;
-
- if ((sigaction(SIGTERM, &n_hand, &o_hand) < 0) ||
- (o_hand.sa_handler == SIG_IGN) &&
- (sigaction(SIGTERM, &o_hand, &o_hand) < 0))
- goto out;
-
- if ((sigaction(SIGINT, &n_hand, &o_hand) < 0) ||
- (o_hand.sa_handler == SIG_IGN) &&
- (sigaction(SIGINT, &o_hand, &o_hand) < 0))
- goto out;
-
- if ((sigaction(SIGQUIT, &n_hand, &o_hand) < 0) ||
- (o_hand.sa_handler == SIG_IGN) &&
- (sigaction(SIGQUIT, &o_hand, &o_hand) < 0))
- goto out;
-
- if ((sigaction(SIGXCPU, &n_hand, &o_hand) < 0) ||
- (o_hand.sa_handler == SIG_IGN) &&
- (sigaction(SIGXCPU, &o_hand, &o_hand) < 0))
- goto out;
-
- n_hand.sa_handler = SIG_IGN;
- if ((sigaction(SIGPIPE, &n_hand, &o_hand) < 0) ||
- (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0))
- goto out;
- return(0);
-
- out:
- syswarn(1, errno, "Unable to set up signal handler");
- return(-1);
-}
diff --git a/pax/pax.h b/pax/pax.h
@@ -1,244 +0,0 @@
-/* $OpenBSD: pax.h,v 1.17 2005/11/09 19:59:06 otto Exp $ */
-/* $NetBSD: pax.h,v 1.3 1995/03/21 09:07:41 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)pax.h 8.2 (Berkeley) 4/18/94
- */
-
-/*
- * BSD PAX global data structures and constants.
- */
-
-#define MAXBLK 64512 /* MAX blocksize supported (posix SPEC) */
- /* WARNING: increasing MAXBLK past 32256 */
- /* will violate posix spec. */
-#define MAXBLK_POSIX 32256 /* MAX blocksize supported as per POSIX */
-#define BLKMULT 512 /* blocksize must be even mult of 512 bytes */
- /* Don't even think of changing this */
-#define DEVBLK 8192 /* default read blksize for devices */
-#define FILEBLK 10240 /* default read blksize for files */
-#define PAXPATHLEN 3072 /* maximum path length for pax. MUST be */
- /* longer than the system MAXPATHLEN */
-
-/*
- * Pax modes of operation
- */
-#define LIST 0 /* List the file in an archive */
-#define EXTRACT 1 /* extract the files in an archive */
-#define ARCHIVE 2 /* write a new archive */
-#define APPND 3 /* append to the end of an archive */
-#define COPY 4 /* copy files to destination dir */
-#define DEFOP LIST /* if no flags default is to LIST */
-
-/*
- * Device type of the current archive volume
- */
-#define ISREG 0 /* regular file */
-#define ISCHR 1 /* character device */
-#define ISBLK 2 /* block device */
-#define ISTAPE 3 /* tape drive */
-#define ISPIPE 4 /* pipe/socket */
-
-/*
- * Pattern matching structure
- *
- * Used to store command line patterns
- */
-typedef struct pattern {
- char *pstr; /* pattern to match, user supplied */
- char *pend; /* end of a prefix match */
- char *chdname; /* the dir to change to if not NULL. */
- int plen; /* length of pstr */
- int flgs; /* processing/state flags */
-#define MTCH 0x1 /* pattern has been matched */
-#define DIR_MTCH 0x2 /* pattern matched a directory */
- struct pattern *fow; /* next pattern */
-} PATTERN;
-
-/*
- * General Archive Structure (used internal to pax)
- *
- * This structure is used to pass information about archive members between
- * the format independent routines and the format specific routines. When
- * new archive formats are added, they must accept requests and supply info
- * encoded in a structure of this type. The name fields are declared statically
- * here, as there is only ONE of these floating around, size is not a major
- * consideration. Eventually converting the name fields to a dynamic length
- * may be required if and when the supporting operating system removes all
- * restrictions on the length of pathnames it will resolve.
- */
-typedef struct {
- int nlen; /* file name length */
- char name[PAXPATHLEN+1]; /* file name */
- int ln_nlen; /* link name length */
- char ln_name[PAXPATHLEN+1]; /* name to link to (if any) */
- char *org_name; /* orig name in file system */
- PATTERN *pat; /* ptr to pattern match (if any) */
- struct stat sb; /* stat buffer see stat(2) */
- off_t pad; /* bytes of padding after file xfer */
- off_t skip; /* bytes of real data after header */
- /* IMPORTANT. The st_size field does */
- /* not always indicate the amount of */
- /* data following the header. */
- u_int32_t crc; /* file crc */
- int type; /* type of file node */
-#define PAX_DIR 1 /* directory */
-#define PAX_CHR 2 /* character device */
-#define PAX_BLK 3 /* block device */
-#define PAX_REG 4 /* regular file */
-#define PAX_SLK 5 /* symbolic link */
-#define PAX_SCK 6 /* socket */
-#define PAX_FIF 7 /* fifo */
-#define PAX_HLK 8 /* hard link */
-#define PAX_HRG 9 /* hard link to a regular file */
-#define PAX_CTG 10 /* high performance file */
-#define PAX_GLL 11 /* GNU long symlink */
-#define PAX_GLF 12 /* GNU long file */
-} ARCHD;
-
-/*
- * Format Specific Routine Table
- *
- * The format specific routine table allows new archive formats to be quickly
- * added. Overall pax operation is independent of the actual format used to
- * form the archive. Only those routines which deal directly with the archive
- * are tailored to the oddities of the specific format. All other routines are
- * independent of the archive format. Data flow in and out of the format
- * dependent routines pass pointers to ARCHD structure (described below).
- */
-typedef struct {
- char *name; /* name of format, this is the name the user */
- /* gives to -x option to select it. */
- int bsz; /* default block size. used when the user */
- /* does not specify a blocksize for writing */
- /* Appends continue to with the blocksize */
- /* the archive is currently using. */
- int hsz; /* Header size in bytes. this is the size of */
- /* the smallest header this format supports. */
- /* Headers are assumed to fit in a BLKMULT. */
- /* If they are bigger, get_head() and */
- /* get_arc() must be adjusted */
- int udev; /* does append require unique dev/ino? some */
- /* formats use the device and inode fields */
- /* to specify hard links. when members in */
- /* the archive have the same inode/dev they */
- /* are assumed to be hard links. During */
- /* append we may have to generate unique ids */
- /* to avoid creating incorrect hard links */
- int hlk; /* does archive store hard links info? if */
- /* not, we do not bother to look for them */
- /* during archive write operations */
- int blkalgn; /* writes must be aligned to blkalgn boundary */
- int inhead; /* is the trailer encoded in a valid header? */
- /* if not, trailers are assumed to be found */
- /* in invalid headers (i.e like tar) */
- int (*id)(char *, /* checks if a buffer is a valid header */
- int); /* returns 1 if it is, o.w. returns a 0 */
- int (*st_rd)(void); /* initialize routine for read. so format */
- /* can set up tables etc before it starts */
- /* reading an archive */
- int (*rd)(ARCHD *, /* read header routine. passed a pointer to */
- char *); /* ARCHD. It must extract the info from the */
- /* format and store it in the ARCHD struct. */
- /* This routine is expected to fill all the */
- /* fields in the ARCHD (including stat buf) */
- /* 0 is returned when a valid header is */
- /* found. -1 when not valid. This routine */
- /* set the skip and pad fields so the format */
- /* independent routines know the amount of */
- /* padding and the number of bytes of data */
- /* which follow the header. This info is */
- /* used skip to the next file header */
- off_t (*end_rd)(void); /* read cleanup. Allows format to clean up */
- /* and MUST RETURN THE LENGTH OF THE TRAILER */
- /* RECORD (so append knows how many bytes */
- /* to move back to rewrite the trailer) */
- int (*st_wr)(void); /* initialize routine for write operations */
- int (*wr)(ARCHD *); /* write archive header. Passed an ARCHD */
- /* filled with the specs on the next file to */
- /* archived. Returns a 1 if no file data is */
- /* is to be stored; 0 if file data is to be */
- /* added. A -1 is returned if a write */
- /* operation to the archive failed. this */
- /* function sets the skip and pad fields so */
- /* the proper padding can be added after */
- /* file data. This routine must NEVER write */
- /* a flawed archive header. */
- int (*end_wr)(void); /* end write. write the trailer and do any */
- /* other format specific functions needed */
- /* at the end of an archive write */
- int (*trail)(ARCHD *, /* returns 0 if a valid trailer, -1 if not */
- char *, int, /* For formats which encode the trailer */
- int *); /* outside of a valid header, a return value */
- /* of 1 indicates that the block passed to */
- /* it can never contain a valid header (skip */
- /* this block, no point in looking at it) */
- /* CAUTION: parameters to this function are */
- /* different for trailers inside or outside */
- /* of headers. See get_head() for details */
- int (*rd_data)(ARCHD *, /* read/process file data from the archive */
- int, off_t *);
- int (*wr_data)(ARCHD *, /* write/process file data to the archive */
- int, off_t *);
- int (*options)(void); /* process format specific options (-o) */
-} FSUB;
-
-/*
- * Format Specific Options List
- *
- * Used to pass format options to the format options handler
- */
-typedef struct oplist {
- char *name; /* option variable name e.g. name= */
- char *value; /* value for option variable */
- struct oplist *fow; /* next option */
-} OPLIST;
-
-/*
- * General Macros
- */
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-#define MAJOR(x) major(x)
-#define MINOR(x) minor(x)
-#define TODEV(x, y) makedev((x), (y))
-
-/*
- * General Defines
- */
-#define HEX 16
-#define OCT 8
-#define _PAX_ 1
-#define _TFILE_BASE "paxXXXXXXXXXX"
diff --git a/pax/sel_subs.c b/pax/sel_subs.c
@@ -1,606 +0,0 @@
-/* $OpenBSD: sel_subs.c,v 1.20 2009/11/12 20:17:03 deraadt Exp $ */
-/* $NetBSD: sel_subs.c,v 1.5 1995/03/21 09:07:42 cgd Exp $ */
-
-/*-
- * Copyright (c) 1992 Keith Muller.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <ctype.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <tzfile.h>
-#include <unistd.h>
-#include "pax.h"
-#include "sel_subs.h"
-#include "extern.h"
-
-static int str_sec(const char *, time_t *);
-static int usr_match(ARCHD *);
-static int grp_match(ARCHD *);
-static int trng_match(ARCHD *);
-
-static TIME_RNG *trhead = NULL; /* time range list head */
-static TIME_RNG *trtail = NULL; /* time range list tail */
-static USRT **usrtb = NULL; /* user selection table */
-static GRPT **grptb = NULL; /* group selection table */
-
-/*
- * Routines for selection of archive members
- */
-
-/*
- * sel_chk()
- * check if this file matches a specified uid, gid or time range
- * Return:
- * 0 if this archive member should be processed, 1 if it should be skipped
- */
-
-int
-sel_chk(ARCHD *arcn)
-{
- if (((usrtb != NULL) && usr_match(arcn)) ||
- ((grptb != NULL) && grp_match(arcn)) ||
- ((trhead != NULL) && trng_match(arcn)))
- return(1);
- return(0);
-}
-
-/*
- * User/group selection routines
- *
- * Routines to handle user selection of files based on the file uid/gid. To
- * add an entry, the user supplies either the name or the uid/gid starting with
- * a # on the command line. A \# will escape the #.
- */
-
-/*
- * usr_add()
- * add a user match to the user match hash table
- * Return:
- * 0 if added ok, -1 otherwise;
- */
-
-int
-usr_add(char *str)
-{
- u_int indx;
- USRT *pt;
- struct passwd *pw;
- uid_t uid;
-
- /*
- * create the table if it doesn't exist
- */
- if ((str == NULL) || (*str == '\0'))
- return(-1);
- if ((usrtb == NULL) &&
- ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) {
- paxwarn(1, "Unable to allocate memory for user selection table");
- return(-1);
- }
-
- /*
- * figure out user spec
- */
- if (str[0] != '#') {
- /*
- * it is a user name, \# escapes # as first char in user name
- */
- if ((str[0] == '\\') && (str[1] == '#'))
- ++str;
- if ((pw = getpwnam(str)) == NULL) {
- paxwarn(1, "Unable to find uid for user: %s", str);
- return(-1);
- }
- uid = (uid_t)pw->pw_uid;
- } else
- uid = (uid_t)strtoul(str+1, NULL, 10);
- endpwent();
-
- /*
- * hash it and go down the hash chain (if any) looking for it
- */
- indx = ((unsigned)uid) % USR_TB_SZ;
- if ((pt = usrtb[indx]) != NULL) {
- while (pt != NULL) {
- if (pt->uid == uid)
- return(0);
- pt = pt->fow;
- }
- }
-
- /*
- * uid is not yet in the table, add it to the front of the chain
- */
- if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) {
- pt->uid = uid;
- pt->fow = usrtb[indx];
- usrtb[indx] = pt;
- return(0);
- }
- paxwarn(1, "User selection table out of memory");
- return(-1);
-}
-
-/*
- * usr_match()
- * check if this files uid matches a selected uid.
- * Return:
- * 0 if this archive member should be processed, 1 if it should be skipped
- */
-
-static int
-usr_match(ARCHD *arcn)
-{
- USRT *pt;
-
- /*
- * hash and look for it in the table
- */
- pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ];
- while (pt != NULL) {
- if (pt->uid == arcn->sb.st_uid)
- return(0);
- pt = pt->fow;
- }
-
- /*
- * not found
- */
- return(1);
-}
-
-/*
- * grp_add()
- * add a group match to the group match hash table
- * Return:
- * 0 if added ok, -1 otherwise;
- */
-
-int
-grp_add(char *str)
-{
- u_int indx;
- GRPT *pt;
- struct group *gr;
- gid_t gid;
-
- /*
- * create the table if it doesn't exist
- */
- if ((str == NULL) || (*str == '\0'))
- return(-1);
- if ((grptb == NULL) &&
- ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) {
- paxwarn(1, "Unable to allocate memory fo group selection table");
- return(-1);
- }
-
- /*
- * figure out user spec
- */
- if (str[0] != '#') {
- /*
- * it is a group name, \# escapes # as first char in group name
- */
- if ((str[0] == '\\') && (str[1] == '#'))
- ++str;
- if ((gr = getgrnam(str)) == NULL) {
- paxwarn(1,"Cannot determine gid for group name: %s", str);
- return(-1);
- }
- gid = (gid_t)gr->gr_gid;
- } else
- gid = (gid_t)strtoul(str+1, NULL, 10);
- endgrent();
-
- /*
- * hash it and go down the hash chain (if any) looking for it
- */
- indx = ((unsigned)gid) % GRP_TB_SZ;
- if ((pt = grptb[indx]) != NULL) {
- while (pt != NULL) {
- if (pt->gid == gid)
- return(0);
- pt = pt->fow;
- }
- }
-
- /*
- * gid not in the table, add it to the front of the chain
- */
- if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) {
- pt->gid = gid;
- pt->fow = grptb[indx];
- grptb[indx] = pt;
- return(0);
- }
- paxwarn(1, "Group selection table out of memory");
- return(-1);
-}
-
-/*
- * grp_match()
- * check if this files gid matches a selected gid.
- * Return:
- * 0 if this archive member should be processed, 1 if it should be skipped
- */
-
-static int
-grp_match(ARCHD *arcn)
-{
- GRPT *pt;
-
- /*
- * hash and look for it in the table
- */
- pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ];
- while (pt != NULL) {
- if (pt->gid == arcn->sb.st_gid)
- return(0);
- pt = pt->fow;
- }
-
- /*
- * not found
- */
- return(1);
-}
-
-/*
- * Time range selection routines
- *
- * Routines to handle user selection of files based on the modification and/or
- * inode change time falling within a specified time range (the non-standard
- * -T flag). The user may specify any number of different file time ranges.
- * Time ranges are checked one at a time until a match is found (if at all).
- * If the file has a mtime (and/or ctime) which lies within one of the time
- * ranges, the file is selected. Time ranges may have a lower and/or a upper
- * value. These ranges are inclusive. When no time ranges are supplied to pax
- * with the -T option, all members in the archive will be selected by the time
- * range routines. When only a lower range is supplied, only files with a
- * mtime (and/or ctime) equal to or younger are selected. When only a upper
- * range is supplied, only files with a mtime (and/or ctime) equal to or older
- * are selected. When the lower time range is equal to the upper time range,
- * only files with a mtime (or ctime) of exactly that time are selected.
- */
-
-/*
- * trng_add()
- * add a time range match to the time range list.
- * This is a non-standard pax option. Lower and upper ranges are in the
- * format: [[[[[cc]yy]mm]dd]HH]MM[.SS] and are comma separated.
- * Time ranges are based on current time, so 1234 would specify a time of
- * 12:34 today.
- * Return:
- * 0 if the time range was added to the list, -1 otherwise
- */
-
-int
-trng_add(char *str)
-{
- TIME_RNG *pt;
- char *up_pt = NULL;
- char *stpt;
- char *flgpt;
- int dot = 0;
-
- /*
- * throw out the badly formed time ranges
- */
- if ((str == NULL) || (*str == '\0')) {
- paxwarn(1, "Empty time range string");
- return(-1);
- }
-
- /*
- * locate optional flags suffix /{cm}.
- */
- if ((flgpt = strrchr(str, '/')) != NULL)
- *flgpt++ = '\0';
-
- for (stpt = str; *stpt != '\0'; ++stpt) {
- if ((*stpt >= '0') && (*stpt <= '9'))
- continue;
- if ((*stpt == ',') && (up_pt == NULL)) {
- *stpt = '\0';
- up_pt = stpt + 1;
- dot = 0;
- continue;
- }
-
- /*
- * allow only one dot per range (secs)
- */
- if ((*stpt == '.') && (!dot)) {
- ++dot;
- continue;
- }
- paxwarn(1, "Improperly specified time range: %s", str);
- goto out;
- }
-
- /*
- * allocate space for the time range and store the limits
- */
- if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) {
- paxwarn(1, "Unable to allocate memory for time range");
- return(-1);
- }
-
- /*
- * by default we only will check file mtime, but user can specify
- * mtime, ctime (inode change time) or both.
- */
- if ((flgpt == NULL) || (*flgpt == '\0'))
- pt->flgs = CMPMTME;
- else {
- pt->flgs = 0;
- while (*flgpt != '\0') {
- switch (*flgpt) {
- case 'M':
- case 'm':
- pt->flgs |= CMPMTME;
- break;
- case 'C':
- case 'c':
- pt->flgs |= CMPCTME;
- break;
- default:
- paxwarn(1, "Bad option %c with time range %s",
- *flgpt, str);
- (void)free((char *)pt);
- goto out;
- }
- ++flgpt;
- }
- }
-
- /*
- * start off with the current time
- */
- pt->low_time = pt->high_time = time(NULL);
- if (*str != '\0') {
- /*
- * add lower limit
- */
- if (str_sec(str, &(pt->low_time)) < 0) {
- paxwarn(1, "Illegal lower time range %s", str);
- (void)free((char *)pt);
- goto out;
- }
- pt->flgs |= HASLOW;
- }
-
- if ((up_pt != NULL) && (*up_pt != '\0')) {
- /*
- * add upper limit
- */
- if (str_sec(up_pt, &(pt->high_time)) < 0) {
- paxwarn(1, "Illegal upper time range %s", up_pt);
- (void)free((char *)pt);
- goto out;
- }
- pt->flgs |= HASHIGH;
-
- /*
- * check that the upper and lower do not overlap
- */
- if (pt->flgs & HASLOW) {
- if (pt->low_time > pt->high_time) {
- paxwarn(1, "Upper %s and lower %s time overlap",
- up_pt, str);
- (void)free((char *)pt);
- return(-1);
- }
- }
- }
-
- pt->fow = NULL;
- if (trhead == NULL) {
- trtail = trhead = pt;
- return(0);
- }
- trtail->fow = pt;
- trtail = pt;
- return(0);
-
- out:
- paxwarn(1, "Time range format is: [[[[[cc]yy]mm]dd]HH]MM[.SS][/[c][m]]");
- return(-1);
-}
-
-/*
- * trng_match()
- * check if this files mtime/ctime falls within any supplied time range.
- * Return:
- * 0 if this archive member should be processed, 1 if it should be skipped
- */
-
-static int
-trng_match(ARCHD *arcn)
-{
- TIME_RNG *pt;
-
- /*
- * have to search down the list one at a time looking for a match.
- * remember time range limits are inclusive.
- */
- pt = trhead;
- while (pt != NULL) {
- switch (pt->flgs & CMPBOTH) {
- case CMPBOTH:
- /*
- * user wants both mtime and ctime checked for this
- * time range
- */
- if (((pt->flgs & HASLOW) &&
- (arcn->sb.st_mtime < pt->low_time) &&
- (arcn->sb.st_ctime < pt->low_time)) ||
- ((pt->flgs & HASHIGH) &&
- (arcn->sb.st_mtime > pt->high_time) &&
- (arcn->sb.st_ctime > pt->high_time))) {
- pt = pt->fow;
- continue;
- }
- break;
- case CMPCTME:
- /*
- * user wants only ctime checked for this time range
- */
- if (((pt->flgs & HASLOW) &&
- (arcn->sb.st_ctime < pt->low_time)) ||
- ((pt->flgs & HASHIGH) &&
- (arcn->sb.st_ctime > pt->high_time))) {
- pt = pt->fow;
- continue;
- }
- break;
- case CMPMTME:
- default:
- /*
- * user wants only mtime checked for this time range
- */
- if (((pt->flgs & HASLOW) &&
- (arcn->sb.st_mtime < pt->low_time)) ||
- ((pt->flgs & HASHIGH) &&
- (arcn->sb.st_mtime > pt->high_time))) {
- pt = pt->fow;
- continue;
- }
- break;
- }
- break;
- }
-
- if (pt == NULL)
- return(1);
- return(0);
-}
-
-/*
- * str_sec()
- * Convert a time string in the format of [[[[[cc]yy]mm]dd]HH]MM[.SS] to
- * seconds UTC. Tval already has current time loaded into it at entry.
- * Return:
- * 0 if converted ok, -1 otherwise
- */
-
-static int
-str_sec(const char *p, time_t *tval)
-{
- struct tm *lt;
- const char *dot, *t;
- size_t len;
- int bigyear;
- int yearset;
-
- yearset = 0;
- len = strlen(p);
-
- for (t = p, dot = NULL; *t; ++t) {
- if (isdigit(*t))
- continue;
- if (*t == '.' && dot == NULL) {
- dot = t;
- continue;
- }
- return(-1);
- }
-
- lt = localtime(tval);
-
- if (dot != NULL) { /* .SS */
- if (strlen(++dot) != 2)
- return(-1);
- lt->tm_sec = ATOI2(dot);
- if (lt->tm_sec > 61)
- return(-1);
- len -= 3;
- } else
- lt->tm_sec = 0;
-
- switch (len) {
- case 12: /* cc */
- bigyear = ATOI2(p);
- lt->tm_year = (bigyear * 100) - TM_YEAR_BASE;
- yearset = 1;
- /* FALLTHROUGH */
- case 10: /* yy */
- if (yearset) {
- lt->tm_year += ATOI2(p);
- } else {
- lt->tm_year = ATOI2(p);
- if (lt->tm_year < 69) /* hack for 2000 ;-} */
- lt->tm_year += (2000 - TM_YEAR_BASE);
- else
- lt->tm_year += (1900 - TM_YEAR_BASE);
- }
- /* FALLTHROUGH */
- case 8: /* mm */
- lt->tm_mon = ATOI2(p);
- if ((lt->tm_mon > 12) || !lt->tm_mon)
- return(-1);
- --lt->tm_mon; /* time struct is 0 - 11 */
- /* FALLTHROUGH */
- case 6: /* dd */
- lt->tm_mday = ATOI2(p);
- if ((lt->tm_mday > 31) || !lt->tm_mday)
- return(-1);
- /* FALLTHROUGH */
- case 4: /* HH */
- lt->tm_hour = ATOI2(p);
- if (lt->tm_hour > 23)
- return(-1);
- /* FALLTHROUGH */
- case 2: /* MM */
- lt->tm_min = ATOI2(p);
- if (lt->tm_min > 59)
- return(-1);
- break;
- default:
- return(-1);
- }
-
- /* convert broken-down time to UTC clock time seconds */
- if ((*tval = mktime(lt)) == -1)
- return(-1);
- return(0);
-}
diff --git a/pax/sel_subs.h b/pax/sel_subs.h
@@ -1,72 +0,0 @@