11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3536049Scharnier#if 0 3636049Scharnierstatic char sccsid[] = "@(#)buf_subs.c 8.2 (Berkeley) 4/18/94"; 3736049Scharnier#endif 381556Srgrimes#endif /* not lint */ 3999110Sobrien#include <sys/cdefs.h> 4099110Sobrien__FBSDID("$FreeBSD$"); 411556Srgrimes 421556Srgrimes#include <sys/types.h> 431556Srgrimes#include <sys/stat.h> 441556Srgrimes#include <errno.h> 451556Srgrimes#include <unistd.h> 4676351Skris#include <stdio.h> 471556Srgrimes#include <stdlib.h> 481556Srgrimes#include <string.h> 491556Srgrimes#include "pax.h" 501556Srgrimes#include "extern.h" 511556Srgrimes 521556Srgrimes/* 531556Srgrimes * routines which implement archive and file buffering 541556Srgrimes */ 551556Srgrimes 561556Srgrimes#define MINFBSZ 512 /* default block size for hole detect */ 5776019Skris#define MAXFLT 10 /* default media read error limit */ 581556Srgrimes 591556Srgrimes/* 601556Srgrimes * Need to change bufmem to dynamic allocation when the upper 611556Srgrimes * limit on blocking size is removed (though that will violate pax spec) 621556Srgrimes * MAXBLK define and tests will also need to be updated. 631556Srgrimes */ 641556Srgrimesstatic char bufmem[MAXBLK+BLKMULT]; /* i/o buffer + pushback id space */ 651556Srgrimesstatic char *buf; /* normal start of i/o buffer */ 661556Srgrimesstatic char *bufend; /* end or last char in i/o buffer */ 671556Srgrimesstatic char *bufpt; /* read/write point in i/o buffer */ 6876019Skrisint blksz = MAXBLK; /* block input/output size in bytes */ 6976019Skrisint wrblksz; /* user spec output size in bytes */ 701556Srgrimesint maxflt = MAXFLT; /* MAX consecutive media errors */ 711556Srgrimesint rdblksz; /* first read blksize (tapes only) */ 721556Srgrimesoff_t wrlimit; /* # of bytes written per archive vol */ 731556Srgrimesoff_t wrcnt; /* # of bytes written on current vol */ 741556Srgrimesoff_t rdcnt; /* # of bytes read on current vol */ 751556Srgrimes 761556Srgrimes/* 771556Srgrimes * wr_start() 781556Srgrimes * set up the buffering system to operate in a write mode 791556Srgrimes * Return: 801556Srgrimes * 0 if ok, -1 if the user specified write block size violates pax spec 811556Srgrimes */ 821556Srgrimes 831556Srgrimesint 841556Srgrimeswr_start(void) 851556Srgrimes{ 861556Srgrimes buf = &(bufmem[BLKMULT]); 871556Srgrimes /* 881556Srgrimes * Check to make sure the write block size meets pax specs. If the user 891556Srgrimes * does not specify a blocksize, we use the format default blocksize. 901556Srgrimes * We must be picky on writes, so we do not allow the user to create an 911556Srgrimes * archive that might be hard to read elsewhere. If all ok, we then 921556Srgrimes * open the first archive volume 931556Srgrimes */ 948855Srgrimes if (!wrblksz) 951556Srgrimes wrblksz = frmt->bsz; 961556Srgrimes if (wrblksz > MAXBLK) { 9776017Skris paxwarn(1, "Write block size of %d too large, maximum is: %d", 981556Srgrimes wrblksz, MAXBLK); 991556Srgrimes return(-1); 1001556Srgrimes } 1011556Srgrimes if (wrblksz % BLKMULT) { 10276017Skris paxwarn(1, "Write block size of %d is not a %d byte multiple", 1031556Srgrimes wrblksz, BLKMULT); 1041556Srgrimes return(-1); 1051556Srgrimes } 10676351Skris if (wrblksz > MAXBLK_POSIX) { 10776351Skris paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable", 10876351Skris wrblksz, MAXBLK_POSIX); 10976351Skris return(-1); 11076351Skris } 1111556Srgrimes 1121556Srgrimes /* 1138855Srgrimes * we only allow wrblksz to be used with all archive operations 1141556Srgrimes */ 1151556Srgrimes blksz = rdblksz = wrblksz; 1161556Srgrimes if ((ar_open(arcname) < 0) && (ar_next() < 0)) 1171556Srgrimes return(-1); 1181556Srgrimes wrcnt = 0; 1191556Srgrimes bufend = buf + wrblksz; 1201556Srgrimes bufpt = buf; 1211556Srgrimes return(0); 1221556Srgrimes} 1231556Srgrimes 1241556Srgrimes/* 1251556Srgrimes * rd_start() 1261556Srgrimes * set up buffering system to read an archive 1271556Srgrimes * Return: 1281556Srgrimes * 0 if ok, -1 otherwise 1291556Srgrimes */ 1301556Srgrimes 1311556Srgrimesint 1321556Srgrimesrd_start(void) 1331556Srgrimes{ 1341556Srgrimes /* 1351556Srgrimes * leave space for the header pushback (see get_arc()). If we are 1361556Srgrimes * going to append and user specified a write block size, check it 1371556Srgrimes * right away 1381556Srgrimes */ 1391556Srgrimes buf = &(bufmem[BLKMULT]); 1401556Srgrimes if ((act == APPND) && wrblksz) { 1411556Srgrimes if (wrblksz > MAXBLK) { 14276017Skris paxwarn(1,"Write block size %d too large, maximum is: %d", 1431556Srgrimes wrblksz, MAXBLK); 1441556Srgrimes return(-1); 1451556Srgrimes } 1461556Srgrimes if (wrblksz % BLKMULT) { 14776017Skris paxwarn(1, "Write block size %d is not a %d byte multiple", 148222177Suqs wrblksz, BLKMULT); 1491556Srgrimes return(-1); 1501556Srgrimes } 1511556Srgrimes } 1521556Srgrimes 1531556Srgrimes /* 1541556Srgrimes * open the archive 1551556Srgrimes */ 1561556Srgrimes if ((ar_open(arcname) < 0) && (ar_next() < 0)) 1571556Srgrimes return(-1); 1581556Srgrimes bufend = buf + rdblksz; 1591556Srgrimes bufpt = bufend; 1601556Srgrimes rdcnt = 0; 1611556Srgrimes return(0); 1621556Srgrimes} 1631556Srgrimes 1641556Srgrimes/* 1651556Srgrimes * cp_start() 166102230Strhodes * set up buffer system for copying within the file system 1671556Srgrimes */ 1681556Srgrimes 1691556Srgrimesvoid 1701556Srgrimescp_start(void) 1711556Srgrimes{ 1721556Srgrimes buf = &(bufmem[BLKMULT]); 1731556Srgrimes rdblksz = blksz = MAXBLK; 1741556Srgrimes} 1751556Srgrimes 1761556Srgrimes/* 1771556Srgrimes * appnd_start() 1781556Srgrimes * Set up the buffering system to append new members to an archive that 1791556Srgrimes * was just read. The last block(s) of an archive may contain a format 1801556Srgrimes * specific trailer. To append a new member, this trailer has to be 1811556Srgrimes * removed from the archive. The first byte of the trailer is replaced by 1821556Srgrimes * the start of the header of the first file added to the archive. The 1831556Srgrimes * format specific end read function tells us how many bytes to move 1841556Srgrimes * backwards in the archive to be positioned BEFORE the trailer. Two 185222177Suqs * different positions have to be adjusted, the O.S. file offset (e.g. the 1861556Srgrimes * position of the tape head) and the write point within the data we have 1871556Srgrimes * stored in the read (soon to become write) buffer. We may have to move 1881556Srgrimes * back several records (the number depends on the size of the archive 1891556Srgrimes * record and the size of the format trailer) to read up the record where 1901556Srgrimes * the first byte of the trailer is recorded. Trailers may span (and 191222177Suqs * overlap) record boundaries. 1921556Srgrimes * We first calculate which record has the first byte of the trailer. We 1931556Srgrimes * move the OS file offset back to the start of this record and read it 1941556Srgrimes * up. We set the buffer write pointer to be at this byte (the byte where 1951556Srgrimes * the trailer starts). We then move the OS file pointer back to the 1961556Srgrimes * start of this record so a flush of this buffer will replace the record 1971556Srgrimes * in the archive. 1981556Srgrimes * A major problem is rewriting this last record. For archives stored 199222177Suqs * on disk files, this is trivial. However, many devices are really picky 2001556Srgrimes * about the conditions under which they will allow a write to occur. 2011556Srgrimes * Often devices restrict the conditions where writes can be made writes, 202222177Suqs * so it may not be feasible to append archives stored on all types of 2038855Srgrimes * devices. 2041556Srgrimes * Return: 2051556Srgrimes * 0 for success, -1 for failure 2061556Srgrimes */ 2071556Srgrimes 2081556Srgrimesint 2091556Srgrimesappnd_start(off_t skcnt) 2101556Srgrimes{ 21190113Simp int res; 2121556Srgrimes off_t cnt; 2131556Srgrimes 2141556Srgrimes if (exit_val != 0) { 21576017Skris paxwarn(0, "Cannot append to an archive that may have flaws."); 2161556Srgrimes return(-1); 2171556Srgrimes } 2181556Srgrimes /* 2191556Srgrimes * if the user did not specify a write blocksize, inherit the size used 2201556Srgrimes * in the last archive volume read. (If a is set we still use rdblksz 2211556Srgrimes * until next volume, cannot shift sizes within a single volume). 2221556Srgrimes */ 2231556Srgrimes if (!wrblksz) 2241556Srgrimes wrblksz = blksz = rdblksz; 2251556Srgrimes else 2261556Srgrimes blksz = rdblksz; 2271556Srgrimes 2281556Srgrimes /* 2291556Srgrimes * make sure that this volume allows appends 2301556Srgrimes */ 2311556Srgrimes if (ar_app_ok() < 0) 2321556Srgrimes return(-1); 2331556Srgrimes 2341556Srgrimes /* 2351556Srgrimes * Calculate bytes to move back and move in front of record where we 2361556Srgrimes * need to start writing from. Remember we have to add in any padding 2371556Srgrimes * that might be in the buffer after the trailer in the last block. We 2381556Srgrimes * travel skcnt + padding ROUNDED UP to blksize. 2391556Srgrimes */ 2401556Srgrimes skcnt += bufend - bufpt; 2411556Srgrimes if ((cnt = (skcnt/blksz) * blksz) < skcnt) 2421556Srgrimes cnt += blksz; 2431556Srgrimes if (ar_rev((off_t)cnt) < 0) 2441556Srgrimes goto out; 2451556Srgrimes 2461556Srgrimes /* 2471556Srgrimes * We may have gone too far if there is valid data in the block we are 2481556Srgrimes * now in front of, read up the block and position the pointer after 2491556Srgrimes * the valid data. 2501556Srgrimes */ 2511556Srgrimes if ((cnt -= skcnt) > 0) { 2521556Srgrimes /* 2531556Srgrimes * watch out for stupid tape drives. ar_rev() will set rdblksz 2541556Srgrimes * to be real physical blocksize so we must loop until we get 2551556Srgrimes * the old rdblksz (now in blksz). If ar_rev() fouls up the 2561556Srgrimes * determination of the physical block size, we will fail. 2571556Srgrimes */ 2581556Srgrimes bufpt = buf; 2591556Srgrimes bufend = buf + blksz; 2601556Srgrimes while (bufpt < bufend) { 2611556Srgrimes if ((res = ar_read(bufpt, rdblksz)) <= 0) 2621556Srgrimes goto out; 2631556Srgrimes bufpt += res; 2641556Srgrimes } 2651556Srgrimes if (ar_rev((off_t)(bufpt - buf)) < 0) 2661556Srgrimes goto out; 2671556Srgrimes bufpt = buf + cnt; 2681556Srgrimes bufend = buf + blksz; 2691556Srgrimes } else { 2701556Srgrimes /* 2711556Srgrimes * buffer is empty 2721556Srgrimes */ 2731556Srgrimes bufend = buf + blksz; 2741556Srgrimes bufpt = buf; 2751556Srgrimes } 2761556Srgrimes rdblksz = blksz; 2771556Srgrimes rdcnt -= skcnt; 2781556Srgrimes wrcnt = 0; 2791556Srgrimes 2801556Srgrimes /* 2811556Srgrimes * At this point we are ready to write. If the device requires special 2821556Srgrimes * handling to write at a point were previously recorded data resides, 2831556Srgrimes * that is handled in ar_set_wr(). From now on we operate under normal 2841556Srgrimes * ARCHIVE mode (write) conditions 2851556Srgrimes */ 2861556Srgrimes if (ar_set_wr() < 0) 2871556Srgrimes return(-1); 2881556Srgrimes act = ARCHIVE; 2891556Srgrimes return(0); 2901556Srgrimes 2911556Srgrimes out: 29276017Skris paxwarn(1, "Unable to rewrite archive trailer, cannot append."); 2931556Srgrimes return(-1); 2941556Srgrimes} 29576019Skris 2961556Srgrimes/* 2971556Srgrimes * rd_sync() 2981556Srgrimes * A read error occurred on this archive volume. Resync the buffer and 2991556Srgrimes * try to reset the device (if possible) so we can continue to read. Keep 3001556Srgrimes * trying to do this until we get a valid read, or we reach the limit on 3011556Srgrimes * consecutive read faults (at which point we give up). The user can 3021556Srgrimes * adjust the read error limit through a command line option. 3031556Srgrimes * Returns: 3041556Srgrimes * 0 on success, and -1 on failure 3051556Srgrimes */ 3061556Srgrimes 3071556Srgrimesint 3081556Srgrimesrd_sync(void) 3091556Srgrimes{ 31090113Simp int errcnt = 0; 31190113Simp int res; 3121556Srgrimes 3131556Srgrimes /* 3141556Srgrimes * if the user says bail out on first fault, we are out of here... 3151556Srgrimes */ 3161556Srgrimes if (maxflt == 0) 3171556Srgrimes return(-1); 3181556Srgrimes if (act == APPND) { 31976017Skris paxwarn(1, "Unable to append when there are archive read errors."); 3201556Srgrimes return(-1); 3211556Srgrimes } 3221556Srgrimes 3231556Srgrimes /* 3241556Srgrimes * poke at device and try to get past media error 3251556Srgrimes */ 3261556Srgrimes if (ar_rdsync() < 0) { 3271556Srgrimes if (ar_next() < 0) 3281556Srgrimes return(-1); 3291556Srgrimes else 3301556Srgrimes rdcnt = 0; 3311556Srgrimes } 3321556Srgrimes 3331556Srgrimes for (;;) { 3341556Srgrimes if ((res = ar_read(buf, blksz)) > 0) { 3351556Srgrimes /* 3361556Srgrimes * All right! got some data, fill that buffer 3371556Srgrimes */ 3381556Srgrimes bufpt = buf; 3391556Srgrimes bufend = buf + res; 3401556Srgrimes rdcnt += res; 3411556Srgrimes return(0); 3421556Srgrimes } 3431556Srgrimes 3441556Srgrimes /* 3451556Srgrimes * Oh well, yet another failed read... 3461556Srgrimes * if error limit reached, ditch. o.w. poke device to move past 3471556Srgrimes * bad media and try again. if media is badly damaged, we ask 3481556Srgrimes * the poor (and upset user at this point) for the next archive 3491556Srgrimes * volume. remember the goal on reads is to get the most we 3501556Srgrimes * can extract out of the archive. 3511556Srgrimes */ 3521556Srgrimes if ((maxflt > 0) && (++errcnt > maxflt)) 35376017Skris paxwarn(0,"Archive read error limit (%d) reached",maxflt); 3541556Srgrimes else if (ar_rdsync() == 0) 3551556Srgrimes continue; 3561556Srgrimes if (ar_next() < 0) 3571556Srgrimes break; 3581556Srgrimes rdcnt = 0; 3591556Srgrimes errcnt = 0; 3601556Srgrimes } 3611556Srgrimes return(-1); 3621556Srgrimes} 3631556Srgrimes 3641556Srgrimes/* 3651556Srgrimes * pback() 3661556Srgrimes * push the data used during the archive id phase back into the I/O 3671556Srgrimes * buffer. This is required as we cannot be sure that the header does NOT 368222177Suqs * overlap a block boundary (as in the case we are trying to recover a 3691556Srgrimes * flawed archived). This was not designed to be used for any other 3701556Srgrimes * purpose. (What software engineering, HA!) 3711556Srgrimes * WARNING: do not even THINK of pback greater than BLKMULT, unless the 3721556Srgrimes * pback space is increased. 3731556Srgrimes */ 3741556Srgrimes 3751556Srgrimesvoid 3761556Srgrimespback(char *pt, int cnt) 3771556Srgrimes{ 3781556Srgrimes bufpt -= cnt; 37976017Skris memcpy(bufpt, pt, cnt); 3801556Srgrimes return; 3811556Srgrimes} 3821556Srgrimes 3831556Srgrimes/* 3841556Srgrimes * rd_skip() 385222177Suqs * skip forward in the archive during an archive read. Used to get quickly 3861556Srgrimes * past file data and padding for files the user did NOT select. 3871556Srgrimes * Return: 3881556Srgrimes * 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected. 3891556Srgrimes */ 3901556Srgrimes 3911556Srgrimesint 3921556Srgrimesrd_skip(off_t skcnt) 3931556Srgrimes{ 3941556Srgrimes off_t res; 3951556Srgrimes off_t cnt; 3961556Srgrimes off_t skipped = 0; 3971556Srgrimes 3981556Srgrimes /* 399222177Suqs * consume what data we have in the buffer. If we have to move forward 4001556Srgrimes * whole records, we call the low level skip function to see if we can 4011556Srgrimes * move within the archive without doing the expensive reads on data we 4021556Srgrimes * do not want. 4031556Srgrimes */ 4041556Srgrimes if (skcnt == 0) 4051556Srgrimes return(0); 4061556Srgrimes res = MIN((bufend - bufpt), skcnt); 4071556Srgrimes bufpt += res; 4081556Srgrimes skcnt -= res; 4091556Srgrimes 4101556Srgrimes /* 4111556Srgrimes * if skcnt is now 0, then no additional i/o is needed 4121556Srgrimes */ 4131556Srgrimes if (skcnt == 0) 4141556Srgrimes return(0); 4151556Srgrimes 4161556Srgrimes /* 4171556Srgrimes * We have to read more, calculate complete and partial record reads 4181556Srgrimes * based on rdblksz. we skip over "cnt" complete records 4191556Srgrimes */ 4201556Srgrimes res = skcnt%rdblksz; 4211556Srgrimes cnt = (skcnt/rdblksz) * rdblksz; 4221556Srgrimes 4231556Srgrimes /* 4241556Srgrimes * if the skip fails, we will have to resync. ar_fow will tell us 4251556Srgrimes * how much it can skip over. We will have to read the rest. 4261556Srgrimes */ 4271556Srgrimes if (ar_fow(cnt, &skipped) < 0) 4281556Srgrimes return(-1); 4291556Srgrimes res += cnt - skipped; 4301556Srgrimes rdcnt += skipped; 4311556Srgrimes 4321556Srgrimes /* 4331556Srgrimes * what is left we have to read (which may be the whole thing if 4341556Srgrimes * ar_fow() told us the device can only read to skip records); 4351556Srgrimes */ 4361556Srgrimes while (res > 0L) { 4371556Srgrimes cnt = bufend - bufpt; 4381556Srgrimes /* 4391556Srgrimes * if the read fails, we will have to resync 4401556Srgrimes */ 4411556Srgrimes if ((cnt <= 0) && ((cnt = buf_fill()) < 0)) 4421556Srgrimes return(-1); 4431556Srgrimes if (cnt == 0) 4441556Srgrimes return(1); 4451556Srgrimes cnt = MIN(cnt, res); 4461556Srgrimes bufpt += cnt; 4471556Srgrimes res -= cnt; 4481556Srgrimes } 4491556Srgrimes return(0); 4501556Srgrimes} 4511556Srgrimes 4528855Srgrimes/* 4531556Srgrimes * wr_fin() 4541556Srgrimes * flush out any data (and pad if required) the last block. We always pad 4551556Srgrimes * with zero (even though we do not have to). Padding with 0 makes it a 456222177Suqs * lot easier to recover if the archive is damaged. zero padding SHOULD 4571556Srgrimes * BE a requirement.... 4581556Srgrimes */ 4591556Srgrimes 4601556Srgrimesvoid 4611556Srgrimeswr_fin(void) 4621556Srgrimes{ 4631556Srgrimes if (bufpt > buf) { 46476017Skris memset(bufpt, 0, bufend - bufpt); 4651556Srgrimes bufpt = bufend; 4661556Srgrimes (void)buf_flush(blksz); 4671556Srgrimes } 4681556Srgrimes} 4691556Srgrimes 4701556Srgrimes/* 4711556Srgrimes * wr_rdbuf() 4721556Srgrimes * fill the write buffer from data passed to it in a buffer (usually used 4731556Srgrimes * by format specific write routines to pass a file header). On failure we 4741556Srgrimes * punt. We do not allow the user to continue to write flawed archives. 4751556Srgrimes * We assume these headers are not very large (the memory copy we use is 4768855Srgrimes * a bit expensive). 4771556Srgrimes * Return: 4781556Srgrimes * 0 if buffer was filled ok, -1 o.w. (buffer flush failure) 4791556Srgrimes */ 4801556Srgrimes 4811556Srgrimesint 48290113Simpwr_rdbuf(char *out, int outcnt) 4831556Srgrimes{ 48490113Simp int cnt; 4851556Srgrimes 4861556Srgrimes /* 4871556Srgrimes * while there is data to copy copy into the write buffer. when the 4881556Srgrimes * write buffer fills, flush it to the archive and continue 4891556Srgrimes */ 4901556Srgrimes while (outcnt > 0) { 4911556Srgrimes cnt = bufend - bufpt; 4921556Srgrimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) 4931556Srgrimes return(-1); 4941556Srgrimes /* 4951556Srgrimes * only move what we have space for 4961556Srgrimes */ 4971556Srgrimes cnt = MIN(cnt, outcnt); 49876017Skris memcpy(bufpt, out, cnt); 4991556Srgrimes bufpt += cnt; 5001556Srgrimes out += cnt; 5011556Srgrimes outcnt -= cnt; 5021556Srgrimes } 5031556Srgrimes return(0); 5041556Srgrimes} 5051556Srgrimes 5061556Srgrimes/* 5071556Srgrimes * rd_wrbuf() 5081556Srgrimes * copy from the read buffer into a supplied buffer a specified number of 5091556Srgrimes * bytes. If the read buffer is empty fill it and continue to copy. 5101556Srgrimes * usually used to obtain a file header for processing by a format 5111556Srgrimes * specific read routine. 5121556Srgrimes * Return 5131556Srgrimes * number of bytes copied to the buffer, 0 indicates EOF on archive volume, 5141556Srgrimes * -1 is a read error 5151556Srgrimes */ 5161556Srgrimes 5171556Srgrimesint 51890113Simprd_wrbuf(char *in, int cpcnt) 5191556Srgrimes{ 52090113Simp int res; 52190113Simp int cnt; 52290113Simp int incnt = cpcnt; 5231556Srgrimes 5241556Srgrimes /* 5251556Srgrimes * loop until we fill the buffer with the requested number of bytes 5261556Srgrimes */ 5271556Srgrimes while (incnt > 0) { 5281556Srgrimes cnt = bufend - bufpt; 5291556Srgrimes if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) { 5301556Srgrimes /* 5311556Srgrimes * read error, return what we got (or the error if 5321556Srgrimes * no data was copied). The caller must know that an 533222177Suqs * error occurred and has the best knowledge what to 5341556Srgrimes * do with it 5351556Srgrimes */ 5361556Srgrimes if ((res = cpcnt - incnt) > 0) 5371556Srgrimes return(res); 5381556Srgrimes return(cnt); 5391556Srgrimes } 5401556Srgrimes 5411556Srgrimes /* 5421556Srgrimes * calculate how much data to copy based on whats left and 5431556Srgrimes * state of buffer 5441556Srgrimes */ 5451556Srgrimes cnt = MIN(cnt, incnt); 54676017Skris memcpy(in, bufpt, cnt); 5471556Srgrimes bufpt += cnt; 5481556Srgrimes incnt -= cnt; 5491556Srgrimes in += cnt; 5501556Srgrimes } 5511556Srgrimes return(cpcnt); 5521556Srgrimes} 5531556Srgrimes 5541556Srgrimes/* 5551556Srgrimes * wr_skip() 55646684Skris * skip forward during a write. In other words add padding to the file. 5571556Srgrimes * we add zero filled padding as it makes flawed archives much easier to 5581556Srgrimes * recover from. the caller tells us how many bytes of padding to add 5591556Srgrimes * This routine was not designed to add HUGE amount of padding, just small 5601556Srgrimes * amounts (a few 512 byte blocks at most) 5611556Srgrimes * Return: 5621556Srgrimes * 0 if ok, -1 if there was a buf_flush failure 5631556Srgrimes */ 5641556Srgrimes 5651556Srgrimesint 5661556Srgrimeswr_skip(off_t skcnt) 5671556Srgrimes{ 56890113Simp int cnt; 5691556Srgrimes 5701556Srgrimes /* 5711556Srgrimes * loop while there is more padding to add 5721556Srgrimes */ 5731556Srgrimes while (skcnt > 0L) { 5741556Srgrimes cnt = bufend - bufpt; 5751556Srgrimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) 5761556Srgrimes return(-1); 5771556Srgrimes cnt = MIN(cnt, skcnt); 57876017Skris memset(bufpt, 0, cnt); 5791556Srgrimes bufpt += cnt; 5801556Srgrimes skcnt -= cnt; 5811556Srgrimes } 5821556Srgrimes return(0); 5831556Srgrimes} 5841556Srgrimes 5851556Srgrimes/* 5861556Srgrimes * wr_rdfile() 587222177Suqs * fill write buffer with the contents of a file. We are passed an open 588100012Skeramida * file descriptor to the file and the archive structure that describes the 5891556Srgrimes * file we are storing. The variable "left" is modified to contain the 5901556Srgrimes * number of bytes of the file we were NOT able to write to the archive. 5911556Srgrimes * it is important that we always write EXACTLY the number of bytes that 5921556Srgrimes * the format specific write routine told us to. The file can also get 5931556Srgrimes * bigger, so reading to the end of file would create an improper archive, 59476017Skris * we just detect this case and warn the user. We never create a bad 5951556Srgrimes * archive if we can avoid it. Of course trying to archive files that are 5961556Srgrimes * active is asking for trouble. It we fail, we pass back how much we 5971556Srgrimes * could NOT copy and let the caller deal with it. 5981556Srgrimes * Return: 5991556Srgrimes * 0 ok, -1 if archive write failure. a short read of the file returns a 6001556Srgrimes * 0, but "left" is set to be greater than zero. 6011556Srgrimes */ 6021556Srgrimes 6031556Srgrimesint 6041556Srgrimeswr_rdfile(ARCHD *arcn, int ifd, off_t *left) 6051556Srgrimes{ 60690113Simp int cnt; 60790113Simp int res = 0; 60890113Simp off_t size = arcn->sb.st_size; 6091556Srgrimes struct stat sb; 6101556Srgrimes 6111556Srgrimes /* 6121556Srgrimes * while there are more bytes to write 6131556Srgrimes */ 6141556Srgrimes while (size > 0L) { 6151556Srgrimes cnt = bufend - bufpt; 6161556Srgrimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) { 6171556Srgrimes *left = size; 6181556Srgrimes return(-1); 6191556Srgrimes } 6201556Srgrimes cnt = MIN(cnt, size); 6211556Srgrimes if ((res = read(ifd, bufpt, cnt)) <= 0) 6221556Srgrimes break; 6231556Srgrimes size -= res; 6241556Srgrimes bufpt += res; 6251556Srgrimes } 6261556Srgrimes 6271556Srgrimes /* 6281556Srgrimes * better check the file did not change during this operation 6291556Srgrimes * or the file read failed. 6301556Srgrimes */ 6311556Srgrimes if (res < 0) 63276017Skris syswarn(1, errno, "Read fault on %s", arcn->org_name); 6331556Srgrimes else if (size != 0L) 63476017Skris paxwarn(1, "File changed size during read %s", arcn->org_name); 6351556Srgrimes else if (fstat(ifd, &sb) < 0) 63676017Skris syswarn(1, errno, "Failed stat on %s", arcn->org_name); 6371556Srgrimes else if (arcn->sb.st_mtime != sb.st_mtime) 63876017Skris paxwarn(1, "File %s was modified during copy to archive", 6391556Srgrimes arcn->org_name); 6401556Srgrimes *left = size; 6411556Srgrimes return(0); 6421556Srgrimes} 6431556Srgrimes 6441556Srgrimes/* 6451556Srgrimes * rd_wrfile() 6461556Srgrimes * extract the contents of a file from the archive. If we are unable to 6471556Srgrimes * extract the entire file (due to failure to write the file) we return 6481556Srgrimes * the numbers of bytes we did NOT process. This way the caller knows how 6491556Srgrimes * many bytes to skip past to find the next archive header. If the failure 6501556Srgrimes * was due to an archive read, we will catch that when we try to skip. If 6511556Srgrimes * the format supplies a file data crc value, we calculate the actual crc 6521556Srgrimes * so that it can be compared to the value stored in the header 6531556Srgrimes * NOTE: 6541556Srgrimes * We call a special function to write the file. This function attempts to 6551556Srgrimes * restore file holes (blocks of zeros) into the file. When files are 6561556Srgrimes * sparse this saves space, and is a LOT faster. For non sparse files 6571556Srgrimes * the performance hit is small. As of this writing, no archive supports 6581556Srgrimes * information on where the file holes are. 6591556Srgrimes * Return: 6601556Srgrimes * 0 ok, -1 if archive read failure. if we cannot write the entire file, 6611556Srgrimes * we return a 0 but "left" is set to be the amount unwritten 6621556Srgrimes */ 6631556Srgrimes 6641556Srgrimesint 6651556Srgrimesrd_wrfile(ARCHD *arcn, int ofd, off_t *left) 6661556Srgrimes{ 66790113Simp int cnt = 0; 66890113Simp off_t size = arcn->sb.st_size; 66990113Simp int res = 0; 67090113Simp char *fnm = arcn->name; 6711556Srgrimes int isem = 1; 6721556Srgrimes int rem; 6731556Srgrimes int sz = MINFBSZ; 674222177Suqs struct stat sb; 6751556Srgrimes u_long crc = 0L; 6761556Srgrimes 6771556Srgrimes /* 6781556Srgrimes * pass the blocksize of the file being written to the write routine, 6791556Srgrimes * if the size is zero, use the default MINFBSZ 6801556Srgrimes */ 68176019Skris if (fstat(ofd, &sb) == 0) { 6821556Srgrimes if (sb.st_blksize > 0) 6831556Srgrimes sz = (int)sb.st_blksize; 68476019Skris } else 68576019Skris syswarn(0,errno,"Unable to obtain block size for file %s",fnm); 6861556Srgrimes rem = sz; 6871556Srgrimes *left = 0L; 6881556Srgrimes 6891556Srgrimes /* 6901556Srgrimes * Copy the archive to the file the number of bytes specified. We have 6911556Srgrimes * to assume that we want to recover file holes as none of the archive 6921556Srgrimes * formats can record the location of file holes. 6931556Srgrimes */ 6941556Srgrimes while (size > 0L) { 6951556Srgrimes cnt = bufend - bufpt; 6961556Srgrimes /* 6971556Srgrimes * if we get a read error, we do not want to skip, as we may 6981556Srgrimes * miss a header, so we do not set left, but if we get a write 6991556Srgrimes * error, we do want to skip over the unprocessed data. 7001556Srgrimes */ 7011556Srgrimes if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) 7021556Srgrimes break; 7031556Srgrimes cnt = MIN(cnt, size); 7041556Srgrimes if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) { 7051556Srgrimes *left = size; 7061556Srgrimes break; 7071556Srgrimes } 7081556Srgrimes 7091556Srgrimes if (docrc) { 7101556Srgrimes /* 7111556Srgrimes * update the actual crc value 7121556Srgrimes */ 7131556Srgrimes cnt = res; 7141556Srgrimes while (--cnt >= 0) 7151556Srgrimes crc += *bufpt++ & 0xff; 7161556Srgrimes } else 7171556Srgrimes bufpt += res; 7181556Srgrimes size -= res; 7191556Srgrimes } 7201556Srgrimes 7211556Srgrimes /* 7221556Srgrimes * if the last block has a file hole (all zero), we must make sure this 7231556Srgrimes * gets updated in the file. We force the last block of zeros to be 72446684Skris * written. just closing with the file offset moved forward may not put 7251556Srgrimes * a hole at the end of the file. 7261556Srgrimes */ 7271556Srgrimes if (isem && (arcn->sb.st_size > 0L)) 7281556Srgrimes file_flush(ofd, fnm, isem); 7291556Srgrimes 7301556Srgrimes /* 7311556Srgrimes * if we failed from archive read, we do not want to skip 7321556Srgrimes */ 7338855Srgrimes if ((size > 0L) && (*left == 0L)) 7341556Srgrimes return(-1); 7351556Srgrimes 7361556Srgrimes /* 7371556Srgrimes * some formats record a crc on file data. If so, then we compare the 7381556Srgrimes * calculated crc to the crc stored in the archive 7391556Srgrimes */ 7401556Srgrimes if (docrc && (size == 0L) && (arcn->crc != crc)) 74176017Skris paxwarn(1,"Actual crc does not match expected crc %s",arcn->name); 7421556Srgrimes return(0); 7431556Srgrimes} 7441556Srgrimes 7451556Srgrimes/* 7461556Srgrimes * cp_file() 7471556Srgrimes * copy the contents of one file to another. used during -rw phase of pax 7481556Srgrimes * just as in rd_wrfile() we use a special write function to write the 7491556Srgrimes * destination file so we can properly copy files with holes. 7501556Srgrimes */ 7511556Srgrimes 7521556Srgrimesvoid 7531556Srgrimescp_file(ARCHD *arcn, int fd1, int fd2) 7541556Srgrimes{ 75590113Simp int cnt; 75690113Simp off_t cpcnt = 0L; 75790113Simp int res = 0; 75890113Simp char *fnm = arcn->name; 75990113Simp int no_hole = 0; 7601556Srgrimes int isem = 1; 7611556Srgrimes int rem; 7621556Srgrimes int sz = MINFBSZ; 7631556Srgrimes struct stat sb; 7641556Srgrimes 7651556Srgrimes /* 7661556Srgrimes * check for holes in the source file. If none, we will use regular 7671556Srgrimes * write instead of file write. 7681556Srgrimes */ 7691556Srgrimes if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size) 7701556Srgrimes ++no_hole; 7711556Srgrimes 7721556Srgrimes /* 7731556Srgrimes * pass the blocksize of the file being written to the write routine, 7741556Srgrimes * if the size is zero, use the default MINFBSZ 7751556Srgrimes */ 77676019Skris if (fstat(fd2, &sb) == 0) { 7771556Srgrimes if (sb.st_blksize > 0) 7781556Srgrimes sz = sb.st_blksize; 77976019Skris } else 78076019Skris syswarn(0,errno,"Unable to obtain block size for file %s",fnm); 7811556Srgrimes rem = sz; 7821556Srgrimes 7831556Srgrimes /* 7841556Srgrimes * read the source file and copy to destination file until EOF 7851556Srgrimes */ 7861556Srgrimes for(;;) { 7871556Srgrimes if ((cnt = read(fd1, buf, blksz)) <= 0) 7881556Srgrimes break; 7891556Srgrimes if (no_hole) 7901556Srgrimes res = write(fd2, buf, cnt); 7911556Srgrimes else 7921556Srgrimes res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm); 7931556Srgrimes if (res != cnt) 7941556Srgrimes break; 7951556Srgrimes cpcnt += cnt; 7961556Srgrimes } 7971556Srgrimes 7981556Srgrimes /* 7991556Srgrimes * check to make sure the copy is valid. 8001556Srgrimes */ 8011556Srgrimes if (res < 0) 80276017Skris syswarn(1, errno, "Failed write during copy of %s to %s", 8031556Srgrimes arcn->org_name, arcn->name); 8041556Srgrimes else if (cpcnt != arcn->sb.st_size) 80576017Skris paxwarn(1, "File %s changed size during copy to %s", 8061556Srgrimes arcn->org_name, arcn->name); 8071556Srgrimes else if (fstat(fd1, &sb) < 0) 80876017Skris syswarn(1, errno, "Failed stat of %s", arcn->org_name); 8091556Srgrimes else if (arcn->sb.st_mtime != sb.st_mtime) 81076017Skris paxwarn(1, "File %s was modified during copy to %s", 8111556Srgrimes arcn->org_name, arcn->name); 8121556Srgrimes 8131556Srgrimes /* 8141556Srgrimes * if the last block has a file hole (all zero), we must make sure this 8151556Srgrimes * gets updated in the file. We force the last block of zeros to be 81646684Skris * written. just closing with the file offset moved forward may not put 8171556Srgrimes * a hole at the end of the file. 8181556Srgrimes */ 8191556Srgrimes if (!no_hole && isem && (arcn->sb.st_size > 0L)) 8201556Srgrimes file_flush(fd2, fnm, isem); 8211556Srgrimes return; 8221556Srgrimes} 8231556Srgrimes 8241556Srgrimes/* 8251556Srgrimes * buf_fill() 8261556Srgrimes * fill the read buffer with the next record (or what we can get) from 8271556Srgrimes * the archive volume. 8281556Srgrimes * Return: 8291556Srgrimes * Number of bytes of data in the read buffer, -1 for read error, and 8301556Srgrimes * 0 when finished (user specified termination in ar_next()). 8311556Srgrimes */ 8321556Srgrimes 8331556Srgrimesint 8341556Srgrimesbuf_fill(void) 8351556Srgrimes{ 83690113Simp int cnt; 8371556Srgrimes static int fini = 0; 8381556Srgrimes 8391556Srgrimes if (fini) 8401556Srgrimes return(0); 8411556Srgrimes 8421556Srgrimes for(;;) { 8431556Srgrimes /* 8441556Srgrimes * try to fill the buffer. on error the next archive volume is 8451556Srgrimes * opened and we try again. 8461556Srgrimes */ 8471556Srgrimes if ((cnt = ar_read(buf, blksz)) > 0) { 8481556Srgrimes bufpt = buf; 8491556Srgrimes bufend = buf + cnt; 8501556Srgrimes rdcnt += cnt; 8511556Srgrimes return(cnt); 8521556Srgrimes } 8531556Srgrimes 8541556Srgrimes /* 8551556Srgrimes * errors require resync, EOF goes to next archive 8561556Srgrimes */ 8571556Srgrimes if (cnt < 0) 8581556Srgrimes break; 8591556Srgrimes if (ar_next() < 0) { 8601556Srgrimes fini = 1; 8611556Srgrimes return(0); 8621556Srgrimes } 8631556Srgrimes rdcnt = 0; 8641556Srgrimes } 8651556Srgrimes exit_val = 1; 8661556Srgrimes return(-1); 8671556Srgrimes} 8681556Srgrimes 8691556Srgrimes/* 8701556Srgrimes * buf_flush() 8711556Srgrimes * force the write buffer to the archive. We are passed the number of 8721556Srgrimes * bytes in the buffer at the point of the flush. When we change archives 8731556Srgrimes * the record size might change. (either larger or smaller). 8741556Srgrimes * Return: 8751556Srgrimes * 0 if all is ok, -1 when a write error occurs. 8761556Srgrimes */ 8771556Srgrimes 8781556Srgrimesint 87990113Simpbuf_flush(int bufcnt) 8801556Srgrimes{ 88190113Simp int cnt; 88290113Simp int push = 0; 88390113Simp int totcnt = 0; 8841556Srgrimes 8851556Srgrimes /* 8861556Srgrimes * if we have reached the user specified byte count for each archive 887222177Suqs * volume, prompt for the next volume. (The non-standard -R flag). 8881556Srgrimes * NOTE: If the wrlimit is smaller than wrcnt, we will always write 8891556Srgrimes * at least one record. We always round limit UP to next blocksize. 8901556Srgrimes */ 8911556Srgrimes if ((wrlimit > 0) && (wrcnt > wrlimit)) { 89276017Skris paxwarn(0, "User specified archive volume byte limit reached."); 8931556Srgrimes if (ar_next() < 0) { 8941556Srgrimes wrcnt = 0; 8951556Srgrimes exit_val = 1; 8961556Srgrimes return(-1); 8971556Srgrimes } 8981556Srgrimes wrcnt = 0; 8991556Srgrimes 9001556Srgrimes /* 9011556Srgrimes * The new archive volume might have changed the size of the 9021556Srgrimes * write blocksize. if so we figure out if we need to write 9031556Srgrimes * (one or more times), or if there is now free space left in 9041556Srgrimes * the buffer (it is no longer full). bufcnt has the number of 9051556Srgrimes * bytes in the buffer, (the blocksize, at the point we were 9061556Srgrimes * CALLED). Push has the amount of "extra" data in the buffer 9071556Srgrimes * if the block size has shrunk from a volume change. 9081556Srgrimes */ 9091556Srgrimes bufend = buf + blksz; 9101556Srgrimes if (blksz > bufcnt) 9111556Srgrimes return(0); 9121556Srgrimes if (blksz < bufcnt) 9131556Srgrimes push = bufcnt - blksz; 9141556Srgrimes } 9151556Srgrimes 9161556Srgrimes /* 9171556Srgrimes * We have enough data to write at least one archive block 9181556Srgrimes */ 9191556Srgrimes for (;;) { 9201556Srgrimes /* 9211556Srgrimes * write a block and check if it all went out ok 9221556Srgrimes */ 9238855Srgrimes cnt = ar_write(buf, blksz); 9241556Srgrimes if (cnt == blksz) { 9251556Srgrimes /* 9261556Srgrimes * the write went ok 9271556Srgrimes */ 9281556Srgrimes wrcnt += cnt; 9291556Srgrimes totcnt += cnt; 9301556Srgrimes if (push > 0) { 9311556Srgrimes /* we have extra data to push to the front. 9321556Srgrimes * check for more than 1 block of push, and if 9331556Srgrimes * so we loop back to write again 9341556Srgrimes */ 93576017Skris memcpy(buf, bufend, push); 9361556Srgrimes bufpt = buf + push; 9371556Srgrimes if (push >= blksz) { 9381556Srgrimes push -= blksz; 9391556Srgrimes continue; 9401556Srgrimes } 9411556Srgrimes } else 9421556Srgrimes bufpt = buf; 9431556Srgrimes return(totcnt); 9441556Srgrimes } else if (cnt > 0) { 9451556Srgrimes /* 9461556Srgrimes * Oh drat we got a partial write! 947222177Suqs * if format doesn't care about alignment let it go, 94876017Skris * we warned the user in ar_write().... but this means 9491556Srgrimes * the last record on this volume violates pax spec.... 9501556Srgrimes */ 9511556Srgrimes totcnt += cnt; 9521556Srgrimes wrcnt += cnt; 9531556Srgrimes bufpt = buf + cnt; 9541556Srgrimes cnt = bufcnt - cnt; 95576017Skris memcpy(buf, bufpt, cnt); 9561556Srgrimes bufpt = buf + cnt; 9571556Srgrimes if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0)) 9581556Srgrimes return(totcnt); 9591556Srgrimes break; 9601556Srgrimes } 9611556Srgrimes 9621556Srgrimes /* 9631556Srgrimes * All done, go to next archive 9641556Srgrimes */ 9651556Srgrimes wrcnt = 0; 9661556Srgrimes if (ar_next() < 0) 9671556Srgrimes break; 9681556Srgrimes 9691556Srgrimes /* 9701556Srgrimes * The new archive volume might also have changed the block 9711556Srgrimes * size. if so, figure out if we have too much or too little 9721556Srgrimes * data for using the new block size 9731556Srgrimes */ 9741556Srgrimes bufend = buf + blksz; 9751556Srgrimes if (blksz > bufcnt) 9761556Srgrimes return(0); 9771556Srgrimes if (blksz < bufcnt) 9781556Srgrimes push = bufcnt - blksz; 9791556Srgrimes } 9801556Srgrimes 9811556Srgrimes /* 9821556Srgrimes * write failed, stop pax. we must not create a bad archive! 9831556Srgrimes */ 9841556Srgrimes exit_val = 1; 9851556Srgrimes return(-1); 9861556Srgrimes} 987