-/* $OpenBSD: ar_io.c,v 1.7 1996/11/24 18:15:59 millert Exp $ */
+/* $OpenBSD: ar_io.c,v 1.8 1996/12/09 12:00:13 deraadt Exp $ */
/* $NetBSD: ar_io.c,v 1.5 1996/03/26 23:54:13 mrg Exp $ */
/*-
#if 0
static char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94";
#else
-static char rcsid[] = "$OpenBSD: ar_io.c,v 1.7 1996/11/24 18:15:59 millert Exp $";
+static char rcsid[] = "$OpenBSD: ar_io.c,v 1.8 1996/12/09 12:00:13 deraadt Exp $";
#endif
#endif /* not lint */
#include <errno.h>
#include <stdlib.h>
#include <err.h>
-#include <zlib.h>
#include "pax.h"
#include "extern.h"
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? */
-static gzFile gzf; /* file pointer for gzip archives */
-static FILE *cfp; /* file pointer for compress archives */
char *arcname; /* printable name of archive */
+char *gzip_program; /* name of gzip program */
-FILE *zdopen __P((int, const char *));
static int get_phys __P((void));
extern sigset_t s_mask;
+static void ar_start_gzip __P((int));
/*
* ar_open()
{
struct mtget mb;
- if (arfd != -1) {
- if (zflag == GZIP_CMP)
- (void)gzclose(gzf);
- else if (zflag == COMPRESS_CMP)
- (void)fclose(cfp);
- else
- (void)close(arfd);
- }
+ if (arfd != -1)
+ (void)close(arfd);
arfd = -1;
can_unlnk = did_io = io_ok = invld_rec = 0;
artyp = ISREG;
arcname = STDN;
} else if ((arfd = open(name, EXT_MODE, DMOD)) < 0)
syswarn(0, errno, "Failed open to read on %s", name);
- if (zflag == GZIP_CMP) {
- gzf = gzdopen(arfd, "r");
- if (gzf && !gz_iszipped(gzf)) {
- (void)lseek(arfd, 0, SEEK_SET);
- zflag = COMPRESS_CMP;
- }
- }
- if (zflag == COMPRESS_CMP)
- cfp = zdopen(arfd, "r");
+ if (zflag)
+ ar_start_gzip(arfd);
break;
case ARCHIVE:
if (name == NULL) {
syswarn(0, errno, "Failed open to write on %s", name);
else
can_unlnk = 1;
- if (zflag == GZIP_CMP)
- gzf = gzdopen(arfd, "w");
- else if (zflag == COMPRESS_CMP)
- cfp = zdopen(arfd, "w");
+ if (zflag)
+ ar_start_gzip(arfd);
break;
case APPND:
if (zflag)
- err(1, "can not compress while appending");
+ err(1, "can not gzip while appending");
if (name == NULL) {
arfd = STDOUT_FILENO;
arcname = STDO;
*/
if (fstat(arfd, &arsb) < 0) {
syswarn(0, errno, "Failed stat on %s", arcname);
- if (zflag == GZIP_CMP)
- (void)gzclose(gzf);
- else if (zflag == COMPRESS_CMP)
- (void)fclose(cfp);
- else
- (void)close(arfd);
+ (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);
- if (zflag == GZIP_CMP)
- (void)gzclose(gzf);
- else if (zflag == COMPRESS_CMP)
- (void)fclose(cfp);
- else
- (void)close(arfd);
+ (void)close(arfd);
arfd = -1;
can_unlnk = 0;
return(-1);
can_unlnk = 0;
}
- if (zflag == GZIP_CMP)
- (void)gzclose(gzf);
- else if (zflag == COMPRESS_CMP)
- (void)fclose(cfp);
- else
- (void)close(arfd);
+ (void)close(arfd);
if (vflag && (artyp == ISTAPE)) {
(void)fputs("done.\n", outf);
/*
* keep reading until pipe is drained
*/
- if (zflag == GZIP_CMP) {
- while ((res = gzread(gzf, drbuf, sizeof(drbuf))) > 0)
- ;
- }
- else if (zflag == COMPRESS_CMP) {
- while ((res = fread(drbuf, 1, sizeof(drbuf), cfp)) > 0)
- ;
- }
- else {
- while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0)
- ;
- }
+ while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0)
+ ;
lstrval = res;
}
return(-1);
}
- if (zflag) {
- paxwarn(1, "Cannot append to a compressed archive.");
- return(-1);
- }
-
if (!invld_rec)
return(0);
paxwarn(1,"Cannot append, device record size %d does not support %s spec",
*/
switch (artyp) {
case ISTAPE:
- if (!zflag) {
- if ((res = read(arfd, buf, cnt)) > 0) {
+ 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) {
/*
- * 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.
+ * Record size changed. If this is 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).
*/
- io_ok = 1;
- if (res != rdblksz) {
- /*
- * Record size changed. If this is 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);
+ rdblksz = res;
+ if (rdblksz % BLKMULT)
+ invld_rec = 1;
}
- break;
+ return(res);
}
+ break;
case ISREG:
case ISBLK:
case ISCHR:
* and return. Trying to do anything else with them runs the
* risk of failure.
*/
- if (zflag == GZIP_CMP) {
- if ((res = gzread(gzf, buf, cnt)) > 0) {
- io_ok = 1;
- return(res);
- }
- }
- else if (zflag == COMPRESS_CMP) {
- if ((res = fread(buf, 1, cnt, cfp)) > 0) {
- io_ok = 1;
- return(res);
- }
- }
- else {
- if ((res = read(arfd, buf, cnt)) > 0) {
- io_ok = 1;
- return(res);
- }
+ if ((res = read(arfd, buf, cnt)) > 0) {
+ io_ok = 1;
+ return(res);
}
break;
}
if (lstrval <= 0)
return(lstrval);
- if (zflag == GZIP_CMP) {
- if ((res = gzwrite(gzf, buf, bsz)) == bsz) {
- wr_trail = 1;
- io_ok = 1;
- return(bsz);
- }
- }
- else if (zflag == COMPRESS_CMP) {
- if ((res = fwrite(buf, 1, bsz, cfp)) == bsz) {
- wr_trail = 1;
- io_ok = 1;
- return(bsz);
- }
- }
- else {
- if ((res = write(arfd, buf, bsz)) == bsz) {
- wr_trail = 1;
- io_ok = 1;
- return(bsz);
- }
+ 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
else
lstrval = 0;
- if (!zflag) {
- 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;
+ 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;
- }
- if (res >= 0)
+ cpos -= (off_t)res;
+ if (ftruncate(arfd, cpos) < 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;
+ 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;
+ }
+ if (res >= 0)
break;
- case ISPIPE:
- default:
- /*
- * we cannot fix errors to these devices
- */
+ /*
+ * 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;
}
/*
if (io_ok)
did_io = 1;
- if (zflag)
- io_ok = 0;
- else {
- 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 foward 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.
- */
+ 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 foward one PHYSICAL record past any
+ * damaged tape section. Some tape drives are stubborn and need
+ * to be pushed.
+ */
+ if (io_ok) {
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;
}
+ 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.");
off_t mpos;
*skipped = 0;
- if (zflag || sksz <= 0)
+ if (sksz <= 0)
return(0);
/*
if (lstrval < 0)
return(lstrval);
- if (zflag) {
- if (sksz <= 0) {
- lstrval = 1;
- return 0;
- }
- /*
- * cannot go backwards on these critters
- */
- paxwarn(1, "Reverse positioning on pipes is not supported.");
- lstrval = -1;
- return(-1);
- }
-
switch(artyp) {
case ISPIPE:
if (sksz <= 0)
struct mtop mb;
char scbuf[MAXBLK];
- if (zflag) {
- syswarn(1, errno, "Cannot determine archive tape blocksize.");
- return(-1);
- }
-
/*
* 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.
}
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
+#ifdef __STDC__
+ar_start_gzip(int fd)
+#else
+ar_start_gzip(fd)
+ int fd;
+#endif
+{
+ pid_t pid;
+ int fds[2];
+ char *gzip_flags;
+
+ if (pipe(fds) < 0)
+ err(1, "could not pipe");
+ pid = fork();
+ if (pid < 0)
+ err(1, "could not fork");
+
+ /* parent */
+ if (pid) {
+ switch (act) {
+ case ARCHIVE:
+ dup2(fds[1], fd);
+ break;
+ case LIST:
+ case EXTRACT:
+ dup2(fds[0], fd);
+ break;
+ default:
+ errx(1, "ar_start_gzip: impossible");
+ }
+ close(fds[0]);
+ close(fds[1]);
+ } else {
+ switch (act) {
+ case ARCHIVE:
+ dup2(fds[0], STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ gzip_flags = "-c";
+ break;
+ case LIST:
+ case EXTRACT:
+ dup2(fds[1], STDOUT_FILENO);
+ dup2(fd, STDIN_FILENO);
+ gzip_flags = "-dc";
+ break;
+ default:
+ errx(1, "ar_start_gzip: impossible");
+ }
+ close(fds[0]);
+ close(fds[1]);
+ if (execlp(gzip_program, gzip_program, gzip_flags, NULL) < 0)
+ err(1, "could not exec");
+ /* NOTREACHED */
+ }
+}