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: stable/10/bin/pax/buf_subs.c 310606 2016-12-26 16:43:39Z pfg $"); 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 <string.h> 481556Srgrimes#include "pax.h" 491556Srgrimes#include "extern.h" 501556Srgrimes 511556Srgrimes/* 521556Srgrimes * routines which implement archive and file buffering 531556Srgrimes */ 541556Srgrimes 551556Srgrimes#define MINFBSZ 512 /* default block size for hole detect */ 5676019Skris#define MAXFLT 10 /* default media read error limit */ 571556Srgrimes 581556Srgrimes/* 591556Srgrimes * Need to change bufmem to dynamic allocation when the upper 601556Srgrimes * limit on blocking size is removed (though that will violate pax spec) 611556Srgrimes * MAXBLK define and tests will also need to be updated. 621556Srgrimes */ 631556Srgrimesstatic char bufmem[MAXBLK+BLKMULT]; /* i/o buffer + pushback id space */ 641556Srgrimesstatic char *buf; /* normal start of i/o buffer */ 651556Srgrimesstatic char *bufend; /* end or last char in i/o buffer */ 661556Srgrimesstatic char *bufpt; /* read/write point in i/o buffer */ 6776019Skrisint blksz = MAXBLK; /* block input/output size in bytes */ 6876019Skrisint wrblksz; /* user spec output size in bytes */ 691556Srgrimesint maxflt = MAXFLT; /* MAX consecutive media errors */ 701556Srgrimesint rdblksz; /* first read blksize (tapes only) */ 711556Srgrimesoff_t wrlimit; /* # of bytes written per archive vol */ 721556Srgrimesoff_t wrcnt; /* # of bytes written on current vol */ 731556Srgrimesoff_t rdcnt; /* # of bytes read on current vol */ 741556Srgrimes 751556Srgrimes/* 761556Srgrimes * wr_start() 771556Srgrimes * set up the buffering system to operate in a write mode 781556Srgrimes * Return: 791556Srgrimes * 0 if ok, -1 if the user specified write block size violates pax spec 801556Srgrimes */ 811556Srgrimes 821556Srgrimesint 831556Srgrimeswr_start(void) 841556Srgrimes{ 851556Srgrimes buf = &(bufmem[BLKMULT]); 861556Srgrimes /* 871556Srgrimes * Check to make sure the write block size meets pax specs. If the user 881556Srgrimes * does not specify a blocksize, we use the format default blocksize. 891556Srgrimes * We must be picky on writes, so we do not allow the user to create an 901556Srgrimes * archive that might be hard to read elsewhere. If all ok, we then 911556Srgrimes * open the first archive volume 921556Srgrimes */ 938855Srgrimes if (!wrblksz) 941556Srgrimes wrblksz = frmt->bsz; 951556Srgrimes if (wrblksz > MAXBLK) { 9676017Skris paxwarn(1, "Write block size of %d too large, maximum is: %d", 971556Srgrimes wrblksz, MAXBLK); 981556Srgrimes return(-1); 991556Srgrimes } 1001556Srgrimes if (wrblksz % BLKMULT) { 10176017Skris paxwarn(1, "Write block size of %d is not a %d byte multiple", 1021556Srgrimes wrblksz, BLKMULT); 1031556Srgrimes return(-1); 1041556Srgrimes } 10576351Skris if (wrblksz > MAXBLK_POSIX) { 10676351Skris paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable", 10776351Skris wrblksz, MAXBLK_POSIX); 10876351Skris return(-1); 10976351Skris } 1101556Srgrimes 1111556Srgrimes /* 1128855Srgrimes * we only allow wrblksz to be used with all archive operations 1131556Srgrimes */ 1141556Srgrimes blksz = rdblksz = wrblksz; 1151556Srgrimes if ((ar_open(arcname) < 0) && (ar_next() < 0)) 1161556Srgrimes return(-1); 1171556Srgrimes wrcnt = 0; 1181556Srgrimes bufend = buf + wrblksz; 1191556Srgrimes bufpt = buf; 1201556Srgrimes return(0); 1211556Srgrimes} 1221556Srgrimes 1231556Srgrimes/* 1241556Srgrimes * rd_start() 1251556Srgrimes * set up buffering system to read an archive 1261556Srgrimes * Return: 1271556Srgrimes * 0 if ok, -1 otherwise 1281556Srgrimes */ 1291556Srgrimes 1301556Srgrimesint 1311556Srgrimesrd_start(void) 1321556Srgrimes{ 1331556Srgrimes /* 1341556Srgrimes * leave space for the header pushback (see get_arc()). If we are 1351556Srgrimes * going to append and user specified a write block size, check it 1361556Srgrimes * right away 1371556Srgrimes */ 1381556Srgrimes buf = &(bufmem[BLKMULT]); 1391556Srgrimes if ((act == APPND) && wrblksz) { 1401556Srgrimes if (wrblksz > MAXBLK) { 14176017Skris paxwarn(1,"Write block size %d too large, maximum is: %d", 1421556Srgrimes wrblksz, MAXBLK); 1431556Srgrimes return(-1); 1441556Srgrimes } 1451556Srgrimes if (wrblksz % BLKMULT) { 14676017Skris paxwarn(1, "Write block size %d is not a %d byte multiple", 147222177Suqs wrblksz, BLKMULT); 1481556Srgrimes return(-1); 1491556Srgrimes } 1501556Srgrimes } 1511556Srgrimes 1521556Srgrimes /* 1531556Srgrimes * open the archive 1541556Srgrimes */ 1551556Srgrimes if ((ar_open(arcname) < 0) && (ar_next() < 0)) 1561556Srgrimes return(-1); 1571556Srgrimes bufend = buf + rdblksz; 1581556Srgrimes bufpt = bufend; 1591556Srgrimes rdcnt = 0; 1601556Srgrimes return(0); 1611556Srgrimes} 1621556Srgrimes 1631556Srgrimes/* 1641556Srgrimes * cp_start() 165102230Strhodes * set up buffer system for copying within the file system 1661556Srgrimes */ 1671556Srgrimes 1681556Srgrimesvoid 1691556Srgrimescp_start(void) 1701556Srgrimes{ 1711556Srgrimes buf = &(bufmem[BLKMULT]); 1721556Srgrimes rdblksz = blksz = MAXBLK; 1731556Srgrimes} 1741556Srgrimes 1751556Srgrimes/* 1761556Srgrimes * appnd_start() 1771556Srgrimes * Set up the buffering system to append new members to an archive that 1781556Srgrimes * was just read. The last block(s) of an archive may contain a format 1791556Srgrimes * specific trailer. To append a new member, this trailer has to be 1801556Srgrimes * removed from the archive. The first byte of the trailer is replaced by 1811556Srgrimes * the start of the header of the first file added to the archive. The 1821556Srgrimes * format specific end read function tells us how many bytes to move 1831556Srgrimes * backwards in the archive to be positioned BEFORE the trailer. Two 184222177Suqs * different positions have to be adjusted, the O.S. file offset (e.g. the 1851556Srgrimes * position of the tape head) and the write point within the data we have 1861556Srgrimes * stored in the read (soon to become write) buffer. We may have to move 1871556Srgrimes * back several records (the number depends on the size of the archive 1881556Srgrimes * record and the size of the format trailer) to read up the record where 1891556Srgrimes * the first byte of the trailer is recorded. Trailers may span (and 190222177Suqs * overlap) record boundaries. 1911556Srgrimes * We first calculate which record has the first byte of the trailer. We 1921556Srgrimes * move the OS file offset back to the start of this record and read it 1931556Srgrimes * up. We set the buffer write pointer to be at this byte (the byte where 1941556Srgrimes * the trailer starts). We then move the OS file pointer back to the 1951556Srgrimes * start of this record so a flush of this buffer will replace the record 1961556Srgrimes * in the archive. 1971556Srgrimes * A major problem is rewriting this last record. For archives stored 198222177Suqs * on disk files, this is trivial. However, many devices are really picky 1991556Srgrimes * about the conditions under which they will allow a write to occur. 2001556Srgrimes * Often devices restrict the conditions where writes can be made writes, 201222177Suqs * so it may not be feasible to append archives stored on all types of 2028855Srgrimes * devices. 2031556Srgrimes * Return: 2041556Srgrimes * 0 for success, -1 for failure 2051556Srgrimes */ 2061556Srgrimes 2071556Srgrimesint 2081556Srgrimesappnd_start(off_t skcnt) 2091556Srgrimes{ 21090113Simp int res; 2111556Srgrimes off_t cnt; 2121556Srgrimes 2131556Srgrimes if (exit_val != 0) { 21476017Skris paxwarn(0, "Cannot append to an archive that may have flaws."); 2151556Srgrimes return(-1); 2161556Srgrimes } 2171556Srgrimes /* 2181556Srgrimes * if the user did not specify a write blocksize, inherit the size used 2191556Srgrimes * in the last archive volume read. (If a is set we still use rdblksz 2201556Srgrimes * until next volume, cannot shift sizes within a single volume). 2211556Srgrimes */ 2221556Srgrimes if (!wrblksz) 2231556Srgrimes wrblksz = blksz = rdblksz; 2241556Srgrimes else 2251556Srgrimes blksz = rdblksz; 2261556Srgrimes 2271556Srgrimes /* 2281556Srgrimes * make sure that this volume allows appends 2291556Srgrimes */ 2301556Srgrimes if (ar_app_ok() < 0) 2311556Srgrimes return(-1); 2321556Srgrimes 2331556Srgrimes /* 2341556Srgrimes * Calculate bytes to move back and move in front of record where we 2351556Srgrimes * need to start writing from. Remember we have to add in any padding 2361556Srgrimes * that might be in the buffer after the trailer in the last block. We 2371556Srgrimes * travel skcnt + padding ROUNDED UP to blksize. 2381556Srgrimes */ 2391556Srgrimes skcnt += bufend - bufpt; 2401556Srgrimes if ((cnt = (skcnt/blksz) * blksz) < skcnt) 2411556Srgrimes cnt += blksz; 2421556Srgrimes if (ar_rev((off_t)cnt) < 0) 2431556Srgrimes goto out; 2441556Srgrimes 2451556Srgrimes /* 2461556Srgrimes * We may have gone too far if there is valid data in the block we are 2471556Srgrimes * now in front of, read up the block and position the pointer after 2481556Srgrimes * the valid data. 2491556Srgrimes */ 2501556Srgrimes if ((cnt -= skcnt) > 0) { 2511556Srgrimes /* 2521556Srgrimes * watch out for stupid tape drives. ar_rev() will set rdblksz 2531556Srgrimes * to be real physical blocksize so we must loop until we get 2541556Srgrimes * the old rdblksz (now in blksz). If ar_rev() fouls up the 2551556Srgrimes * determination of the physical block size, we will fail. 2561556Srgrimes */ 2571556Srgrimes bufpt = buf; 2581556Srgrimes bufend = buf + blksz; 2591556Srgrimes while (bufpt < bufend) { 2601556Srgrimes if ((res = ar_read(bufpt, rdblksz)) <= 0) 2611556Srgrimes goto out; 2621556Srgrimes bufpt += res; 2631556Srgrimes } 2641556Srgrimes if (ar_rev((off_t)(bufpt - buf)) < 0) 2651556Srgrimes goto out; 2661556Srgrimes bufpt = buf + cnt; 2671556Srgrimes bufend = buf + blksz; 2681556Srgrimes } else { 2691556Srgrimes /* 2701556Srgrimes * buffer is empty 2711556Srgrimes */ 2721556Srgrimes bufend = buf + blksz; 2731556Srgrimes bufpt = buf; 2741556Srgrimes } 2751556Srgrimes rdblksz = blksz; 2761556Srgrimes rdcnt -= skcnt; 2771556Srgrimes wrcnt = 0; 2781556Srgrimes 2791556Srgrimes /* 2801556Srgrimes * At this point we are ready to write. If the device requires special 2811556Srgrimes * handling to write at a point were previously recorded data resides, 2821556Srgrimes * that is handled in ar_set_wr(). From now on we operate under normal 2831556Srgrimes * ARCHIVE mode (write) conditions 2841556Srgrimes */ 2851556Srgrimes if (ar_set_wr() < 0) 2861556Srgrimes return(-1); 2871556Srgrimes act = ARCHIVE; 2881556Srgrimes return(0); 2891556Srgrimes 2901556Srgrimes out: 29176017Skris paxwarn(1, "Unable to rewrite archive trailer, cannot append."); 2921556Srgrimes return(-1); 2931556Srgrimes} 29476019Skris 2951556Srgrimes/* 2961556Srgrimes * rd_sync() 2971556Srgrimes * A read error occurred on this archive volume. Resync the buffer and 2981556Srgrimes * try to reset the device (if possible) so we can continue to read. Keep 2991556Srgrimes * trying to do this until we get a valid read, or we reach the limit on 3001556Srgrimes * consecutive read faults (at which point we give up). The user can 3011556Srgrimes * adjust the read error limit through a command line option. 3021556Srgrimes * Returns: 3031556Srgrimes * 0 on success, and -1 on failure 3041556Srgrimes */ 3051556Srgrimes 3061556Srgrimesint 3071556Srgrimesrd_sync(void) 3081556Srgrimes{ 30990113Simp int errcnt = 0; 31090113Simp int res; 3111556Srgrimes 3121556Srgrimes /* 3131556Srgrimes * if the user says bail out on first fault, we are out of here... 3141556Srgrimes */ 3151556Srgrimes if (maxflt == 0) 3161556Srgrimes return(-1); 3171556Srgrimes if (act == APPND) { 31876017Skris paxwarn(1, "Unable to append when there are archive read errors."); 3191556Srgrimes return(-1); 3201556Srgrimes } 3211556Srgrimes 3221556Srgrimes /* 3231556Srgrimes * poke at device and try to get past media error 3241556Srgrimes */ 3251556Srgrimes if (ar_rdsync() < 0) { 3261556Srgrimes if (ar_next() < 0) 3271556Srgrimes return(-1); 3281556Srgrimes else 3291556Srgrimes rdcnt = 0; 3301556Srgrimes } 3311556Srgrimes 3321556Srgrimes for (;;) { 3331556Srgrimes if ((res = ar_read(buf, blksz)) > 0) { 3341556Srgrimes /* 3351556Srgrimes * All right! got some data, fill that buffer 3361556Srgrimes */ 3371556Srgrimes bufpt = buf; 3381556Srgrimes bufend = buf + res; 3391556Srgrimes rdcnt += res; 3401556Srgrimes return(0); 3411556Srgrimes } 3421556Srgrimes 3431556Srgrimes /* 3441556Srgrimes * Oh well, yet another failed read... 3451556Srgrimes * if error limit reached, ditch. o.w. poke device to move past 3461556Srgrimes * bad media and try again. if media is badly damaged, we ask 3471556Srgrimes * the poor (and upset user at this point) for the next archive 3481556Srgrimes * volume. remember the goal on reads is to get the most we 3491556Srgrimes * can extract out of the archive. 3501556Srgrimes */ 3511556Srgrimes if ((maxflt > 0) && (++errcnt > maxflt)) 35276017Skris paxwarn(0,"Archive read error limit (%d) reached",maxflt); 3531556Srgrimes else if (ar_rdsync() == 0) 3541556Srgrimes continue; 3551556Srgrimes if (ar_next() < 0) 3561556Srgrimes break; 3571556Srgrimes rdcnt = 0; 3581556Srgrimes errcnt = 0; 3591556Srgrimes } 3601556Srgrimes return(-1); 3611556Srgrimes} 3621556Srgrimes 3631556Srgrimes/* 3641556Srgrimes * pback() 3651556Srgrimes * push the data used during the archive id phase back into the I/O 3661556Srgrimes * buffer. This is required as we cannot be sure that the header does NOT 367222177Suqs * overlap a block boundary (as in the case we are trying to recover a 3681556Srgrimes * flawed archived). This was not designed to be used for any other 3691556Srgrimes * purpose. (What software engineering, HA!) 3701556Srgrimes * WARNING: do not even THINK of pback greater than BLKMULT, unless the 3711556Srgrimes * pback space is increased. 3721556Srgrimes */ 3731556Srgrimes 3741556Srgrimesvoid 3751556Srgrimespback(char *pt, int cnt) 3761556Srgrimes{ 3771556Srgrimes bufpt -= cnt; 37876017Skris memcpy(bufpt, pt, cnt); 3791556Srgrimes return; 3801556Srgrimes} 3811556Srgrimes 3821556Srgrimes/* 3831556Srgrimes * rd_skip() 384222177Suqs * skip forward in the archive during an archive read. Used to get quickly 3851556Srgrimes * past file data and padding for files the user did NOT select. 3861556Srgrimes * Return: 3871556Srgrimes * 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected. 3881556Srgrimes */ 3891556Srgrimes 3901556Srgrimesint 3911556Srgrimesrd_skip(off_t skcnt) 3921556Srgrimes{ 3931556Srgrimes off_t res; 3941556Srgrimes off_t cnt; 3951556Srgrimes off_t skipped = 0; 3961556Srgrimes 3971556Srgrimes /* 398222177Suqs * consume what data we have in the buffer. If we have to move forward 3991556Srgrimes * whole records, we call the low level skip function to see if we can 4001556Srgrimes * move within the archive without doing the expensive reads on data we 4011556Srgrimes * do not want. 4021556Srgrimes */ 4031556Srgrimes if (skcnt == 0) 4041556Srgrimes return(0); 4051556Srgrimes res = MIN((bufend - bufpt), skcnt); 4061556Srgrimes bufpt += res; 4071556Srgrimes skcnt -= res; 4081556Srgrimes 4091556Srgrimes /* 4101556Srgrimes * if skcnt is now 0, then no additional i/o is needed 4111556Srgrimes */ 4121556Srgrimes if (skcnt == 0) 4131556Srgrimes return(0); 4141556Srgrimes 4151556Srgrimes /* 4161556Srgrimes * We have to read more, calculate complete and partial record reads 4171556Srgrimes * based on rdblksz. we skip over "cnt" complete records 4181556Srgrimes */ 4191556Srgrimes res = skcnt%rdblksz; 4201556Srgrimes cnt = (skcnt/rdblksz) * rdblksz; 4211556Srgrimes 4221556Srgrimes /* 4231556Srgrimes * if the skip fails, we will have to resync. ar_fow will tell us 4241556Srgrimes * how much it can skip over. We will have to read the rest. 4251556Srgrimes */ 4261556Srgrimes if (ar_fow(cnt, &skipped) < 0) 4271556Srgrimes return(-1); 4281556Srgrimes res += cnt - skipped; 4291556Srgrimes rdcnt += skipped; 4301556Srgrimes 4311556Srgrimes /* 4321556Srgrimes * what is left we have to read (which may be the whole thing if 4331556Srgrimes * ar_fow() told us the device can only read to skip records); 4341556Srgrimes */ 4351556Srgrimes while (res > 0L) { 4361556Srgrimes cnt = bufend - bufpt; 4371556Srgrimes /* 4381556Srgrimes * if the read fails, we will have to resync 4391556Srgrimes */ 4401556Srgrimes if ((cnt <= 0) && ((cnt = buf_fill()) < 0)) 4411556Srgrimes return(-1); 4421556Srgrimes if (cnt == 0) 4431556Srgrimes return(1); 4441556Srgrimes cnt = MIN(cnt, res); 4451556Srgrimes bufpt += cnt; 4461556Srgrimes res -= cnt; 4471556Srgrimes } 4481556Srgrimes return(0); 4491556Srgrimes} 4501556Srgrimes 4518855Srgrimes/* 4521556Srgrimes * wr_fin() 4531556Srgrimes * flush out any data (and pad if required) the last block. We always pad 4541556Srgrimes * with zero (even though we do not have to). Padding with 0 makes it a 455222177Suqs * lot easier to recover if the archive is damaged. zero padding SHOULD 4561556Srgrimes * BE a requirement.... 4571556Srgrimes */ 4581556Srgrimes 4591556Srgrimesvoid 4601556Srgrimeswr_fin(void) 4611556Srgrimes{ 4621556Srgrimes if (bufpt > buf) { 46376017Skris memset(bufpt, 0, bufend - bufpt); 4641556Srgrimes bufpt = bufend; 4651556Srgrimes (void)buf_flush(blksz); 4661556Srgrimes } 4671556Srgrimes} 4681556Srgrimes 4691556Srgrimes/* 4701556Srgrimes * wr_rdbuf() 4711556Srgrimes * fill the write buffer from data passed to it in a buffer (usually used 4721556Srgrimes * by format specific write routines to pass a file header). On failure we 4731556Srgrimes * punt. We do not allow the user to continue to write flawed archives. 4741556Srgrimes * We assume these headers are not very large (the memory copy we use is 4758855Srgrimes * a bit expensive). 4761556Srgrimes * Return: 4771556Srgrimes * 0 if buffer was filled ok, -1 o.w. (buffer flush failure) 4781556Srgrimes */ 4791556Srgrimes 4801556Srgrimesint 48190113Simpwr_rdbuf(char *out, int outcnt) 4821556Srgrimes{ 48390113Simp int cnt; 4841556Srgrimes 4851556Srgrimes /* 4861556Srgrimes * while there is data to copy copy into the write buffer. when the 4871556Srgrimes * write buffer fills, flush it to the archive and continue 4881556Srgrimes */ 4891556Srgrimes while (outcnt > 0) { 4901556Srgrimes cnt = bufend - bufpt; 4911556Srgrimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) 4921556Srgrimes return(-1); 4931556Srgrimes /* 4941556Srgrimes * only move what we have space for 4951556Srgrimes */ 4961556Srgrimes cnt = MIN(cnt, outcnt); 49776017Skris memcpy(bufpt, out, cnt); 4981556Srgrimes bufpt += cnt; 4991556Srgrimes out += cnt; 5001556Srgrimes outcnt -= cnt; 5011556Srgrimes } 5021556Srgrimes return(0); 5031556Srgrimes} 5041556Srgrimes 5051556Srgrimes/* 5061556Srgrimes * rd_wrbuf() 5071556Srgrimes * copy from the read buffer into a supplied buffer a specified number of 5081556Srgrimes * bytes. If the read buffer is empty fill it and continue to copy. 5091556Srgrimes * usually used to obtain a file header for processing by a format 5101556Srgrimes * specific read routine. 5111556Srgrimes * Return 5121556Srgrimes * number of bytes copied to the buffer, 0 indicates EOF on archive volume, 5131556Srgrimes * -1 is a read error 5141556Srgrimes */ 5151556Srgrimes 5161556Srgrimesint 51790113Simprd_wrbuf(char *in, int cpcnt) 5181556Srgrimes{ 51990113Simp int res; 52090113Simp int cnt; 52190113Simp int incnt = cpcnt; 5221556Srgrimes 5231556Srgrimes /* 5241556Srgrimes * loop until we fill the buffer with the requested number of bytes 5251556Srgrimes */ 5261556Srgrimes while (incnt > 0) { 5271556Srgrimes cnt = bufend - bufpt; 5281556Srgrimes if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) { 5291556Srgrimes /* 5301556Srgrimes * read error, return what we got (or the error if 5311556Srgrimes * no data was copied). The caller must know that an 532222177Suqs * error occurred and has the best knowledge what to 5331556Srgrimes * do with it 5341556Srgrimes */ 5351556Srgrimes if ((res = cpcnt - incnt) > 0) 5361556Srgrimes return(res); 5371556Srgrimes return(cnt); 5381556Srgrimes } 5391556Srgrimes 5401556Srgrimes /* 5411556Srgrimes * calculate how much data to copy based on whats left and 5421556Srgrimes * state of buffer 5431556Srgrimes */ 5441556Srgrimes cnt = MIN(cnt, incnt); 54576017Skris memcpy(in, bufpt, cnt); 5461556Srgrimes bufpt += cnt; 5471556Srgrimes incnt -= cnt; 5481556Srgrimes in += cnt; 5491556Srgrimes } 5501556Srgrimes return(cpcnt); 5511556Srgrimes} 5521556Srgrimes 5531556Srgrimes/* 5541556Srgrimes * wr_skip() 55546684Skris * skip forward during a write. In other words add padding to the file. 5561556Srgrimes * we add zero filled padding as it makes flawed archives much easier to 5571556Srgrimes * recover from. the caller tells us how many bytes of padding to add 5581556Srgrimes * This routine was not designed to add HUGE amount of padding, just small 5591556Srgrimes * amounts (a few 512 byte blocks at most) 5601556Srgrimes * Return: 5611556Srgrimes * 0 if ok, -1 if there was a buf_flush failure 5621556Srgrimes */ 5631556Srgrimes 5641556Srgrimesint 5651556Srgrimeswr_skip(off_t skcnt) 5661556Srgrimes{ 56790113Simp int cnt; 5681556Srgrimes 5691556Srgrimes /* 5701556Srgrimes * loop while there is more padding to add 5711556Srgrimes */ 5721556Srgrimes while (skcnt > 0L) { 5731556Srgrimes cnt = bufend - bufpt; 5741556Srgrimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) 5751556Srgrimes return(-1); 5761556Srgrimes cnt = MIN(cnt, skcnt); 57776017Skris memset(bufpt, 0, cnt); 5781556Srgrimes bufpt += cnt; 5791556Srgrimes skcnt -= cnt; 5801556Srgrimes } 5811556Srgrimes return(0); 5821556Srgrimes} 5831556Srgrimes 5841556Srgrimes/* 5851556Srgrimes * wr_rdfile() 586222177Suqs * fill write buffer with the contents of a file. We are passed an open 587100012Skeramida * file descriptor to the file and the archive structure that describes the 5881556Srgrimes * file we are storing. The variable "left" is modified to contain the 5891556Srgrimes * number of bytes of the file we were NOT able to write to the archive. 5901556Srgrimes * it is important that we always write EXACTLY the number of bytes that 5911556Srgrimes * the format specific write routine told us to. The file can also get 5921556Srgrimes * bigger, so reading to the end of file would create an improper archive, 59376017Skris * we just detect this case and warn the user. We never create a bad 5941556Srgrimes * archive if we can avoid it. Of course trying to archive files that are 5951556Srgrimes * active is asking for trouble. It we fail, we pass back how much we 5961556Srgrimes * could NOT copy and let the caller deal with it. 5971556Srgrimes * Return: 5981556Srgrimes * 0 ok, -1 if archive write failure. a short read of the file returns a 5991556Srgrimes * 0, but "left" is set to be greater than zero. 6001556Srgrimes */ 6011556Srgrimes 6021556Srgrimesint 6031556Srgrimeswr_rdfile(ARCHD *arcn, int ifd, off_t *left) 6041556Srgrimes{ 60590113Simp int cnt; 60690113Simp int res = 0; 60790113Simp off_t size = arcn->sb.st_size; 6081556Srgrimes struct stat sb; 6091556Srgrimes 6101556Srgrimes /* 6111556Srgrimes * while there are more bytes to write 6121556Srgrimes */ 6131556Srgrimes while (size > 0L) { 6141556Srgrimes cnt = bufend - bufpt; 6151556Srgrimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) { 6161556Srgrimes *left = size; 6171556Srgrimes return(-1); 6181556Srgrimes } 6191556Srgrimes cnt = MIN(cnt, size); 6201556Srgrimes if ((res = read(ifd, bufpt, cnt)) <= 0) 6211556Srgrimes break; 6221556Srgrimes size -= res; 6231556Srgrimes bufpt += res; 6241556Srgrimes } 6251556Srgrimes 6261556Srgrimes /* 6271556Srgrimes * better check the file did not change during this operation 6281556Srgrimes * or the file read failed. 6291556Srgrimes */ 6301556Srgrimes if (res < 0) 63176017Skris syswarn(1, errno, "Read fault on %s", arcn->org_name); 6321556Srgrimes else if (size != 0L) 63376017Skris paxwarn(1, "File changed size during read %s", arcn->org_name); 6341556Srgrimes else if (fstat(ifd, &sb) < 0) 63576017Skris syswarn(1, errno, "Failed stat on %s", arcn->org_name); 6361556Srgrimes else if (arcn->sb.st_mtime != sb.st_mtime) 63776017Skris paxwarn(1, "File %s was modified during copy to archive", 6381556Srgrimes arcn->org_name); 6391556Srgrimes *left = size; 6401556Srgrimes return(0); 6411556Srgrimes} 6421556Srgrimes 6431556Srgrimes/* 6441556Srgrimes * rd_wrfile() 6451556Srgrimes * extract the contents of a file from the archive. If we are unable to 6461556Srgrimes * extract the entire file (due to failure to write the file) we return 6471556Srgrimes * the numbers of bytes we did NOT process. This way the caller knows how 6481556Srgrimes * many bytes to skip past to find the next archive header. If the failure 6491556Srgrimes * was due to an archive read, we will catch that when we try to skip. If 6501556Srgrimes * the format supplies a file data crc value, we calculate the actual crc 6511556Srgrimes * so that it can be compared to the value stored in the header 6521556Srgrimes * NOTE: 6531556Srgrimes * We call a special function to write the file. This function attempts to 6541556Srgrimes * restore file holes (blocks of zeros) into the file. When files are 6551556Srgrimes * sparse this saves space, and is a LOT faster. For non sparse files 6561556Srgrimes * the performance hit is small. As of this writing, no archive supports 6571556Srgrimes * information on where the file holes are. 6581556Srgrimes * Return: 6591556Srgrimes * 0 ok, -1 if archive read failure. if we cannot write the entire file, 6601556Srgrimes * we return a 0 but "left" is set to be the amount unwritten 6611556Srgrimes */ 6621556Srgrimes 6631556Srgrimesint 6641556Srgrimesrd_wrfile(ARCHD *arcn, int ofd, off_t *left) 6651556Srgrimes{ 66690113Simp int cnt = 0; 66790113Simp off_t size = arcn->sb.st_size; 66890113Simp int res = 0; 66990113Simp char *fnm = arcn->name; 6701556Srgrimes int isem = 1; 6711556Srgrimes int rem; 6721556Srgrimes int sz = MINFBSZ; 673222177Suqs struct stat sb; 6741556Srgrimes u_long crc = 0L; 6751556Srgrimes 6761556Srgrimes /* 6771556Srgrimes * pass the blocksize of the file being written to the write routine, 6781556Srgrimes * if the size is zero, use the default MINFBSZ 6791556Srgrimes */ 68076019Skris if (fstat(ofd, &sb) == 0) { 6811556Srgrimes if (sb.st_blksize > 0) 6821556Srgrimes sz = (int)sb.st_blksize; 68376019Skris } else 68476019Skris syswarn(0,errno,"Unable to obtain block size for file %s",fnm); 6851556Srgrimes rem = sz; 6861556Srgrimes *left = 0L; 6871556Srgrimes 6881556Srgrimes /* 6891556Srgrimes * Copy the archive to the file the number of bytes specified. We have 6901556Srgrimes * to assume that we want to recover file holes as none of the archive 6911556Srgrimes * formats can record the location of file holes. 6921556Srgrimes */ 6931556Srgrimes while (size > 0L) { 6941556Srgrimes cnt = bufend - bufpt; 6951556Srgrimes /* 6961556Srgrimes * if we get a read error, we do not want to skip, as we may 6971556Srgrimes * miss a header, so we do not set left, but if we get a write 6981556Srgrimes * error, we do want to skip over the unprocessed data. 6991556Srgrimes */ 7001556Srgrimes if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) 7011556Srgrimes break; 7021556Srgrimes cnt = MIN(cnt, size); 7031556Srgrimes if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) { 7041556Srgrimes *left = size; 7051556Srgrimes break; 7061556Srgrimes } 7071556Srgrimes 7081556Srgrimes if (docrc) { 7091556Srgrimes /* 7101556Srgrimes * update the actual crc value 7111556Srgrimes */ 7121556Srgrimes cnt = res; 7131556Srgrimes while (--cnt >= 0) 7141556Srgrimes crc += *bufpt++ & 0xff; 7151556Srgrimes } else 7161556Srgrimes bufpt += res; 7171556Srgrimes size -= res; 7181556Srgrimes } 7191556Srgrimes 7201556Srgrimes /* 7211556Srgrimes * if the last block has a file hole (all zero), we must make sure this 7221556Srgrimes * gets updated in the file. We force the last block of zeros to be 72346684Skris * written. just closing with the file offset moved forward may not put 7241556Srgrimes * a hole at the end of the file. 7251556Srgrimes */ 7261556Srgrimes if (isem && (arcn->sb.st_size > 0L)) 7271556Srgrimes file_flush(ofd, fnm, isem); 7281556Srgrimes 7291556Srgrimes /* 7301556Srgrimes * if we failed from archive read, we do not want to skip 7311556Srgrimes */ 7328855Srgrimes if ((size > 0L) && (*left == 0L)) 7331556Srgrimes return(-1); 7341556Srgrimes 7351556Srgrimes /* 7361556Srgrimes * some formats record a crc on file data. If so, then we compare the 7371556Srgrimes * calculated crc to the crc stored in the archive 7381556Srgrimes */ 7391556Srgrimes if (docrc && (size == 0L) && (arcn->crc != crc)) 74076017Skris paxwarn(1,"Actual crc does not match expected crc %s",arcn->name); 7411556Srgrimes return(0); 7421556Srgrimes} 7431556Srgrimes 7441556Srgrimes/* 7451556Srgrimes * cp_file() 7461556Srgrimes * copy the contents of one file to another. used during -rw phase of pax 7471556Srgrimes * just as in rd_wrfile() we use a special write function to write the 7481556Srgrimes * destination file so we can properly copy files with holes. 7491556Srgrimes */ 7501556Srgrimes 7511556Srgrimesvoid 7521556Srgrimescp_file(ARCHD *arcn, int fd1, int fd2) 7531556Srgrimes{ 75490113Simp int cnt; 75590113Simp off_t cpcnt = 0L; 75690113Simp int res = 0; 75790113Simp char *fnm = arcn->name; 75890113Simp int no_hole = 0; 7591556Srgrimes int isem = 1; 7601556Srgrimes int rem; 7611556Srgrimes int sz = MINFBSZ; 7621556Srgrimes struct stat sb; 7631556Srgrimes 7641556Srgrimes /* 7651556Srgrimes * check for holes in the source file. If none, we will use regular 7661556Srgrimes * write instead of file write. 7671556Srgrimes */ 7681556Srgrimes if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size) 7691556Srgrimes ++no_hole; 7701556Srgrimes 7711556Srgrimes /* 7721556Srgrimes * pass the blocksize of the file being written to the write routine, 7731556Srgrimes * if the size is zero, use the default MINFBSZ 7741556Srgrimes */ 77576019Skris if (fstat(fd2, &sb) == 0) { 7761556Srgrimes if (sb.st_blksize > 0) 7771556Srgrimes sz = sb.st_blksize; 77876019Skris } else 77976019Skris syswarn(0,errno,"Unable to obtain block size for file %s",fnm); 7801556Srgrimes rem = sz; 7811556Srgrimes 7821556Srgrimes /* 7831556Srgrimes * read the source file and copy to destination file until EOF 7841556Srgrimes */ 7851556Srgrimes for(;;) { 7861556Srgrimes if ((cnt = read(fd1, buf, blksz)) <= 0) 7871556Srgrimes break; 7881556Srgrimes if (no_hole) 7891556Srgrimes res = write(fd2, buf, cnt); 7901556Srgrimes else 7911556Srgrimes res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm); 7921556Srgrimes if (res != cnt) 7931556Srgrimes break; 7941556Srgrimes cpcnt += cnt; 7951556Srgrimes } 7961556Srgrimes 7971556Srgrimes /* 7981556Srgrimes * check to make sure the copy is valid. 7991556Srgrimes */ 8001556Srgrimes if (res < 0) 80176017Skris syswarn(1, errno, "Failed write during copy of %s to %s", 8021556Srgrimes arcn->org_name, arcn->name); 8031556Srgrimes else if (cpcnt != arcn->sb.st_size) 80476017Skris paxwarn(1, "File %s changed size during copy to %s", 8051556Srgrimes arcn->org_name, arcn->name); 8061556Srgrimes else if (fstat(fd1, &sb) < 0) 80776017Skris syswarn(1, errno, "Failed stat of %s", arcn->org_name); 8081556Srgrimes else if (arcn->sb.st_mtime != sb.st_mtime) 80976017Skris paxwarn(1, "File %s was modified during copy to %s", 8101556Srgrimes arcn->org_name, arcn->name); 8111556Srgrimes 8121556Srgrimes /* 8131556Srgrimes * if the last block has a file hole (all zero), we must make sure this 8141556Srgrimes * gets updated in the file. We force the last block of zeros to be 81546684Skris * written. just closing with the file offset moved forward may not put 8161556Srgrimes * a hole at the end of the file. 8171556Srgrimes */ 8181556Srgrimes if (!no_hole && isem && (arcn->sb.st_size > 0L)) 8191556Srgrimes file_flush(fd2, fnm, isem); 8201556Srgrimes return; 8211556Srgrimes} 8221556Srgrimes 8231556Srgrimes/* 8241556Srgrimes * buf_fill() 8251556Srgrimes * fill the read buffer with the next record (or what we can get) from 8261556Srgrimes * the archive volume. 8271556Srgrimes * Return: 8281556Srgrimes * Number of bytes of data in the read buffer, -1 for read error, and 8291556Srgrimes * 0 when finished (user specified termination in ar_next()). 8301556Srgrimes */ 8311556Srgrimes 8321556Srgrimesint 8331556Srgrimesbuf_fill(void) 8341556Srgrimes{ 83590113Simp int cnt; 8361556Srgrimes static int fini = 0; 8371556Srgrimes 8381556Srgrimes if (fini) 8391556Srgrimes return(0); 8401556Srgrimes 8411556Srgrimes for(;;) { 8421556Srgrimes /* 8431556Srgrimes * try to fill the buffer. on error the next archive volume is 8441556Srgrimes * opened and we try again. 8451556Srgrimes */ 8461556Srgrimes if ((cnt = ar_read(buf, blksz)) > 0) { 8471556Srgrimes bufpt = buf; 8481556Srgrimes bufend = buf + cnt; 8491556Srgrimes rdcnt += cnt; 8501556Srgrimes return(cnt); 8511556Srgrimes } 8521556Srgrimes 8531556Srgrimes /* 8541556Srgrimes * errors require resync, EOF goes to next archive 855310606Spfg * but in case we have not determined yet the format, 856310606Spfg * this means that we have a very short file, so we 857310606Spfg * are done again. 8581556Srgrimes */ 8591556Srgrimes if (cnt < 0) 8601556Srgrimes break; 861310606Spfg if (frmt == NULL || ar_next() < 0) { 8621556Srgrimes fini = 1; 8631556Srgrimes return(0); 8641556Srgrimes } 8651556Srgrimes rdcnt = 0; 8661556Srgrimes } 8671556Srgrimes exit_val = 1; 8681556Srgrimes return(-1); 8691556Srgrimes} 8701556Srgrimes 8711556Srgrimes/* 8721556Srgrimes * buf_flush() 8731556Srgrimes * force the write buffer to the archive. We are passed the number of 8741556Srgrimes * bytes in the buffer at the point of the flush. When we change archives 8751556Srgrimes * the record size might change. (either larger or smaller). 8761556Srgrimes * Return: 8771556Srgrimes * 0 if all is ok, -1 when a write error occurs. 8781556Srgrimes */ 8791556Srgrimes 8801556Srgrimesint 88190113Simpbuf_flush(int bufcnt) 8821556Srgrimes{ 88390113Simp int cnt; 88490113Simp int push = 0; 88590113Simp int totcnt = 0; 8861556Srgrimes 8871556Srgrimes /* 8881556Srgrimes * if we have reached the user specified byte count for each archive 889222177Suqs * volume, prompt for the next volume. (The non-standard -R flag). 8901556Srgrimes * NOTE: If the wrlimit is smaller than wrcnt, we will always write 8911556Srgrimes * at least one record. We always round limit UP to next blocksize. 8921556Srgrimes */ 8931556Srgrimes if ((wrlimit > 0) && (wrcnt > wrlimit)) { 89476017Skris paxwarn(0, "User specified archive volume byte limit reached."); 8951556Srgrimes if (ar_next() < 0) { 8961556Srgrimes wrcnt = 0; 8971556Srgrimes exit_val = 1; 8981556Srgrimes return(-1); 8991556Srgrimes } 9001556Srgrimes wrcnt = 0; 9011556Srgrimes 9021556Srgrimes /* 9031556Srgrimes * The new archive volume might have changed the size of the 9041556Srgrimes * write blocksize. if so we figure out if we need to write 9051556Srgrimes * (one or more times), or if there is now free space left in 9061556Srgrimes * the buffer (it is no longer full). bufcnt has the number of 9071556Srgrimes * bytes in the buffer, (the blocksize, at the point we were 9081556Srgrimes * CALLED). Push has the amount of "extra" data in the buffer 9091556Srgrimes * if the block size has shrunk from a volume change. 9101556Srgrimes */ 9111556Srgrimes bufend = buf + blksz; 9121556Srgrimes if (blksz > bufcnt) 9131556Srgrimes return(0); 9141556Srgrimes if (blksz < bufcnt) 9151556Srgrimes push = bufcnt - blksz; 9161556Srgrimes } 9171556Srgrimes 9181556Srgrimes /* 9191556Srgrimes * We have enough data to write at least one archive block 9201556Srgrimes */ 9211556Srgrimes for (;;) { 9221556Srgrimes /* 9231556Srgrimes * write a block and check if it all went out ok 9241556Srgrimes */ 9258855Srgrimes cnt = ar_write(buf, blksz); 9261556Srgrimes if (cnt == blksz) { 9271556Srgrimes /* 9281556Srgrimes * the write went ok 9291556Srgrimes */ 9301556Srgrimes wrcnt += cnt; 9311556Srgrimes totcnt += cnt; 9321556Srgrimes if (push > 0) { 9331556Srgrimes /* we have extra data to push to the front. 9341556Srgrimes * check for more than 1 block of push, and if 9351556Srgrimes * so we loop back to write again 9361556Srgrimes */ 93776017Skris memcpy(buf, bufend, push); 9381556Srgrimes bufpt = buf + push; 9391556Srgrimes if (push >= blksz) { 9401556Srgrimes push -= blksz; 9411556Srgrimes continue; 9421556Srgrimes } 9431556Srgrimes } else 9441556Srgrimes bufpt = buf; 9451556Srgrimes return(totcnt); 9461556Srgrimes } else if (cnt > 0) { 9471556Srgrimes /* 9481556Srgrimes * Oh drat we got a partial write! 949222177Suqs * if format doesn't care about alignment let it go, 95076017Skris * we warned the user in ar_write().... but this means 9511556Srgrimes * the last record on this volume violates pax spec.... 9521556Srgrimes */ 9531556Srgrimes totcnt += cnt; 9541556Srgrimes wrcnt += cnt; 9551556Srgrimes bufpt = buf + cnt; 9561556Srgrimes cnt = bufcnt - cnt; 95776017Skris memcpy(buf, bufpt, cnt); 9581556Srgrimes bufpt = buf + cnt; 9591556Srgrimes if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0)) 9601556Srgrimes return(totcnt); 9611556Srgrimes break; 9621556Srgrimes } 9631556Srgrimes 9641556Srgrimes /* 9651556Srgrimes * All done, go to next archive 9661556Srgrimes */ 9671556Srgrimes wrcnt = 0; 9681556Srgrimes if (ar_next() < 0) 9691556Srgrimes break; 9701556Srgrimes 9711556Srgrimes /* 9721556Srgrimes * The new archive volume might also have changed the block 9731556Srgrimes * size. if so, figure out if we have too much or too little 9741556Srgrimes * data for using the new block size 9751556Srgrimes */ 9761556Srgrimes bufend = buf + blksz; 9771556Srgrimes if (blksz > bufcnt) 9781556Srgrimes return(0); 9791556Srgrimes if (blksz < bufcnt) 9801556Srgrimes push = bufcnt - blksz; 9811556Srgrimes } 9821556Srgrimes 9831556Srgrimes /* 9841556Srgrimes * write failed, stop pax. we must not create a bad archive! 9851556Srgrimes */ 9861556Srgrimes exit_val = 1; 9871556Srgrimes return(-1); 9881556Srgrimes} 989