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

📄 buf_subs.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * 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[] = "@(#)buf_subs.c	8.2 (Berkeley) 4/18/94";#endif /* not lint */#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/param.h>#include <stdio.h>#include <ctype.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 */#if __STDC__intwr_start(void)#elseintwr_start()#endif{	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) {		warn(1, "Write block size of %d too large, maximium is: %d",			wrblksz, MAXBLK);		return(-1);	}	if (wrblksz % BLKMULT) {		warn(1, "Write block size of %d is not a %d byte multiple",		    wrblksz, BLKMULT);		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 */#if __STDC__intrd_start(void)#elseintrd_start()#endif{	/*	 * 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) {			warn(1,"Write block size %d too large, maximium is: %d",				wrblksz, MAXBLK);			return(-1);		}		if (wrblksz % BLKMULT) {			warn(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 */#if __STDC__voidcp_start(void)#elsevoidcp_start()#endif{	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 postions 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 boundries. *	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 trival. 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 writes, *	so it may not be feasable to append archives stored on all types of *	devices.  * Return: *	0 for success, -1 for failure */#if __STDC__intappnd_start(off_t skcnt)#elseintappnd_start(skcnt)	off_t skcnt;#endif{	register int res;	off_t cnt;	if (exit_val != 0) {		warn(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:	warn(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 */#if __STDC__intrd_sync(void)#elseintrd_sync()#endif{	register int errcnt = 0;	register int res;	/*	 * if the user says bail out on first fault, we are out of here...	 */	if (maxflt == 0)		return(-1);	if (act == APPND) {		warn(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))			warn(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 boundry (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. */#if __STDC__voidpback(char *pt, int cnt)#elsevoidpback(pt, cnt)	char *pt;	int cnt;#endif{	bufpt -= cnt;	bcopy(pt, bufpt, cnt);	return;}/* * rd_skip() *	skip foward 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. */#if __STDC__intrd_skip(off_t skcnt)#elseintrd_skip(skcnt)	off_t skcnt;#endif{	off_t res;	off_t cnt;	off_t skipped = 0;	/*	 * consume what data we have in the buffer. If we have to move foward	 * 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 paddding SHOULD *	BE a requirement.... */#if __STDC__voidwr_fin(void)#elsevoidwr_fin()#endif{	if (bufpt > buf) {		bzero(bufpt, 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) */#if __STDC__intwr_rdbuf(register char *out, register int outcnt)#elseintwr_rdbuf(out, outcnt)	register char *out;	register int outcnt;#endif{	register 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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -