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

📄 ar_io.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	lstrval = res;}/* * ar_set_wr() *	Set up device right before switching from read to write in an append. *	device dependent code (if required) to do this should be added here. *	For all archive devices we are already positioned at the place we want *	to start writing when this routine is called. * Return: *	0 if all ready to write, -1 otherwise */#if __STDC__intar_set_wr(void)#elseintar_set_wr()#endif{	off_t cpos;	/*	 * we must make sure the trailer is rewritten on append, ar_next()	 * will stop us if the archive containing the trailer was not written	 */	wr_trail = 0;		/* 	 * Add any device dependent code as required here	 */	if (artyp != ISREG)		return(0);	/*	 * Ok we have an archive in a regular file. If we were rewriting a	 * file, we must get rid of all the stuff after the current offset	 * (it was not written by pax).	 */	if (((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) ||	    (ftruncate(arfd, cpos) < 0)) {		syswarn(1, errno, "Unable to truncate archive file");		return(-1);	}	return(0);}/* * ar_app_ok() *	check if the last volume in the archive allows appends. We cannot check *	this until we are ready to write since there is no spec that says all  *	volumes in a single archive have to be of the same type... * Return: *	0 if we can append, -1 otherwise. */#if __STDC__intar_app_ok(void)#elseintar_app_ok()#endif{	if (artyp == ISPIPE) {		warn(1, "Cannot append to an archive obtained from a pipe.");		return(-1);	}	if (!invld_rec)		return(0);	warn(1,"Cannot append, device record size %d does not support %s spec",		rdblksz, argv0);	return(-1);}/* * ar_read() *	read up to a specified number of bytes from the archive into the *	supplied buffer. When dealing with tapes we may not always be able to *	read what we want. * Return: *	Number of bytes in buffer. 0 for end of file, -1 for a read error. */#if __STDC__intar_read(register char *buf, register int cnt)#elseintar_read(buf, cnt)	register char *buf;	register int cnt;#endif{	register int res = 0;	/*	 * if last i/o was in error, no more reads until reset or new volume	 */	if (lstrval <= 0)		return(lstrval);	/*	 * how we read must be based on device type	 */	switch (artyp) {	case ISTAPE:		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) {				/*				 * 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);		}		break;	case ISREG:	case ISBLK:	case ISCHR:	case ISPIPE:	default:		/*		 * Files are so easy to deal with. These other things cannot		 * be trusted at all. So when we are dealing with character		 * devices and pipes we just take what they have ready for us		 * and return. Trying to do anything else with them runs the		 * risk of failure.		 */		if ((res = read(arfd, buf, cnt)) > 0) {			io_ok = 1;			return(res);		}		break;	}	/*	 * We are in trouble at this point, something is broken...	 */	lstrval = res;	if (res < 0)		syswarn(1, errno, "Failed read on archive volume %d", arvol);	else		warn(0, "End of archive volume %d reached", arvol);	return(res);} /* * ar_write() *	Write a specified number of bytes in supplied buffer to the archive *	device so it appears as a single "block". Deals with errors and tries *	to recover when faced with short writes. * Return: *	Number of bytes written. 0 indicates end of volume reached and with no *	flaws (as best that can be detected). A -1 indicates an unrecoverable *	error in the archive occured. */#if __STDC__intar_write(register char *buf, register int bsz)#elseintar_write(buf, bsz)	register char *buf;	register int bsz;#endif{	register int res;	off_t cpos;	/*	 * do not allow pax to create a "bad" archive. Once a write fails on	 * an archive volume prevent further writes to it.	 */	if (lstrval <= 0)		return(lstrval);	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	 * writes that may violate pax spec to the next archive volume.	 */	if (res < 0)		lstrval = res;	else		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;			cpos -= (off_t)res;			if (ftruncate(arfd, cpos) < 0)				break;			res = lstrval = 0;			break;		}		if (res >= 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;		break;	case ISTAPE:	case ISCHR:	case ISBLK:		if (res >= 0)			break;		if (errno == EACCES) {			warn(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;	}	/*	 * Better tell the user the bad news...	 * if this is a block aligned archive format, we may have a bad archive	 * if the format wants the header to start at a BLKMULT boundry. While	 * we can deal with the mis-aligned data, it violates spec and other	 * archive readers will likely fail. if the format is not block	 * aligned, the user may be lucky (and the archive is ok).	 */	if (res >= 0) {		if (res > 0)			wr_trail = 1;		io_ok = 1;	}	/*	 * If we were trying to rewrite the trailer and it didn't work, we	 * must quit right away.	 */	if (!wr_trail && (res <= 0)) {		warn(1,"Unable to append, trailer re-write failed. Quitting.");		return(res);	}			if (res == 0) 		warn(0, "End of archive volume %d reached", arvol);	else if (res < 0)		syswarn(1, errno, "Failed write to archive volume: %d", arvol);	else if (!frmt->blkalgn || ((res % frmt->blkalgn) == 0))		warn(0,"WARNING: partial archive write. Archive MAY BE FLAWED");	else		warn(1,"WARNING: partial archive write. Archive IS FLAWED");	return(res);}/* * ar_rdsync() *	Try to move past a bad spot on a flawed archive as needed to continue *	I/O. Clears error flags to allow I/O to continue. * Return: *	0 when ok to try i/o again, -1 otherwise. */#if __STDC__intar_rdsync(void)#elseintar_rdsync()#endif{	long fsbz;	off_t cpos;	off_t mpos;        struct mtop mb;	/*	 * Fail resync attempts at user request (done) or this is going to be	 * an update/append to a existing archive. if last i/o hit media end,	 * we need to go to the next volume not try a resync	 */	if ((done > 0) || (lstrval == 0))		return(-1);	if ((act == APPND) || (act == ARCHIVE)) {		warn(1, "Cannot allow updates to an archive with flaws.");		return(-1);	}	if (io_ok)		did_io = 1;	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.		 */		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) {		warn(1, "Unable to recover from an archive read failure.");		return(-1);	}	warn(0, "Attempting to recover from an archive read failure.");	return(0);}/* * ar_fow() *	Move the I/O position within the archive foward the specified number of *	bytes as supported by the device. If we cannot move the requested *	number of bytes, return the actual number of bytes moved in skipped. * Return: *	0 if moved the requested distance, -1 on complete failure, 1 on *	partial move (the amount moved is in skipped) */#if __STDC__intar_fow(off_t sksz, off_t *skipped)#elseintar_fow(sksz, skipped)	off_t sksz;	off_t *skipped;#endif{	off_t cpos;	off_t mpos;	*skipped = 0;	if (sksz <= 0)		return(0);	/*	 * we cannot move foward at EOF or error	 */	if (lstrval <= 0)		return(lstrval);	/*	 * Safer to read forward on devices where it is hard to find the end of	 * the media without reading to it. With tapes we cannot be sure of the	 * number of physical blocks to skip (we do not know physical block	 * size at this point), so we must only read foward on tapes!	 */	if (artyp != ISREG) 		return(0);	/*	 * figure out where we are in the archive	 */	if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) >= 0) {		/* 	 	 * we can be asked to move farther than there are bytes in this		 * volume, if so, just go to file end and let normal buf_fill()

⌨️ 快捷键说明

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