14b88c807SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
44b88c807SRodney W. Grimes * Copyright (c) 1992 Keith Muller.
54b88c807SRodney W. Grimes * Copyright (c) 1992, 1993
64b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved.
74b88c807SRodney W. Grimes *
84b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by
94b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego.
104b88c807SRodney W. Grimes *
114b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
124b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions
134b88c807SRodney W. Grimes * are met:
144b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
164b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
174b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
184b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution.
19fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
204b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software
214b88c807SRodney W. Grimes * without specific prior written permission.
224b88c807SRodney W. Grimes *
234b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
244b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
254b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
264b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
274b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
284b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
294b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
304b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
314b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
324b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
334b88c807SRodney W. Grimes * SUCH DAMAGE.
344b88c807SRodney W. Grimes */
354b88c807SRodney W. Grimes
364b88c807SRodney W. Grimes #include <sys/types.h>
374b88c807SRodney W. Grimes #include <sys/stat.h>
384b88c807SRodney W. Grimes #include <errno.h>
394b88c807SRodney W. Grimes #include <unistd.h>
40b1787decSKris Kennaway #include <stdio.h>
414b88c807SRodney W. Grimes #include <string.h>
424b88c807SRodney W. Grimes #include "pax.h"
434b88c807SRodney W. Grimes #include "extern.h"
444b88c807SRodney W. Grimes
454b88c807SRodney W. Grimes /*
464b88c807SRodney W. Grimes * routines which implement archive and file buffering
474b88c807SRodney W. Grimes */
484b88c807SRodney W. Grimes
494b88c807SRodney W. Grimes #define MINFBSZ 512 /* default block size for hole detect */
504b88c807SRodney W. Grimes #define MAXFLT 10 /* default media read error limit */
514b88c807SRodney W. Grimes
524b88c807SRodney W. Grimes /*
534b88c807SRodney W. Grimes * Need to change bufmem to dynamic allocation when the upper
544b88c807SRodney W. Grimes * limit on blocking size is removed (though that will violate pax spec)
554b88c807SRodney W. Grimes * MAXBLK define and tests will also need to be updated.
564b88c807SRodney W. Grimes */
574b88c807SRodney W. Grimes static char bufmem[MAXBLK+BLKMULT]; /* i/o buffer + pushback id space */
584b88c807SRodney W. Grimes static char *buf; /* normal start of i/o buffer */
594b88c807SRodney W. Grimes static char *bufend; /* end or last char in i/o buffer */
604b88c807SRodney W. Grimes static char *bufpt; /* read/write point in i/o buffer */
614b88c807SRodney W. Grimes int blksz = MAXBLK; /* block input/output size in bytes */
624b88c807SRodney W. Grimes int wrblksz; /* user spec output size in bytes */
634b88c807SRodney W. Grimes int maxflt = MAXFLT; /* MAX consecutive media errors */
644b88c807SRodney W. Grimes int rdblksz; /* first read blksize (tapes only) */
654b88c807SRodney W. Grimes off_t wrlimit; /* # of bytes written per archive vol */
664b88c807SRodney W. Grimes off_t wrcnt; /* # of bytes written on current vol */
674b88c807SRodney W. Grimes off_t rdcnt; /* # of bytes read on current vol */
684b88c807SRodney W. Grimes
694b88c807SRodney W. Grimes /*
704b88c807SRodney W. Grimes * wr_start()
714b88c807SRodney W. Grimes * set up the buffering system to operate in a write mode
724b88c807SRodney W. Grimes * Return:
734b88c807SRodney W. Grimes * 0 if ok, -1 if the user specified write block size violates pax spec
744b88c807SRodney W. Grimes */
754b88c807SRodney W. Grimes
764b88c807SRodney W. Grimes int
wr_start(void)774b88c807SRodney W. Grimes wr_start(void)
784b88c807SRodney W. Grimes {
794b88c807SRodney W. Grimes buf = &(bufmem[BLKMULT]);
804b88c807SRodney W. Grimes /*
814b88c807SRodney W. Grimes * Check to make sure the write block size meets pax specs. If the user
824b88c807SRodney W. Grimes * does not specify a blocksize, we use the format default blocksize.
834b88c807SRodney W. Grimes * We must be picky on writes, so we do not allow the user to create an
844b88c807SRodney W. Grimes * archive that might be hard to read elsewhere. If all ok, we then
854b88c807SRodney W. Grimes * open the first archive volume
864b88c807SRodney W. Grimes */
874b88c807SRodney W. Grimes if (!wrblksz)
884b88c807SRodney W. Grimes wrblksz = frmt->bsz;
894b88c807SRodney W. Grimes if (wrblksz > MAXBLK) {
90778766feSKris Kennaway paxwarn(1, "Write block size of %d too large, maximum is: %d",
914b88c807SRodney W. Grimes wrblksz, MAXBLK);
924b88c807SRodney W. Grimes return(-1);
934b88c807SRodney W. Grimes }
944b88c807SRodney W. Grimes if (wrblksz % BLKMULT) {
95778766feSKris Kennaway paxwarn(1, "Write block size of %d is not a %d byte multiple",
964b88c807SRodney W. Grimes wrblksz, BLKMULT);
974b88c807SRodney W. Grimes return(-1);
984b88c807SRodney W. Grimes }
99b1787decSKris Kennaway if (wrblksz > MAXBLK_POSIX) {
100b1787decSKris Kennaway paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable",
101b1787decSKris Kennaway wrblksz, MAXBLK_POSIX);
102b1787decSKris Kennaway return(-1);
103b1787decSKris Kennaway }
1044b88c807SRodney W. Grimes
1054b88c807SRodney W. Grimes /*
1064b88c807SRodney W. Grimes * we only allow wrblksz to be used with all archive operations
1074b88c807SRodney W. Grimes */
1084b88c807SRodney W. Grimes blksz = rdblksz = wrblksz;
1094b88c807SRodney W. Grimes if ((ar_open(arcname) < 0) && (ar_next() < 0))
1104b88c807SRodney W. Grimes return(-1);
1114b88c807SRodney W. Grimes wrcnt = 0;
1124b88c807SRodney W. Grimes bufend = buf + wrblksz;
1134b88c807SRodney W. Grimes bufpt = buf;
1144b88c807SRodney W. Grimes return(0);
1154b88c807SRodney W. Grimes }
1164b88c807SRodney W. Grimes
1174b88c807SRodney W. Grimes /*
1184b88c807SRodney W. Grimes * rd_start()
1194b88c807SRodney W. Grimes * set up buffering system to read an archive
1204b88c807SRodney W. Grimes * Return:
1214b88c807SRodney W. Grimes * 0 if ok, -1 otherwise
1224b88c807SRodney W. Grimes */
1234b88c807SRodney W. Grimes
1244b88c807SRodney W. Grimes int
rd_start(void)1254b88c807SRodney W. Grimes rd_start(void)
1264b88c807SRodney W. Grimes {
1274b88c807SRodney W. Grimes /*
1284b88c807SRodney W. Grimes * leave space for the header pushback (see get_arc()). If we are
1294b88c807SRodney W. Grimes * going to append and user specified a write block size, check it
1304b88c807SRodney W. Grimes * right away
1314b88c807SRodney W. Grimes */
1324b88c807SRodney W. Grimes buf = &(bufmem[BLKMULT]);
1334b88c807SRodney W. Grimes if ((act == APPND) && wrblksz) {
1344b88c807SRodney W. Grimes if (wrblksz > MAXBLK) {
135778766feSKris Kennaway paxwarn(1,"Write block size %d too large, maximum is: %d",
1364b88c807SRodney W. Grimes wrblksz, MAXBLK);
1374b88c807SRodney W. Grimes return(-1);
1384b88c807SRodney W. Grimes }
1394b88c807SRodney W. Grimes if (wrblksz % BLKMULT) {
140778766feSKris Kennaway paxwarn(1, "Write block size %d is not a %d byte multiple",
1414b88c807SRodney W. Grimes wrblksz, BLKMULT);
1424b88c807SRodney W. Grimes return(-1);
1434b88c807SRodney W. Grimes }
1444b88c807SRodney W. Grimes }
1454b88c807SRodney W. Grimes
1464b88c807SRodney W. Grimes /*
1474b88c807SRodney W. Grimes * open the archive
1484b88c807SRodney W. Grimes */
1494b88c807SRodney W. Grimes if ((ar_open(arcname) < 0) && (ar_next() < 0))
1504b88c807SRodney W. Grimes return(-1);
1514b88c807SRodney W. Grimes bufend = buf + rdblksz;
1524b88c807SRodney W. Grimes bufpt = bufend;
1534b88c807SRodney W. Grimes rdcnt = 0;
1544b88c807SRodney W. Grimes return(0);
1554b88c807SRodney W. Grimes }
1564b88c807SRodney W. Grimes
1574b88c807SRodney W. Grimes /*
1584b88c807SRodney W. Grimes * cp_start()
1594b88c807SRodney W. Grimes * set up buffer system for copying within the file system
1604b88c807SRodney W. Grimes */
1614b88c807SRodney W. Grimes
1624b88c807SRodney W. Grimes void
cp_start(void)1634b88c807SRodney W. Grimes cp_start(void)
1644b88c807SRodney W. Grimes {
1654b88c807SRodney W. Grimes buf = &(bufmem[BLKMULT]);
1664b88c807SRodney W. Grimes rdblksz = blksz = MAXBLK;
1674b88c807SRodney W. Grimes }
1684b88c807SRodney W. Grimes
1694b88c807SRodney W. Grimes /*
1704b88c807SRodney W. Grimes * appnd_start()
1714b88c807SRodney W. Grimes * Set up the buffering system to append new members to an archive that
1724b88c807SRodney W. Grimes * was just read. The last block(s) of an archive may contain a format
1734b88c807SRodney W. Grimes * specific trailer. To append a new member, this trailer has to be
1744b88c807SRodney W. Grimes * removed from the archive. The first byte of the trailer is replaced by
1754b88c807SRodney W. Grimes * the start of the header of the first file added to the archive. The
1764b88c807SRodney W. Grimes * format specific end read function tells us how many bytes to move
1774b88c807SRodney W. Grimes * backwards in the archive to be positioned BEFORE the trailer. Two
17801c99176SUlrich Spörlein * different positions have to be adjusted, the O.S. file offset (e.g. the
1794b88c807SRodney W. Grimes * position of the tape head) and the write point within the data we have
1804b88c807SRodney W. Grimes * stored in the read (soon to become write) buffer. We may have to move
1814b88c807SRodney W. Grimes * back several records (the number depends on the size of the archive
1824b88c807SRodney W. Grimes * record and the size of the format trailer) to read up the record where
1834b88c807SRodney W. Grimes * the first byte of the trailer is recorded. Trailers may span (and
18401c99176SUlrich Spörlein * overlap) record boundaries.
1854b88c807SRodney W. Grimes * We first calculate which record has the first byte of the trailer. We
1864b88c807SRodney W. Grimes * move the OS file offset back to the start of this record and read it
1874b88c807SRodney W. Grimes * up. We set the buffer write pointer to be at this byte (the byte where
1884b88c807SRodney W. Grimes * the trailer starts). We then move the OS file pointer back to the
1894b88c807SRodney W. Grimes * start of this record so a flush of this buffer will replace the record
1904b88c807SRodney W. Grimes * in the archive.
1914b88c807SRodney W. Grimes * A major problem is rewriting this last record. For archives stored
19201c99176SUlrich Spörlein * on disk files, this is trivial. However, many devices are really picky
1934b88c807SRodney W. Grimes * about the conditions under which they will allow a write to occur.
194*0266a5d6SDag-Erling Smørgrav * Often devices restrict the conditions where writes can be made,
19501c99176SUlrich Spörlein * so it may not be feasible to append archives stored on all types of
1964b88c807SRodney W. Grimes * devices.
1974b88c807SRodney W. Grimes * Return:
1984b88c807SRodney W. Grimes * 0 for success, -1 for failure
1994b88c807SRodney W. Grimes */
2004b88c807SRodney W. Grimes
2014b88c807SRodney W. Grimes int
appnd_start(off_t skcnt)2024b88c807SRodney W. Grimes appnd_start(off_t skcnt)
2034b88c807SRodney W. Grimes {
204f789b261SWarner Losh int res;
2054b88c807SRodney W. Grimes off_t cnt;
2064b88c807SRodney W. Grimes
2074b88c807SRodney W. Grimes if (exit_val != 0) {
208778766feSKris Kennaway paxwarn(0, "Cannot append to an archive that may have flaws.");
2094b88c807SRodney W. Grimes return(-1);
2104b88c807SRodney W. Grimes }
2114b88c807SRodney W. Grimes /*
2124b88c807SRodney W. Grimes * if the user did not specify a write blocksize, inherit the size used
2134b88c807SRodney W. Grimes * in the last archive volume read. (If a is set we still use rdblksz
2144b88c807SRodney W. Grimes * until next volume, cannot shift sizes within a single volume).
2154b88c807SRodney W. Grimes */
2164b88c807SRodney W. Grimes if (!wrblksz)
2174b88c807SRodney W. Grimes wrblksz = blksz = rdblksz;
2184b88c807SRodney W. Grimes else
2194b88c807SRodney W. Grimes blksz = rdblksz;
2204b88c807SRodney W. Grimes
2214b88c807SRodney W. Grimes /*
2224b88c807SRodney W. Grimes * make sure that this volume allows appends
2234b88c807SRodney W. Grimes */
2244b88c807SRodney W. Grimes if (ar_app_ok() < 0)
2254b88c807SRodney W. Grimes return(-1);
2264b88c807SRodney W. Grimes
2274b88c807SRodney W. Grimes /*
2284b88c807SRodney W. Grimes * Calculate bytes to move back and move in front of record where we
2294b88c807SRodney W. Grimes * need to start writing from. Remember we have to add in any padding
2304b88c807SRodney W. Grimes * that might be in the buffer after the trailer in the last block. We
2314b88c807SRodney W. Grimes * travel skcnt + padding ROUNDED UP to blksize.
2324b88c807SRodney W. Grimes */
2334b88c807SRodney W. Grimes skcnt += bufend - bufpt;
2344b88c807SRodney W. Grimes if ((cnt = (skcnt/blksz) * blksz) < skcnt)
2354b88c807SRodney W. Grimes cnt += blksz;
2364b88c807SRodney W. Grimes if (ar_rev((off_t)cnt) < 0)
2374b88c807SRodney W. Grimes goto out;
2384b88c807SRodney W. Grimes
2394b88c807SRodney W. Grimes /*
2404b88c807SRodney W. Grimes * We may have gone too far if there is valid data in the block we are
2414b88c807SRodney W. Grimes * now in front of, read up the block and position the pointer after
2424b88c807SRodney W. Grimes * the valid data.
2434b88c807SRodney W. Grimes */
2444b88c807SRodney W. Grimes if ((cnt -= skcnt) > 0) {
2454b88c807SRodney W. Grimes /*
2464b88c807SRodney W. Grimes * watch out for stupid tape drives. ar_rev() will set rdblksz
2474b88c807SRodney W. Grimes * to be real physical blocksize so we must loop until we get
2484b88c807SRodney W. Grimes * the old rdblksz (now in blksz). If ar_rev() fouls up the
2494b88c807SRodney W. Grimes * determination of the physical block size, we will fail.
2504b88c807SRodney W. Grimes */
2514b88c807SRodney W. Grimes bufpt = buf;
2524b88c807SRodney W. Grimes bufend = buf + blksz;
2534b88c807SRodney W. Grimes while (bufpt < bufend) {
2544b88c807SRodney W. Grimes if ((res = ar_read(bufpt, rdblksz)) <= 0)
2554b88c807SRodney W. Grimes goto out;
2564b88c807SRodney W. Grimes bufpt += res;
2574b88c807SRodney W. Grimes }
2584b88c807SRodney W. Grimes if (ar_rev((off_t)(bufpt - buf)) < 0)
2594b88c807SRodney W. Grimes goto out;
2604b88c807SRodney W. Grimes bufpt = buf + cnt;
2614b88c807SRodney W. Grimes bufend = buf + blksz;
2624b88c807SRodney W. Grimes } else {
2634b88c807SRodney W. Grimes /*
2644b88c807SRodney W. Grimes * buffer is empty
2654b88c807SRodney W. Grimes */
2664b88c807SRodney W. Grimes bufend = buf + blksz;
2674b88c807SRodney W. Grimes bufpt = buf;
2684b88c807SRodney W. Grimes }
2694b88c807SRodney W. Grimes rdblksz = blksz;
2704b88c807SRodney W. Grimes rdcnt -= skcnt;
2714b88c807SRodney W. Grimes wrcnt = 0;
2724b88c807SRodney W. Grimes
2734b88c807SRodney W. Grimes /*
2744b88c807SRodney W. Grimes * At this point we are ready to write. If the device requires special
2754b88c807SRodney W. Grimes * handling to write at a point were previously recorded data resides,
2764b88c807SRodney W. Grimes * that is handled in ar_set_wr(). From now on we operate under normal
2774b88c807SRodney W. Grimes * ARCHIVE mode (write) conditions
2784b88c807SRodney W. Grimes */
2794b88c807SRodney W. Grimes if (ar_set_wr() < 0)
2804b88c807SRodney W. Grimes return(-1);
2814b88c807SRodney W. Grimes act = ARCHIVE;
2824b88c807SRodney W. Grimes return(0);
2834b88c807SRodney W. Grimes
2844b88c807SRodney W. Grimes out:
285778766feSKris Kennaway paxwarn(1, "Unable to rewrite archive trailer, cannot append.");
2864b88c807SRodney W. Grimes return(-1);
2874b88c807SRodney W. Grimes }
2884b88c807SRodney W. Grimes
2894b88c807SRodney W. Grimes /*
2904b88c807SRodney W. Grimes * rd_sync()
2914b88c807SRodney W. Grimes * A read error occurred on this archive volume. Resync the buffer and
2924b88c807SRodney W. Grimes * try to reset the device (if possible) so we can continue to read. Keep
2934b88c807SRodney W. Grimes * trying to do this until we get a valid read, or we reach the limit on
2944b88c807SRodney W. Grimes * consecutive read faults (at which point we give up). The user can
2954b88c807SRodney W. Grimes * adjust the read error limit through a command line option.
2964b88c807SRodney W. Grimes * Returns:
2974b88c807SRodney W. Grimes * 0 on success, and -1 on failure
2984b88c807SRodney W. Grimes */
2994b88c807SRodney W. Grimes
3004b88c807SRodney W. Grimes int
rd_sync(void)3014b88c807SRodney W. Grimes rd_sync(void)
3024b88c807SRodney W. Grimes {
303f789b261SWarner Losh int errcnt = 0;
304f789b261SWarner Losh int res;
3054b88c807SRodney W. Grimes
3064b88c807SRodney W. Grimes /*
3074b88c807SRodney W. Grimes * if the user says bail out on first fault, we are out of here...
3084b88c807SRodney W. Grimes */
3094b88c807SRodney W. Grimes if (maxflt == 0)
3104b88c807SRodney W. Grimes return(-1);
3114b88c807SRodney W. Grimes if (act == APPND) {
312778766feSKris Kennaway paxwarn(1, "Unable to append when there are archive read errors.");
3134b88c807SRodney W. Grimes return(-1);
3144b88c807SRodney W. Grimes }
3154b88c807SRodney W. Grimes
3164b88c807SRodney W. Grimes /*
3174b88c807SRodney W. Grimes * poke at device and try to get past media error
3184b88c807SRodney W. Grimes */
3194b88c807SRodney W. Grimes if (ar_rdsync() < 0) {
3204b88c807SRodney W. Grimes if (ar_next() < 0)
3214b88c807SRodney W. Grimes return(-1);
3224b88c807SRodney W. Grimes else
3234b88c807SRodney W. Grimes rdcnt = 0;
3244b88c807SRodney W. Grimes }
3254b88c807SRodney W. Grimes
3264b88c807SRodney W. Grimes for (;;) {
3274b88c807SRodney W. Grimes if ((res = ar_read(buf, blksz)) > 0) {
3284b88c807SRodney W. Grimes /*
3294b88c807SRodney W. Grimes * All right! got some data, fill that buffer
3304b88c807SRodney W. Grimes */
3314b88c807SRodney W. Grimes bufpt = buf;
3324b88c807SRodney W. Grimes bufend = buf + res;
3334b88c807SRodney W. Grimes rdcnt += res;
3344b88c807SRodney W. Grimes return(0);
3354b88c807SRodney W. Grimes }
3364b88c807SRodney W. Grimes
3374b88c807SRodney W. Grimes /*
3384b88c807SRodney W. Grimes * Oh well, yet another failed read...
3394b88c807SRodney W. Grimes * if error limit reached, ditch. o.w. poke device to move past
3404b88c807SRodney W. Grimes * bad media and try again. if media is badly damaged, we ask
3414b88c807SRodney W. Grimes * the poor (and upset user at this point) for the next archive
3424b88c807SRodney W. Grimes * volume. remember the goal on reads is to get the most we
3434b88c807SRodney W. Grimes * can extract out of the archive.
3444b88c807SRodney W. Grimes */
3454b88c807SRodney W. Grimes if ((maxflt > 0) && (++errcnt > maxflt))
346778766feSKris Kennaway paxwarn(0,"Archive read error limit (%d) reached",maxflt);
3474b88c807SRodney W. Grimes else if (ar_rdsync() == 0)
3484b88c807SRodney W. Grimes continue;
3494b88c807SRodney W. Grimes if (ar_next() < 0)
3504b88c807SRodney W. Grimes break;
3514b88c807SRodney W. Grimes rdcnt = 0;
3524b88c807SRodney W. Grimes errcnt = 0;
3534b88c807SRodney W. Grimes }
3544b88c807SRodney W. Grimes return(-1);
3554b88c807SRodney W. Grimes }
3564b88c807SRodney W. Grimes
3574b88c807SRodney W. Grimes /*
3584b88c807SRodney W. Grimes * pback()
3594b88c807SRodney W. Grimes * push the data used during the archive id phase back into the I/O
3604b88c807SRodney W. Grimes * buffer. This is required as we cannot be sure that the header does NOT
36101c99176SUlrich Spörlein * overlap a block boundary (as in the case we are trying to recover a
3624b88c807SRodney W. Grimes * flawed archived). This was not designed to be used for any other
3634b88c807SRodney W. Grimes * purpose. (What software engineering, HA!)
3644b88c807SRodney W. Grimes * WARNING: do not even THINK of pback greater than BLKMULT, unless the
3654b88c807SRodney W. Grimes * pback space is increased.
3664b88c807SRodney W. Grimes */
3674b88c807SRodney W. Grimes
3684b88c807SRodney W. Grimes void
pback(char * pt,int cnt)3694b88c807SRodney W. Grimes pback(char *pt, int cnt)
3704b88c807SRodney W. Grimes {
3714b88c807SRodney W. Grimes bufpt -= cnt;
372778766feSKris Kennaway memcpy(bufpt, pt, cnt);
3734b88c807SRodney W. Grimes return;
3744b88c807SRodney W. Grimes }
3754b88c807SRodney W. Grimes
3764b88c807SRodney W. Grimes /*
3774b88c807SRodney W. Grimes * rd_skip()
37801c99176SUlrich Spörlein * skip forward in the archive during an archive read. Used to get quickly
3794b88c807SRodney W. Grimes * past file data and padding for files the user did NOT select.
3804b88c807SRodney W. Grimes * Return:
3814b88c807SRodney W. Grimes * 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected.
3824b88c807SRodney W. Grimes */
3834b88c807SRodney W. Grimes
3844b88c807SRodney W. Grimes int
rd_skip(off_t skcnt)3854b88c807SRodney W. Grimes rd_skip(off_t skcnt)
3864b88c807SRodney W. Grimes {
3874b88c807SRodney W. Grimes off_t res;
3884b88c807SRodney W. Grimes off_t cnt;
3894b88c807SRodney W. Grimes off_t skipped = 0;
3904b88c807SRodney W. Grimes
3914b88c807SRodney W. Grimes /*
39201c99176SUlrich Spörlein * consume what data we have in the buffer. If we have to move forward
3934b88c807SRodney W. Grimes * whole records, we call the low level skip function to see if we can
3944b88c807SRodney W. Grimes * move within the archive without doing the expensive reads on data we
3954b88c807SRodney W. Grimes * do not want.
3964b88c807SRodney W. Grimes */
3974b88c807SRodney W. Grimes if (skcnt == 0)
3984b88c807SRodney W. Grimes return(0);
3994b88c807SRodney W. Grimes res = MIN((bufend - bufpt), skcnt);
4004b88c807SRodney W. Grimes bufpt += res;
4014b88c807SRodney W. Grimes skcnt -= res;
4024b88c807SRodney W. Grimes
4034b88c807SRodney W. Grimes /*
4044b88c807SRodney W. Grimes * if skcnt is now 0, then no additional i/o is needed
4054b88c807SRodney W. Grimes */
4064b88c807SRodney W. Grimes if (skcnt == 0)
4074b88c807SRodney W. Grimes return(0);
4084b88c807SRodney W. Grimes
4094b88c807SRodney W. Grimes /*
4104b88c807SRodney W. Grimes * We have to read more, calculate complete and partial record reads
4114b88c807SRodney W. Grimes * based on rdblksz. we skip over "cnt" complete records
4124b88c807SRodney W. Grimes */
4134b88c807SRodney W. Grimes res = skcnt%rdblksz;
4144b88c807SRodney W. Grimes cnt = (skcnt/rdblksz) * rdblksz;
4154b88c807SRodney W. Grimes
4164b88c807SRodney W. Grimes /*
4174b88c807SRodney W. Grimes * if the skip fails, we will have to resync. ar_fow will tell us
4184b88c807SRodney W. Grimes * how much it can skip over. We will have to read the rest.
4194b88c807SRodney W. Grimes */
4204b88c807SRodney W. Grimes if (ar_fow(cnt, &skipped) < 0)
4214b88c807SRodney W. Grimes return(-1);
4224b88c807SRodney W. Grimes res += cnt - skipped;
4234b88c807SRodney W. Grimes rdcnt += skipped;
4244b88c807SRodney W. Grimes
4254b88c807SRodney W. Grimes /*
4264b88c807SRodney W. Grimes * what is left we have to read (which may be the whole thing if
4274b88c807SRodney W. Grimes * ar_fow() told us the device can only read to skip records);
4284b88c807SRodney W. Grimes */
4294b88c807SRodney W. Grimes while (res > 0L) {
4304b88c807SRodney W. Grimes cnt = bufend - bufpt;
4314b88c807SRodney W. Grimes /*
4324b88c807SRodney W. Grimes * if the read fails, we will have to resync
4334b88c807SRodney W. Grimes */
4344b88c807SRodney W. Grimes if ((cnt <= 0) && ((cnt = buf_fill()) < 0))
4354b88c807SRodney W. Grimes return(-1);
4364b88c807SRodney W. Grimes if (cnt == 0)
4374b88c807SRodney W. Grimes return(1);
4384b88c807SRodney W. Grimes cnt = MIN(cnt, res);
4394b88c807SRodney W. Grimes bufpt += cnt;
4404b88c807SRodney W. Grimes res -= cnt;
4414b88c807SRodney W. Grimes }
4424b88c807SRodney W. Grimes return(0);
4434b88c807SRodney W. Grimes }
4444b88c807SRodney W. Grimes
4454b88c807SRodney W. Grimes /*
4464b88c807SRodney W. Grimes * wr_fin()
4474b88c807SRodney W. Grimes * flush out any data (and pad if required) the last block. We always pad
4484b88c807SRodney W. Grimes * with zero (even though we do not have to). Padding with 0 makes it a
44901c99176SUlrich Spörlein * lot easier to recover if the archive is damaged. zero padding SHOULD
4504b88c807SRodney W. Grimes * BE a requirement....
4514b88c807SRodney W. Grimes */
4524b88c807SRodney W. Grimes
4534b88c807SRodney W. Grimes void
wr_fin(void)4544b88c807SRodney W. Grimes wr_fin(void)
4554b88c807SRodney W. Grimes {
4564b88c807SRodney W. Grimes if (bufpt > buf) {
457778766feSKris Kennaway memset(bufpt, 0, bufend - bufpt);
4584b88c807SRodney W. Grimes bufpt = bufend;
4594b88c807SRodney W. Grimes (void)buf_flush(blksz);
4604b88c807SRodney W. Grimes }
4614b88c807SRodney W. Grimes }
4624b88c807SRodney W. Grimes
4634b88c807SRodney W. Grimes /*
4644b88c807SRodney W. Grimes * wr_rdbuf()
4654b88c807SRodney W. Grimes * fill the write buffer from data passed to it in a buffer (usually used
4664b88c807SRodney W. Grimes * by format specific write routines to pass a file header). On failure we
4674b88c807SRodney W. Grimes * punt. We do not allow the user to continue to write flawed archives.
4684b88c807SRodney W. Grimes * We assume these headers are not very large (the memory copy we use is
4694b88c807SRodney W. Grimes * a bit expensive).
4704b88c807SRodney W. Grimes * Return:
4714b88c807SRodney W. Grimes * 0 if buffer was filled ok, -1 o.w. (buffer flush failure)
4724b88c807SRodney W. Grimes */
4734b88c807SRodney W. Grimes
4744b88c807SRodney W. Grimes int
wr_rdbuf(char * out,int outcnt)475f789b261SWarner Losh wr_rdbuf(char *out, int outcnt)
4764b88c807SRodney W. Grimes {
477f789b261SWarner Losh int cnt;
4784b88c807SRodney W. Grimes
4794b88c807SRodney W. Grimes /*
480dae3a64fSEitan Adler * while there is data to copy into the write buffer. when the
4814b88c807SRodney W. Grimes * write buffer fills, flush it to the archive and continue
4824b88c807SRodney W. Grimes */
4834b88c807SRodney W. Grimes while (outcnt > 0) {
4844b88c807SRodney W. Grimes cnt = bufend - bufpt;
4854b88c807SRodney W. Grimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
4864b88c807SRodney W. Grimes return(-1);
4874b88c807SRodney W. Grimes /*
4884b88c807SRodney W. Grimes * only move what we have space for
4894b88c807SRodney W. Grimes */
4904b88c807SRodney W. Grimes cnt = MIN(cnt, outcnt);
491778766feSKris Kennaway memcpy(bufpt, out, cnt);
4924b88c807SRodney W. Grimes bufpt += cnt;
4934b88c807SRodney W. Grimes out += cnt;
4944b88c807SRodney W. Grimes outcnt -= cnt;
4954b88c807SRodney W. Grimes }
4964b88c807SRodney W. Grimes return(0);
4974b88c807SRodney W. Grimes }
4984b88c807SRodney W. Grimes
4994b88c807SRodney W. Grimes /*
5004b88c807SRodney W. Grimes * rd_wrbuf()
5014b88c807SRodney W. Grimes * copy from the read buffer into a supplied buffer a specified number of
5024b88c807SRodney W. Grimes * bytes. If the read buffer is empty fill it and continue to copy.
5034b88c807SRodney W. Grimes * usually used to obtain a file header for processing by a format
5044b88c807SRodney W. Grimes * specific read routine.
5054b88c807SRodney W. Grimes * Return
5064b88c807SRodney W. Grimes * number of bytes copied to the buffer, 0 indicates EOF on archive volume,
5074b88c807SRodney W. Grimes * -1 is a read error
5084b88c807SRodney W. Grimes */
5094b88c807SRodney W. Grimes
5104b88c807SRodney W. Grimes int
rd_wrbuf(char * in,int cpcnt)511f789b261SWarner Losh rd_wrbuf(char *in, int cpcnt)
5124b88c807SRodney W. Grimes {
513f789b261SWarner Losh int res;
514f789b261SWarner Losh int cnt;
515f789b261SWarner Losh int incnt = cpcnt;
5164b88c807SRodney W. Grimes
5174b88c807SRodney W. Grimes /*
5184b88c807SRodney W. Grimes * loop until we fill the buffer with the requested number of bytes
5194b88c807SRodney W. Grimes */
5204b88c807SRodney W. Grimes while (incnt > 0) {
5214b88c807SRodney W. Grimes cnt = bufend - bufpt;
5224b88c807SRodney W. Grimes if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) {
5234b88c807SRodney W. Grimes /*
5244b88c807SRodney W. Grimes * read error, return what we got (or the error if
5254b88c807SRodney W. Grimes * no data was copied). The caller must know that an
52601c99176SUlrich Spörlein * error occurred and has the best knowledge what to
5274b88c807SRodney W. Grimes * do with it
5284b88c807SRodney W. Grimes */
5294b88c807SRodney W. Grimes if ((res = cpcnt - incnt) > 0)
5304b88c807SRodney W. Grimes return(res);
5314b88c807SRodney W. Grimes return(cnt);
5324b88c807SRodney W. Grimes }
5334b88c807SRodney W. Grimes
5344b88c807SRodney W. Grimes /*
5358db44603SElyes HAOUAS * calculate how much data to copy based on what's left and
5364b88c807SRodney W. Grimes * state of buffer
5374b88c807SRodney W. Grimes */
5384b88c807SRodney W. Grimes cnt = MIN(cnt, incnt);
539778766feSKris Kennaway memcpy(in, bufpt, cnt);
5404b88c807SRodney W. Grimes bufpt += cnt;
5414b88c807SRodney W. Grimes incnt -= cnt;
5424b88c807SRodney W. Grimes in += cnt;
5434b88c807SRodney W. Grimes }
5444b88c807SRodney W. Grimes return(cpcnt);
5454b88c807SRodney W. Grimes }
5464b88c807SRodney W. Grimes
5474b88c807SRodney W. Grimes /*
5484b88c807SRodney W. Grimes * wr_skip()
54946be34b9SKris Kennaway * skip forward during a write. In other words add padding to the file.
5504b88c807SRodney W. Grimes * we add zero filled padding as it makes flawed archives much easier to
5514b88c807SRodney W. Grimes * recover from. the caller tells us how many bytes of padding to add
5524b88c807SRodney W. Grimes * This routine was not designed to add HUGE amount of padding, just small
5534b88c807SRodney W. Grimes * amounts (a few 512 byte blocks at most)
5544b88c807SRodney W. Grimes * Return:
5554b88c807SRodney W. Grimes * 0 if ok, -1 if there was a buf_flush failure
5564b88c807SRodney W. Grimes */
5574b88c807SRodney W. Grimes
5584b88c807SRodney W. Grimes int
wr_skip(off_t skcnt)5594b88c807SRodney W. Grimes wr_skip(off_t skcnt)
5604b88c807SRodney W. Grimes {
561f789b261SWarner Losh int cnt;
5624b88c807SRodney W. Grimes
5634b88c807SRodney W. Grimes /*
5644b88c807SRodney W. Grimes * loop while there is more padding to add
5654b88c807SRodney W. Grimes */
5664b88c807SRodney W. Grimes while (skcnt > 0L) {
5674b88c807SRodney W. Grimes cnt = bufend - bufpt;
5684b88c807SRodney W. Grimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
5694b88c807SRodney W. Grimes return(-1);
5704b88c807SRodney W. Grimes cnt = MIN(cnt, skcnt);
571778766feSKris Kennaway memset(bufpt, 0, cnt);
5724b88c807SRodney W. Grimes bufpt += cnt;
5734b88c807SRodney W. Grimes skcnt -= cnt;
5744b88c807SRodney W. Grimes }
5754b88c807SRodney W. Grimes return(0);
5764b88c807SRodney W. Grimes }
5774b88c807SRodney W. Grimes
5784b88c807SRodney W. Grimes /*
5794b88c807SRodney W. Grimes * wr_rdfile()
5804b88c807SRodney W. Grimes * fill write buffer with the contents of a file. We are passed an open
581cd8fb74dSGiorgos Keramidas * file descriptor to the file and the archive structure that describes the
5824b88c807SRodney W. Grimes * file we are storing. The variable "left" is modified to contain the
5834b88c807SRodney W. Grimes * number of bytes of the file we were NOT able to write to the archive.
5844b88c807SRodney W. Grimes * it is important that we always write EXACTLY the number of bytes that
5854b88c807SRodney W. Grimes * the format specific write routine told us to. The file can also get
5864b88c807SRodney W. Grimes * bigger, so reading to the end of file would create an improper archive,
587778766feSKris Kennaway * we just detect this case and warn the user. We never create a bad
5884b88c807SRodney W. Grimes * archive if we can avoid it. Of course trying to archive files that are
5894b88c807SRodney W. Grimes * active is asking for trouble. It we fail, we pass back how much we
5904b88c807SRodney W. Grimes * could NOT copy and let the caller deal with it.
5914b88c807SRodney W. Grimes * Return:
5924b88c807SRodney W. Grimes * 0 ok, -1 if archive write failure. a short read of the file returns a
5934b88c807SRodney W. Grimes * 0, but "left" is set to be greater than zero.
5944b88c807SRodney W. Grimes */
5954b88c807SRodney W. Grimes
5964b88c807SRodney W. Grimes int
wr_rdfile(ARCHD * arcn,int ifd,off_t * left)5974b88c807SRodney W. Grimes wr_rdfile(ARCHD *arcn, int ifd, off_t *left)
5984b88c807SRodney W. Grimes {
599f789b261SWarner Losh int cnt;
600f789b261SWarner Losh int res = 0;
601f789b261SWarner Losh off_t size = arcn->sb.st_size;
6024b88c807SRodney W. Grimes struct stat sb;
6034b88c807SRodney W. Grimes
6044b88c807SRodney W. Grimes /*
6054b88c807SRodney W. Grimes * while there are more bytes to write
6064b88c807SRodney W. Grimes */
6074b88c807SRodney W. Grimes while (size > 0L) {
6084b88c807SRodney W. Grimes cnt = bufend - bufpt;
6094b88c807SRodney W. Grimes if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) {
6104b88c807SRodney W. Grimes *left = size;
6114b88c807SRodney W. Grimes return(-1);
6124b88c807SRodney W. Grimes }
6134b88c807SRodney W. Grimes cnt = MIN(cnt, size);
6144b88c807SRodney W. Grimes if ((res = read(ifd, bufpt, cnt)) <= 0)
6154b88c807SRodney W. Grimes break;
6164b88c807SRodney W. Grimes size -= res;
6174b88c807SRodney W. Grimes bufpt += res;
6184b88c807SRodney W. Grimes }
6194b88c807SRodney W. Grimes
6204b88c807SRodney W. Grimes /*
6214b88c807SRodney W. Grimes * better check the file did not change during this operation
6224b88c807SRodney W. Grimes * or the file read failed.
6234b88c807SRodney W. Grimes */
6244b88c807SRodney W. Grimes if (res < 0)
625778766feSKris Kennaway syswarn(1, errno, "Read fault on %s", arcn->org_name);
6264b88c807SRodney W. Grimes else if (size != 0L)
627778766feSKris Kennaway paxwarn(1, "File changed size during read %s", arcn->org_name);
6284b88c807SRodney W. Grimes else if (fstat(ifd, &sb) < 0)
629778766feSKris Kennaway syswarn(1, errno, "Failed stat on %s", arcn->org_name);
6304b88c807SRodney W. Grimes else if (arcn->sb.st_mtime != sb.st_mtime)
631778766feSKris Kennaway paxwarn(1, "File %s was modified during copy to archive",
6324b88c807SRodney W. Grimes arcn->org_name);
6334b88c807SRodney W. Grimes *left = size;
6344b88c807SRodney W. Grimes return(0);
6354b88c807SRodney W. Grimes }
6364b88c807SRodney W. Grimes
6374b88c807SRodney W. Grimes /*
6384b88c807SRodney W. Grimes * rd_wrfile()
6394b88c807SRodney W. Grimes * extract the contents of a file from the archive. If we are unable to
6404b88c807SRodney W. Grimes * extract the entire file (due to failure to write the file) we return
6414b88c807SRodney W. Grimes * the numbers of bytes we did NOT process. This way the caller knows how
6424b88c807SRodney W. Grimes * many bytes to skip past to find the next archive header. If the failure
6434b88c807SRodney W. Grimes * was due to an archive read, we will catch that when we try to skip. If
6444b88c807SRodney W. Grimes * the format supplies a file data crc value, we calculate the actual crc
6454b88c807SRodney W. Grimes * so that it can be compared to the value stored in the header
6464b88c807SRodney W. Grimes * NOTE:
6474b88c807SRodney W. Grimes * We call a special function to write the file. This function attempts to
6484b88c807SRodney W. Grimes * restore file holes (blocks of zeros) into the file. When files are
6494b88c807SRodney W. Grimes * sparse this saves space, and is a LOT faster. For non sparse files
6504b88c807SRodney W. Grimes * the performance hit is small. As of this writing, no archive supports
6514b88c807SRodney W. Grimes * information on where the file holes are.
6524b88c807SRodney W. Grimes * Return:
6534b88c807SRodney W. Grimes * 0 ok, -1 if archive read failure. if we cannot write the entire file,
6544b88c807SRodney W. Grimes * we return a 0 but "left" is set to be the amount unwritten
6554b88c807SRodney W. Grimes */
6564b88c807SRodney W. Grimes
6574b88c807SRodney W. Grimes int
rd_wrfile(ARCHD * arcn,int ofd,off_t * left)6584b88c807SRodney W. Grimes rd_wrfile(ARCHD *arcn, int ofd, off_t *left)
6594b88c807SRodney W. Grimes {
660f789b261SWarner Losh int cnt = 0;
661f789b261SWarner Losh off_t size = arcn->sb.st_size;
662f789b261SWarner Losh int res = 0;
663f789b261SWarner Losh char *fnm = arcn->name;
6644b88c807SRodney W. Grimes int isem = 1;
6654b88c807SRodney W. Grimes int rem;
6664b88c807SRodney W. Grimes int sz = MINFBSZ;
6674b88c807SRodney W. Grimes struct stat sb;
6684b88c807SRodney W. Grimes u_long crc = 0L;
6694b88c807SRodney W. Grimes
6704b88c807SRodney W. Grimes /*
6714b88c807SRodney W. Grimes * pass the blocksize of the file being written to the write routine,
6724b88c807SRodney W. Grimes * if the size is zero, use the default MINFBSZ
6734b88c807SRodney W. Grimes */
6744b88c807SRodney W. Grimes if (fstat(ofd, &sb) == 0) {
6754b88c807SRodney W. Grimes if (sb.st_blksize > 0)
6764b88c807SRodney W. Grimes sz = (int)sb.st_blksize;
6774b88c807SRodney W. Grimes } else
678778766feSKris Kennaway syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
6794b88c807SRodney W. Grimes rem = sz;
6804b88c807SRodney W. Grimes *left = 0L;
6814b88c807SRodney W. Grimes
6824b88c807SRodney W. Grimes /*
6834b88c807SRodney W. Grimes * Copy the archive to the file the number of bytes specified. We have
6844b88c807SRodney W. Grimes * to assume that we want to recover file holes as none of the archive
6854b88c807SRodney W. Grimes * formats can record the location of file holes.
6864b88c807SRodney W. Grimes */
6874b88c807SRodney W. Grimes while (size > 0L) {
6884b88c807SRodney W. Grimes cnt = bufend - bufpt;
6894b88c807SRodney W. Grimes /*
6904b88c807SRodney W. Grimes * if we get a read error, we do not want to skip, as we may
6914b88c807SRodney W. Grimes * miss a header, so we do not set left, but if we get a write
6924b88c807SRodney W. Grimes * error, we do want to skip over the unprocessed data.
6934b88c807SRodney W. Grimes */
6944b88c807SRodney W. Grimes if ((cnt <= 0) && ((cnt = buf_fill()) <= 0))
6954b88c807SRodney W. Grimes break;
6964b88c807SRodney W. Grimes cnt = MIN(cnt, size);
6974b88c807SRodney W. Grimes if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) {
6984b88c807SRodney W. Grimes *left = size;
6994b88c807SRodney W. Grimes break;
7004b88c807SRodney W. Grimes }
7014b88c807SRodney W. Grimes
7024b88c807SRodney W. Grimes if (docrc) {
7034b88c807SRodney W. Grimes /*
7044b88c807SRodney W. Grimes * update the actual crc value
7054b88c807SRodney W. Grimes */
7064b88c807SRodney W. Grimes cnt = res;
7074b88c807SRodney W. Grimes while (--cnt >= 0)
7084b88c807SRodney W. Grimes crc += *bufpt++ & 0xff;
7094b88c807SRodney W. Grimes } else
7104b88c807SRodney W. Grimes bufpt += res;
7114b88c807SRodney W. Grimes size -= res;
7124b88c807SRodney W. Grimes }
7134b88c807SRodney W. Grimes
7144b88c807SRodney W. Grimes /*
7154b88c807SRodney W. Grimes * if the last block has a file hole (all zero), we must make sure this
7164b88c807SRodney W. Grimes * gets updated in the file. We force the last block of zeros to be
71746be34b9SKris Kennaway * written. just closing with the file offset moved forward may not put
7184b88c807SRodney W. Grimes * a hole at the end of the file.
7194b88c807SRodney W. Grimes */
7204b88c807SRodney W. Grimes if (isem && (arcn->sb.st_size > 0L))
7214b88c807SRodney W. Grimes file_flush(ofd, fnm, isem);
7224b88c807SRodney W. Grimes
7234b88c807SRodney W. Grimes /*
7244b88c807SRodney W. Grimes * if we failed from archive read, we do not want to skip
7254b88c807SRodney W. Grimes */
7264b88c807SRodney W. Grimes if ((size > 0L) && (*left == 0L))
7274b88c807SRodney W. Grimes return(-1);
7284b88c807SRodney W. Grimes
7294b88c807SRodney W. Grimes /*
7304b88c807SRodney W. Grimes * some formats record a crc on file data. If so, then we compare the
7314b88c807SRodney W. Grimes * calculated crc to the crc stored in the archive
7324b88c807SRodney W. Grimes */
7334b88c807SRodney W. Grimes if (docrc && (size == 0L) && (arcn->crc != crc))
734778766feSKris Kennaway paxwarn(1,"Actual crc does not match expected crc %s",arcn->name);
7354b88c807SRodney W. Grimes return(0);
7364b88c807SRodney W. Grimes }
7374b88c807SRodney W. Grimes
7384b88c807SRodney W. Grimes /*
7394b88c807SRodney W. Grimes * cp_file()
7404b88c807SRodney W. Grimes * copy the contents of one file to another. used during -rw phase of pax
7414b88c807SRodney W. Grimes * just as in rd_wrfile() we use a special write function to write the
7424b88c807SRodney W. Grimes * destination file so we can properly copy files with holes.
7434b88c807SRodney W. Grimes */
7444b88c807SRodney W. Grimes
7454b88c807SRodney W. Grimes void
cp_file(ARCHD * arcn,int fd1,int fd2)7464b88c807SRodney W. Grimes cp_file(ARCHD *arcn, int fd1, int fd2)
7474b88c807SRodney W. Grimes {
748f789b261SWarner Losh int cnt;
749f789b261SWarner Losh off_t cpcnt = 0L;
750f789b261SWarner Losh int res = 0;
751f789b261SWarner Losh char *fnm = arcn->name;
752f789b261SWarner Losh int no_hole = 0;
7534b88c807SRodney W. Grimes int isem = 1;
7544b88c807SRodney W. Grimes int rem;
7554b88c807SRodney W. Grimes int sz = MINFBSZ;
7564b88c807SRodney W. Grimes struct stat sb;
7574b88c807SRodney W. Grimes
7584b88c807SRodney W. Grimes /*
7594b88c807SRodney W. Grimes * check for holes in the source file. If none, we will use regular
7604b88c807SRodney W. Grimes * write instead of file write.
7614b88c807SRodney W. Grimes */
7624b88c807SRodney W. Grimes if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size)
7634b88c807SRodney W. Grimes ++no_hole;
7644b88c807SRodney W. Grimes
7654b88c807SRodney W. Grimes /*
7664b88c807SRodney W. Grimes * pass the blocksize of the file being written to the write routine,
7674b88c807SRodney W. Grimes * if the size is zero, use the default MINFBSZ
7684b88c807SRodney W. Grimes */
7694b88c807SRodney W. Grimes if (fstat(fd2, &sb) == 0) {
7704b88c807SRodney W. Grimes if (sb.st_blksize > 0)
7714b88c807SRodney W. Grimes sz = sb.st_blksize;
7724b88c807SRodney W. Grimes } else
773778766feSKris Kennaway syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
7744b88c807SRodney W. Grimes rem = sz;
7754b88c807SRodney W. Grimes
7764b88c807SRodney W. Grimes /*
7774b88c807SRodney W. Grimes * read the source file and copy to destination file until EOF
7784b88c807SRodney W. Grimes */
7794b88c807SRodney W. Grimes for(;;) {
7804b88c807SRodney W. Grimes if ((cnt = read(fd1, buf, blksz)) <= 0)
7814b88c807SRodney W. Grimes break;
7824b88c807SRodney W. Grimes if (no_hole)
7834b88c807SRodney W. Grimes res = write(fd2, buf, cnt);
7844b88c807SRodney W. Grimes else
7854b88c807SRodney W. Grimes res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm);
7864b88c807SRodney W. Grimes if (res != cnt)
7874b88c807SRodney W. Grimes break;
7884b88c807SRodney W. Grimes cpcnt += cnt;
7894b88c807SRodney W. Grimes }
7904b88c807SRodney W. Grimes
7914b88c807SRodney W. Grimes /*
7924b88c807SRodney W. Grimes * check to make sure the copy is valid.
7934b88c807SRodney W. Grimes */
7944b88c807SRodney W. Grimes if (res < 0)
795778766feSKris Kennaway syswarn(1, errno, "Failed write during copy of %s to %s",
7964b88c807SRodney W. Grimes arcn->org_name, arcn->name);
7974b88c807SRodney W. Grimes else if (cpcnt != arcn->sb.st_size)
798778766feSKris Kennaway paxwarn(1, "File %s changed size during copy to %s",
7994b88c807SRodney W. Grimes arcn->org_name, arcn->name);
8004b88c807SRodney W. Grimes else if (fstat(fd1, &sb) < 0)
801778766feSKris Kennaway syswarn(1, errno, "Failed stat of %s", arcn->org_name);
8024b88c807SRodney W. Grimes else if (arcn->sb.st_mtime != sb.st_mtime)
803778766feSKris Kennaway paxwarn(1, "File %s was modified during copy to %s",
8044b88c807SRodney W. Grimes arcn->org_name, arcn->name);
8054b88c807SRodney W. Grimes
8064b88c807SRodney W. Grimes /*
8074b88c807SRodney W. Grimes * if the last block has a file hole (all zero), we must make sure this
8084b88c807SRodney W. Grimes * gets updated in the file. We force the last block of zeros to be
80946be34b9SKris Kennaway * written. just closing with the file offset moved forward may not put
8104b88c807SRodney W. Grimes * a hole at the end of the file.
8114b88c807SRodney W. Grimes */
8124b88c807SRodney W. Grimes if (!no_hole && isem && (arcn->sb.st_size > 0L))
8134b88c807SRodney W. Grimes file_flush(fd2, fnm, isem);
8144b88c807SRodney W. Grimes return;
8154b88c807SRodney W. Grimes }
8164b88c807SRodney W. Grimes
8174b88c807SRodney W. Grimes /*
8184b88c807SRodney W. Grimes * buf_fill()
8194b88c807SRodney W. Grimes * fill the read buffer with the next record (or what we can get) from
8204b88c807SRodney W. Grimes * the archive volume.
8214b88c807SRodney W. Grimes * Return:
8224b88c807SRodney W. Grimes * Number of bytes of data in the read buffer, -1 for read error, and
8234b88c807SRodney W. Grimes * 0 when finished (user specified termination in ar_next()).
8244b88c807SRodney W. Grimes */
8254b88c807SRodney W. Grimes
8264b88c807SRodney W. Grimes int
buf_fill(void)8274b88c807SRodney W. Grimes buf_fill(void)
8284b88c807SRodney W. Grimes {
829f789b261SWarner Losh int cnt;
8304b88c807SRodney W. Grimes static int fini = 0;
8314b88c807SRodney W. Grimes
8324b88c807SRodney W. Grimes if (fini)
8334b88c807SRodney W. Grimes return(0);
8344b88c807SRodney W. Grimes
8354b88c807SRodney W. Grimes for(;;) {
8364b88c807SRodney W. Grimes /*
8374b88c807SRodney W. Grimes * try to fill the buffer. on error the next archive volume is
8384b88c807SRodney W. Grimes * opened and we try again.
8394b88c807SRodney W. Grimes */
8404b88c807SRodney W. Grimes if ((cnt = ar_read(buf, blksz)) > 0) {
8414b88c807SRodney W. Grimes bufpt = buf;
8424b88c807SRodney W. Grimes bufend = buf + cnt;
8434b88c807SRodney W. Grimes rdcnt += cnt;
8444b88c807SRodney W. Grimes return(cnt);
8454b88c807SRodney W. Grimes }
8464b88c807SRodney W. Grimes
8474b88c807SRodney W. Grimes /*
8484b88c807SRodney W. Grimes * errors require resync, EOF goes to next archive
8498ad81aaeSPedro F. Giffuni * but in case we have not determined yet the format,
8508ad81aaeSPedro F. Giffuni * this means that we have a very short file, so we
8518ad81aaeSPedro F. Giffuni * are done again.
8524b88c807SRodney W. Grimes */
8534b88c807SRodney W. Grimes if (cnt < 0)
8544b88c807SRodney W. Grimes break;
8558ad81aaeSPedro F. Giffuni if (frmt == NULL || ar_next() < 0) {
8564b88c807SRodney W. Grimes fini = 1;
8574b88c807SRodney W. Grimes return(0);
8584b88c807SRodney W. Grimes }
8594b88c807SRodney W. Grimes rdcnt = 0;
8604b88c807SRodney W. Grimes }
8614b88c807SRodney W. Grimes exit_val = 1;
8624b88c807SRodney W. Grimes return(-1);
8634b88c807SRodney W. Grimes }
8644b88c807SRodney W. Grimes
8654b88c807SRodney W. Grimes /*
8664b88c807SRodney W. Grimes * buf_flush()
8674b88c807SRodney W. Grimes * force the write buffer to the archive. We are passed the number of
8684b88c807SRodney W. Grimes * bytes in the buffer at the point of the flush. When we change archives
8694b88c807SRodney W. Grimes * the record size might change. (either larger or smaller).
8704b88c807SRodney W. Grimes * Return:
8714b88c807SRodney W. Grimes * 0 if all is ok, -1 when a write error occurs.
8724b88c807SRodney W. Grimes */
8734b88c807SRodney W. Grimes
8744b88c807SRodney W. Grimes int
buf_flush(int bufcnt)875f789b261SWarner Losh buf_flush(int bufcnt)
8764b88c807SRodney W. Grimes {
877f789b261SWarner Losh int cnt;
878f789b261SWarner Losh int push = 0;
879f789b261SWarner Losh int totcnt = 0;
8804b88c807SRodney W. Grimes
8814b88c807SRodney W. Grimes /*
8824b88c807SRodney W. Grimes * if we have reached the user specified byte count for each archive
88301c99176SUlrich Spörlein * volume, prompt for the next volume. (The non-standard -R flag).
8844b88c807SRodney W. Grimes * NOTE: If the wrlimit is smaller than wrcnt, we will always write
8854b88c807SRodney W. Grimes * at least one record. We always round limit UP to next blocksize.
8864b88c807SRodney W. Grimes */
8874b88c807SRodney W. Grimes if ((wrlimit > 0) && (wrcnt > wrlimit)) {
888778766feSKris Kennaway paxwarn(0, "User specified archive volume byte limit reached.");
8894b88c807SRodney W. Grimes if (ar_next() < 0) {
8904b88c807SRodney W. Grimes wrcnt = 0;
8914b88c807SRodney W. Grimes exit_val = 1;
8924b88c807SRodney W. Grimes return(-1);
8934b88c807SRodney W. Grimes }
8944b88c807SRodney W. Grimes wrcnt = 0;
8954b88c807SRodney W. Grimes
8964b88c807SRodney W. Grimes /*
8974b88c807SRodney W. Grimes * The new archive volume might have changed the size of the
8984b88c807SRodney W. Grimes * write blocksize. if so we figure out if we need to write
8994b88c807SRodney W. Grimes * (one or more times), or if there is now free space left in
9004b88c807SRodney W. Grimes * the buffer (it is no longer full). bufcnt has the number of
9014b88c807SRodney W. Grimes * bytes in the buffer, (the blocksize, at the point we were
9024b88c807SRodney W. Grimes * CALLED). Push has the amount of "extra" data in the buffer
9034b88c807SRodney W. Grimes * if the block size has shrunk from a volume change.
9044b88c807SRodney W. Grimes */
9054b88c807SRodney W. Grimes bufend = buf + blksz;
9064b88c807SRodney W. Grimes if (blksz > bufcnt)
9074b88c807SRodney W. Grimes return(0);
9084b88c807SRodney W. Grimes if (blksz < bufcnt)
9094b88c807SRodney W. Grimes push = bufcnt - blksz;
9104b88c807SRodney W. Grimes }
9114b88c807SRodney W. Grimes
9124b88c807SRodney W. Grimes /*
9134b88c807SRodney W. Grimes * We have enough data to write at least one archive block
9144b88c807SRodney W. Grimes */
9154b88c807SRodney W. Grimes for (;;) {
9164b88c807SRodney W. Grimes /*
9174b88c807SRodney W. Grimes * write a block and check if it all went out ok
9184b88c807SRodney W. Grimes */
9194b88c807SRodney W. Grimes cnt = ar_write(buf, blksz);
9204b88c807SRodney W. Grimes if (cnt == blksz) {
9214b88c807SRodney W. Grimes /*
9224b88c807SRodney W. Grimes * the write went ok
9234b88c807SRodney W. Grimes */
9244b88c807SRodney W. Grimes wrcnt += cnt;
9254b88c807SRodney W. Grimes totcnt += cnt;
9264b88c807SRodney W. Grimes if (push > 0) {
9274b88c807SRodney W. Grimes /* we have extra data to push to the front.
9284b88c807SRodney W. Grimes * check for more than 1 block of push, and if
9294b88c807SRodney W. Grimes * so we loop back to write again
9304b88c807SRodney W. Grimes */
931778766feSKris Kennaway memcpy(buf, bufend, push);
9324b88c807SRodney W. Grimes bufpt = buf + push;
9334b88c807SRodney W. Grimes if (push >= blksz) {
9344b88c807SRodney W. Grimes push -= blksz;
9354b88c807SRodney W. Grimes continue;
9364b88c807SRodney W. Grimes }
9374b88c807SRodney W. Grimes } else
9384b88c807SRodney W. Grimes bufpt = buf;
9394b88c807SRodney W. Grimes return(totcnt);
9404b88c807SRodney W. Grimes } else if (cnt > 0) {
9414b88c807SRodney W. Grimes /*
9424b88c807SRodney W. Grimes * Oh drat we got a partial write!
94301c99176SUlrich Spörlein * if format doesn't care about alignment let it go,
944778766feSKris Kennaway * we warned the user in ar_write().... but this means
9454b88c807SRodney W. Grimes * the last record on this volume violates pax spec....
9464b88c807SRodney W. Grimes */
9474b88c807SRodney W. Grimes totcnt += cnt;
9484b88c807SRodney W. Grimes wrcnt += cnt;
9494b88c807SRodney W. Grimes bufpt = buf + cnt;
9504b88c807SRodney W. Grimes cnt = bufcnt - cnt;
951778766feSKris Kennaway memcpy(buf, bufpt, cnt);
9524b88c807SRodney W. Grimes bufpt = buf + cnt;
9534b88c807SRodney W. Grimes if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0))
9544b88c807SRodney W. Grimes return(totcnt);
9554b88c807SRodney W. Grimes break;
9564b88c807SRodney W. Grimes }
9574b88c807SRodney W. Grimes
9584b88c807SRodney W. Grimes /*
9594b88c807SRodney W. Grimes * All done, go to next archive
9604b88c807SRodney W. Grimes */
9614b88c807SRodney W. Grimes wrcnt = 0;
9624b88c807SRodney W. Grimes if (ar_next() < 0)
9634b88c807SRodney W. Grimes break;
9644b88c807SRodney W. Grimes
9654b88c807SRodney W. Grimes /*
9664b88c807SRodney W. Grimes * The new archive volume might also have changed the block
9674b88c807SRodney W. Grimes * size. if so, figure out if we have too much or too little
9684b88c807SRodney W. Grimes * data for using the new block size
9694b88c807SRodney W. Grimes */
9704b88c807SRodney W. Grimes bufend = buf + blksz;
9714b88c807SRodney W. Grimes if (blksz > bufcnt)
9724b88c807SRodney W. Grimes return(0);
9734b88c807SRodney W. Grimes if (blksz < bufcnt)
9744b88c807SRodney W. Grimes push = bufcnt - blksz;
9754b88c807SRodney W. Grimes }
9764b88c807SRodney W. Grimes
9774b88c807SRodney W. Grimes /*
9784b88c807SRodney W. Grimes * write failed, stop pax. we must not create a bad archive!
9794b88c807SRodney W. Grimes */
9804b88c807SRodney W. Grimes exit_val = 1;
9814b88c807SRodney W. Grimes return(-1);
9824b88c807SRodney W. Grimes }
983