📄 ar_io.c
字号:
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 + -