⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tape.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -