📄 ar_io.c
字号:
/*- * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */#ifndef lintstatic char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94";#endif /* not lint */#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 <signal.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <ctype.h>#include <errno.h>#include <stdlib.h>#include "pax.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>" /* psuedo name for stdout */#define STDN "<STDIN>" /* psuedo 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? */char *arcname; /* printable name of archive */static int get_phys __P((void));extern sigset_t s_mask;/* * 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 */#if __STDC__intar_open(char *name)#elseintar_open(name) char *name;#endif{ 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(0, errno, "Failed open to read on %s", name); break; case ARCHIVE: if (name == NULL) { arfd = STDOUT_FILENO; arcname = STDO; } else if ((arfd = open(name, AR_MODE, DMOD)) < 0) syswarn(0, errno, "Failed open to write on %s", name); else can_unlnk = 1; break; case APPND: if (name == NULL) { arfd = STDOUT_FILENO; arcname = STDO; } else if ((arfd = open(name, APP_MODE, DMOD)) < 0) syswarn(0, 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); /* * set up is based on device type */ if (fstat(arfd, &arsb) < 0) { syswarn(0, errno, "Failed stat on %s", arcname); (void)close(arfd); arfd = -1; can_unlnk = 0; return(-1); } if (S_ISDIR(arsb.st_mode)) { warn(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, otherwize we will continue to use rdblksz). We * must to 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 cannont 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, worse case, slow... */ blksz = rdblksz = BLKMULT; break; } lstrval = 1; return(0);}/* * ar_close() * closes archive device, increments volume number, and prints i/o summary */#if __STDC__voidar_close(void)#elsevoidar_close()#endif{ FILE *outf; if (arfd < 0) { did_io = io_ok = flcnt = 0; return; } if (act == LIST) outf = stdout; else outf = stderr; /* * 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', outf); (void)fprintf(outf, "%s: Waiting for tape drive close to complete...", argv0); (void)fflush(outf); } /* * 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; } (void)close(arfd); if (vflag && (artyp == ISTAPE)) { (void)fputs("done.\n", outf); vfpart = 0; (void)fflush(outf); } 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', outf); 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 NET2_STAT (void)fprintf(outf, "%s: unknown format, %lu bytes skipped.\n",# else (void)fprintf(outf, "%s: unknown format, %qu bytes skipped.\n",# endif argv0, rdcnt); (void)fflush(outf); flcnt = 0; return; } (void)fprintf(outf,# ifdef NET2_STAT "%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(outf); 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). */#if __STDC__voidar_drain(void)#elsevoidar_drain()#endif{ register 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) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -