📄 tape.c
字号:
/* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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[] = "@(#)tape.c 8.3 (Berkeley) 4/1/94";#endif /* not lint */#include <sys/param.h>#include <sys/file.h>#include <sys/ioctl.h>#include <sys/mtio.h>#include <sys/stat.h>#include <ufs/ufs/dinode.h>#include <protocols/dumprestore.h>#include <errno.h>#include <setjmp.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "restore.h"#include "extern.h"#include "pathnames.h"static long fssize = MAXBSIZE;static int mt = -1;static int pipein = 0;static char magtape[BUFSIZ];static int blkcnt;static int numtrec;static char *tapebuf;static union u_spcl endoftapemark;static long blksread; /* blocks read since last header */static long tpblksread = 0; /* TP_BSIZE blocks read */static long tapesread;static jmp_buf restart;static int gettingfile = 0; /* restart has a valid frame */static char *host = NULL;static int ofile;static char *map;static char lnkbuf[MAXPATHLEN + 1];static int pathlen;int oldinofmt; /* old inode format conversion required */int Bcvt; /* Swap Bytes (for CCI or sun) */static int Qcvt; /* Swap quads (for sun) */#define FLUSHTAPEBUF() blkcnt = ntrec + 1static void accthdr __P((struct s_spcl *));static int checksum __P((int *));static void findinode __P((struct s_spcl *));static void findtapeblksize __P((void));static int gethead __P((struct s_spcl *));static void readtape __P((char *));static void setdumpnum __P((void));static u_long swabl __P((u_long));static u_char *swablong __P((u_char *, int));static u_char *swabshort __P((u_char *, int));static void terminateinput __P((void));static void xtrfile __P((char *, long));static void xtrlnkfile __P((char *, long));static void xtrlnkskip __P((char *, long));static void xtrmap __P((char *, long));static void xtrmapskip __P((char *, long));static void xtrskip __P((char *, long));/* * Set up an input source */voidsetinput(source) char *source;{ FLUSHTAPEBUF(); if (bflag) newtapebuf(ntrec); else newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); terminal = stdin;#ifdef RRESTORE if (index(source, ':')) { host = source; source = index(host, ':'); *source++ = '\0'; if (rmthost(host) == 0) done(1); } else#endif if (strcmp(source, "-") == 0) { /* * Since input is coming from a pipe we must establish * our own connection to the terminal. */ terminal = fopen(_PATH_TTY, "r"); if (terminal == NULL) { (void)fprintf(stderr, "cannot open %s: %s\n", _PATH_TTY, strerror(errno)); terminal = fopen(_PATH_DEVNULL, "r"); if (terminal == NULL) { (void)fprintf(stderr, "cannot open %s: %s\n", _PATH_DEVNULL, strerror(errno)); done(1); } } pipein++; } setuid(getuid()); /* no longer need or want root privileges */ (void) strcpy(magtape, source);}voidnewtapebuf(size) long size;{ static tapebufsize = -1; ntrec = size; if (size <= tapebufsize) return; if (tapebuf != NULL) free(tapebuf); tapebuf = malloc(size * TP_BSIZE); if (tapebuf == NULL) { fprintf(stderr, "Cannot allocate space for tape buffer\n"); done(1); } tapebufsize = size;}/* * Verify that the tape drive can be accessed and * that it actually is a dump tape. */voidsetup(){ int i, j, *ip; struct stat stbuf; vprintf(stdout, "Verify tape and initialize maps\n");#ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else#endif if (pipein) mt = 0; else mt = open(magtape, O_RDONLY, 0); if (mt < 0) { fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); done(1); } volno = 1; setdumpnum(); FLUSHTAPEBUF(); if (!pipein && !bflag) findtapeblksize(); if (gethead(&spcl) == FAIL) { blkcnt--; /* push back this block */ blksread--; tpblksread--; cvtflag++; if (gethead(&spcl) == FAIL) { fprintf(stderr, "Tape is not a dump tape\n"); done(1); } fprintf(stderr, "Converting to new file system format.\n"); } if (pipein) { endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; endoftapemark.s_spcl.c_type = TS_END; ip = (int *)&endoftapemark; j = sizeof(union u_spcl) / sizeof(int); i = 0; do i += *ip++; while (--j); endoftapemark.s_spcl.c_checksum = CHECKSUM - i; } if (vflag || command == 't') printdumpinfo(); dumptime = spcl.c_ddate; dumpdate = spcl.c_date; if (stat(".", &stbuf) < 0) { fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); done(1); } if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE) fssize = stbuf.st_blksize; if (((fssize - 1) & fssize) != 0) { fprintf(stderr, "bad block size %d\n", fssize); done(1); } if (spcl.c_volume != 1) { fprintf(stderr, "Tape is not volume 1 of the dump\n"); done(1); } if (gethead(&spcl) == FAIL) { dprintf(stdout, "header read failed at %d blocks\n", blksread); panic("no header after volume mark!\n"); } findinode(&spcl); if (spcl.c_type != TS_CLRI) { fprintf(stderr, "Cannot find file removal list\n"); done(1); } maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; dprintf(stdout, "maxino = %d\n", maxino); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) panic("no memory for file removal list\n"); clrimap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); if (spcl.c_type != TS_BITS) { fprintf(stderr, "Cannot find file dump list\n"); done(1); } map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == (char *)NULL) panic("no memory for file dump list\n"); dumpmap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip);}/* * Prompt user to load a new dump volume. * "Nextvol" is the next suggested volume to use. * This suggested volume is enforced when doing full * or incremental restores, but can be overrridden by * the user when only extracting a subset of the files. */voidgetvol(nextvol) long nextvol;{ long newvol, savecnt, wantnext, i; union u_spcl tmpspcl;# define tmpbuf tmpspcl.s_spcl char buf[TP_BSIZE]; if (nextvol == 1) { tapesread = 0; gettingfile = 0; } if (pipein) { if (nextvol != 1) panic("Changing volumes on pipe input?\n"); if (volno == 1) return; goto gethdr; } savecnt = blksread;again: if (pipein) done(1); /* pipes do not get a second chance */ if (command == 'R' || command == 'r' || curfile.action != SKIP) { newvol = nextvol; wantnext = 1; } else { newvol = 0; wantnext = 0; } while (newvol <= 0) { if (tapesread == 0) { fprintf(stderr, "%s%s%s%s%s", "You have not read any tapes yet.\n", "Unless you know which volume your", " file(s) are on you should start\n", "with the last volume and work", " towards towards the first.\n"); } else { fprintf(stderr, "You have read volumes"); strcpy(buf, ": "); for (i = 1; i < 32; i++) if (tapesread & (1 << i)) { fprintf(stderr, "%s%d", buf, i); strcpy(buf, ", "); } fprintf(stderr, "\n"); } do { fprintf(stderr, "Specify next volume #: "); (void) fflush(stderr); (void) fgets(buf, BUFSIZ, terminal); } while (!feof(terminal) && buf[0] == '\n'); if (feof(terminal)) done(1); newvol = atoi(buf); if (newvol <= 0) { fprintf(stderr, "Volume numbers are positive numerics\n"); } } if (newvol == volno) { tapesread |= 1 << volno; return; } closemt(); fprintf(stderr, "Mount tape volume %d\n", newvol); fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); (void) fflush(stderr); (void) fgets(buf, BUFSIZ, terminal); if (feof(terminal)) done(1); if (!strcmp(buf, "none\n")) { terminateinput(); return; } if (buf[0] != '\n') { (void) strcpy(magtape, buf); magtape[strlen(magtape) - 1] = '\0'; }#ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else#endif mt = open(magtape, O_RDONLY, 0); if (mt == -1) { fprintf(stderr, "Cannot open %s\n", magtape); volno = -1; goto again; }gethdr: volno = newvol; setdumpnum(); FLUSHTAPEBUF(); if (gethead(&tmpbuf) == FAIL) { dprintf(stdout, "header read failed at %d blocks\n", blksread); fprintf(stderr, "tape is not dump tape\n"); volno = 0; goto again; } if (tmpbuf.c_volume != volno) { fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); volno = 0; goto again; } if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&tmpbuf.c_date)); fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); volno = 0; goto again; } tapesread |= 1 << volno; blksread = savecnt; /* * If continuing from the previous volume, skip over any * blocks read already at the end of the previous volume. * * If coming to this volume at random, skip to the beginning * of the next record. */ dprintf(stdout, "read %ld recs, tape starts with %ld\n", tpblksread, tmpbuf.c_firstrec); if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { if (!wantnext) { tpblksread = tmpbuf.c_firstrec; for (i = tmpbuf.c_count; i > 0; i--) readtape(buf); } else if (tmpbuf.c_firstrec > 0 && tmpbuf.c_firstrec < tpblksread - 1) { /* * -1 since we've read the volume header */ i = tpblksread - tmpbuf.c_firstrec - 1; dprintf(stderr, "Skipping %d duplicate record%s.\n", i, i > 1 ? "s" : ""); while (--i >= 0) readtape(buf); } } if (curfile.action == USING) { if (volno == 1) panic("active file into volume 1\n"); return; } /* * Skip up to the beginning of the next record */ if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) for (i = tmpbuf.c_count; i > 0; i--) readtape(buf); (void) gethead(&spcl); findinode(&spcl); if (gettingfile) { gettingfile = 0; longjmp(restart, 1); }}/* * Handle unexpected EOF. */static voidterminateinput(){ if (gettingfile && curfile.action == USING) { printf("Warning: %s %s\n", "End-of-input encountered while extracting", curfile.name); } curfile.name = "<name unknown>"; curfile.action = UNKNOWN; curfile.dip = NULL; curfile.ino = maxino; if (gettingfile) { gettingfile = 0; longjmp(restart, 1); }}/* * handle multiple dumps per tape by skipping forward to the * appropriate one. */static voidsetdumpnum(){ struct mtop tcom; if (dumpnum == 1 || volno != 1) return; if (pipein) { fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); done(1); } tcom.mt_op = MTFSF; tcom.mt_count = dumpnum - 1;#ifdef RRESTORE if (host) rmtioctl(MTFSF, dumpnum - 1); else #endif if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));}voidprintdumpinfo(){ fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); fprintf(stdout, "Dumped from: %s", (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); if (spcl.c_host[0] == '\0') return; fprintf(stderr, "Level %d dump of %s on %s:%s\n", spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); fprintf(stderr, "Label: %s\n", spcl.c_label);}intextractfile(name) char *name;{ int mode; struct timeval timep[2]; struct entry *ep; curfile.name = name; curfile.action = USING; timep[0].tv_sec = curfile.dip->di_atime.ts_sec; timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000; timep[1].tv_sec = curfile.dip->di_mtime.ts_sec; timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000; mode = curfile.dip->di_mode; switch (mode & IFMT) { default: fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); skipfile(); return (FAIL); case IFSOCK: vprintf(stdout, "skipped socket %s\n", name); skipfile(); return (GOOD); case IFDIR: if (mflag) { ep = lookupname(name); if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } vprintf(stdout, "extract file %s\n", name); return (genliteraldir(name, curfile.ino)); case IFLNK: lnkbuf[0] = '\0'; pathlen = 0; getfile(xtrlnkfile, xtrlnkskip); if (pathlen == 0) { vprintf(stdout, "%s: zero length symbolic link (ignored)\n", name); return (GOOD); } return (linkit(lnkbuf, name, SYMLINK)); case IFCHR: case IFBLK: vprintf(stdout, "extract special file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { fprintf(stderr, "%s: cannot create special file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); (void) chmod(name, mode); skipfile(); utimes(name, timep); return (GOOD); case IFREG: vprintf(stdout, "extract file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if ((ofile = creat(name, 0666)) < 0) { fprintf(stderr, "%s: cannot create file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); (void) fchmod(ofile, mode); getfile(xtrfile, xtrskip); (void) close(ofile); utimes(name, timep); return (GOOD); } /* NOTREACHED */}/* * skip over bit maps on the tape */voidskipmaps(){ while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) skipfile();}/* * skip over a file on the tape */voidskipfile(){ curfile.action = SKIP; getfile(xtrnull, xtrnull);}/* * Extract a file from the tape. * When an allocated block is found it is passed to the fill function; * when an unallocated block (hole) is found, a zeroed buffer is passed * to the skip function. */voidgetfile(fill, skip) void (*fill) __P((char *, long)); void (*skip) __P((char *, long));{ register int i; int curblk = 0; long size = spcl.c_dinode.di_size; static char clearedbuf[MAXBSIZE]; char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; char junk[TP_BSIZE]; if (spcl.c_type == TS_END) panic("ran off end of tape\n"); if (spcl.c_magic != NFS_MAGIC) panic("not at beginning of a file\n"); if (!gettingfile && setjmp(restart) != 0) return; gettingfile++;loop: for (i = 0; i < spcl.c_count; i++) { if (spcl.c_addr[i]) { readtape(&buf[curblk++][0]); if (curblk == fssize / TP_BSIZE) { (*fill)((char *)buf, size > TP_BSIZE ? (long) (fssize) : (curblk - 1) * TP_BSIZE + size); curblk = 0; } } else { if (curblk > 0) { (*fill)((char *)buf, size > TP_BSIZE ? (long) (curblk * TP_BSIZE) : (curblk - 1) * TP_BSIZE + size); curblk = 0; } (*skip)(clearedbuf, size > TP_BSIZE ? (long) TP_BSIZE : size); } if ((size -= TP_BSIZE) <= 0) { for (i++; i < spcl.c_count; i++) if (spcl.c_addr[i]) readtape(junk); break; } } if (gethead(&spcl) == GOOD && size > 0) { if (spcl.c_type == TS_ADDR) goto loop; dprintf(stdout, "Missing address (header) block for %s at %d blocks\n", curfile.name, blksread); } if (curblk > 0) (*fill)((char *)buf, (curblk * TP_BSIZE) + size); findinode(&spcl); gettingfile = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -