| 1 |
/* $OpenBSD: buf_subs.c,v 1.21 2005/11/09 19:59:06 otto Exp $ */ |
| 2 |
/* $NetBSD: buf_subs.c,v 1.5 1995/03/21 09:07:08 cgd Exp $ */ |
| 3 |
|
| 4 |
/*- |
| 5 |
* Copyright (c) 1992 Keith Muller. |
| 6 |
* Copyright (c) 1992, 1993 |
| 7 |
* The Regents of the University of California. All rights reserved. |
| 8 |
* |
| 9 |
* This code is derived from software contributed to Berkeley by |
| 10 |
* Keith Muller of the University of California, San Diego. |
| 11 |
* |
| 12 |
* Redistribution and use in source and binary forms, with or without |
| 13 |
* modification, are permitted provided that the following conditions |
| 14 |
* are met: |
| 15 |
* 1. Redistributions of source code must retain the above copyright |
| 16 |
* notice, this list of conditions and the following disclaimer. |
| 17 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 18 |
* notice, this list of conditions and the following disclaimer in the |
| 19 |
* documentation and/or other materials provided with the distribution. |
| 20 |
* 3. Neither the name of the University nor the names of its contributors |
| 21 |
* may be used to endorse or promote products derived from this software |
| 22 |
* without specific prior written permission. |
| 23 |
* |
| 24 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 25 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 26 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 27 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 28 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 29 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 30 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 31 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 32 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 33 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 34 |
* SUCH DAMAGE. |
| 35 |
*/ |
| 36 |
|
| 37 |
#include <sys/param.h> |
| 38 |
#include <sys/time.h> |
| 39 |
#include <sys/stat.h> |
| 40 |
#include <stdio.h> |
| 41 |
#include <errno.h> |
| 42 |
#include <unistd.h> |
| 43 |
#include <stdlib.h> |
| 44 |
#include <string.h> |
| 45 |
#include "pax.h" |
| 46 |
#include "extern.h" |
| 47 |
|
| 48 |
__SCCSID("@(#)buf_subs.c 8.2 (Berkeley) 4/18/94"); |
| 49 |
__RCSID("$MirOS: src/bin/pax/buf_subs.c,v 1.2 2007/02/17 04:52:40 tg Exp $"); |
| 50 |
|
| 51 |
/* |
| 52 |
* routines which implement archive and file buffering |
| 53 |
*/ |
| 54 |
|
| 55 |
#define MINFBSZ 512 /* default block size for hole detect */ |
| 56 |
#define MAXFLT 10 /* default media read error limit */ |
| 57 |
|
| 58 |
/* |
| 59 |
* Need to change bufmem to dynamic allocation when the upper |
| 60 |
* limit on blocking size is removed (though that will violate pax spec) |
| 61 |
* MAXBLK define and tests will also need to be updated. |
| 62 |
*/ |
| 63 |
static char bufmem[MAXBLK+BLKMULT]; /* i/o buffer + pushback id space */ |
| 64 |
static char *buf; /* normal start of i/o buffer */ |
| 65 |
static char *bufend; /* end or last char in i/o buffer */ |
| 66 |
static char *bufpt; /* read/write point in i/o buffer */ |
| 67 |
int blksz = MAXBLK; /* block input/output size in bytes */ |
| 68 |
int wrblksz; /* user spec output size in bytes */ |
| 69 |
int maxflt = MAXFLT; /* MAX consecutive media errors */ |
| 70 |
int rdblksz; /* first read blksize (tapes only) */ |
| 71 |
off_t wrlimit; /* # of bytes written per archive vol */ |
| 72 |
off_t wrcnt; /* # of bytes written on current vol */ |
| 73 |
off_t rdcnt; /* # of bytes read on current vol */ |
| 74 |
|
| 75 |
/* |
| 76 |
* wr_start() |
| 77 |
* set up the buffering system to operate in a write mode |
| 78 |
* Return: |
| 79 |
* 0 if ok, -1 if the user specified write block size violates pax spec |
| 80 |
*/ |
| 81 |
|
| 82 |
int |
| 83 |
wr_start(void) |
| 84 |
{ |
| 85 |
buf = &(bufmem[BLKMULT]); |
| 86 |
/* |
| 87 |
* Check to make sure the write block size meets pax specs. If the user |
| 88 |
* does not specify a blocksize, we use the format default blocksize. |
| 89 |
* We must be picky on writes, so we do not allow the user to create an |
| 90 |
* archive that might be hard to read elsewhere. If all ok, we then |
| 91 |
* open the first archive volume |
| 92 |
*/ |
| 93 |
if (!wrblksz) |
| 94 |
wrblksz = frmt->bsz; |
| 95 |
if (wrblksz > MAXBLK) { |
| 96 |
paxwarn(1, "Write block size of %d too large, maximium is: %d", |
| 97 |
wrblksz, MAXBLK); |
| 98 |
return(-1); |
| 99 |
} |
| 100 |
if (wrblksz % BLKMULT) { |
| 101 |
paxwarn(1, "Write block size of %d is not a %d byte multiple", |
| 102 |
wrblksz, BLKMULT); |
| 103 |
return(-1); |
| 104 |
} |
| 105 |
if (wrblksz > MAXBLK_POSIX) { |
| 106 |
paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable", |
| 107 |
wrblksz, MAXBLK_POSIX); |
| 108 |
return(-1); |
| 109 |
} |
| 110 |
|
| 111 |
/* |
| 112 |
* we only allow wrblksz to be used with all archive operations |
| 113 |
*/ |
| 114 |
blksz = rdblksz = wrblksz; |
| 115 |
if ((ar_open(arcname) < 0) && (ar_next() < 0)) |
| 116 |
return(-1); |
| 117 |
wrcnt = 0; |
| 118 |
bufend = buf + wrblksz; |
| 119 |
bufpt = buf; |
| 120 |
return(0); |
| 121 |
} |
| 122 |
|
| 123 |
/* |
| 124 |
* rd_start() |
| 125 |
* set up buffering system to read an archive |
| 126 |
* Return: |
| 127 |
* 0 if ok, -1 otherwise |
| 128 |
*/ |
| 129 |
|
| 130 |
int |
| 131 |
rd_start(void) |
| 132 |
{ |
| 133 |
/* |
| 134 |
* leave space for the header pushback (see get_arc()). If we are |
| 135 |
* going to append and user specified a write block size, check it |
| 136 |
* right away |
| 137 |
*/ |
| 138 |
buf = &(bufmem[BLKMULT]); |
| 139 |
if ((act == APPND) && wrblksz) { |
| 140 |
if (wrblksz > MAXBLK) { |
| 141 |
paxwarn(1,"Write block size %d too large, maximium is: %d", |
| 142 |
wrblksz, MAXBLK); |
| 143 |
return(-1); |
| 144 |
} |
| 145 |
if (wrblksz % BLKMULT) { |
| 146 |
paxwarn(1, "Write block size %d is not a %d byte multiple", |
| 147 |
wrblksz, BLKMULT); |
| 148 |
return(-1); |
| 149 |
} |
| 150 |
} |
| 151 |
|
| 152 |
/* |
| 153 |
* open the archive |
| 154 |
*/ |
| 155 |
if ((ar_open(arcname) < 0) && (ar_next() < 0)) |
| 156 |
return(-1); |
| 157 |
bufend = buf + rdblksz; |
| 158 |
bufpt = bufend; |
| 159 |
rdcnt = 0; |
| 160 |
return(0); |
| 161 |
} |
| 162 |
|
| 163 |
/* |
| 164 |
* cp_start() |
| 165 |
* set up buffer system for copying within the file system |
| 166 |
*/ |
| 167 |
|
| 168 |
void |
| 169 |
cp_start(void) |
| 170 |
{ |
| 171 |
buf = &(bufmem[BLKMULT]); |
| 172 |
rdblksz = blksz = MAXBLK; |
| 173 |
} |
| 174 |
|
| 175 |
/* |
| 176 |
* appnd_start() |
| 177 |
* Set up the buffering system to append new members to an archive that |
| 178 |
* was just read. The last block(s) of an archive may contain a format |
| 179 |
* specific trailer. To append a new member, this trailer has to be |
| 180 |
* removed from the archive. The first byte of the trailer is replaced by |
| 181 |
* the start of the header of the first file added to the archive. The |
| 182 |
* format specific end read function tells us how many bytes to move |
| 183 |
* backwards in the archive to be positioned BEFORE the trailer. Two |
| 184 |
* different position have to be adjusted, the O.S. file offset (e.g. the |
| 185 |
* position of the tape head) and the write point within the data we have |
| 186 |
* stored in the read (soon to become write) buffer. We may have to move |
| 187 |
* back several records (the number depends on the size of the archive |
| 188 |
* record and the size of the format trailer) to read up the record where |
| 189 |
* the first byte of the trailer is recorded. Trailers may span (and |
| 190 |
* overlap) record boundaries. |
| 191 |
* We first calculate which record has the first byte of the trailer. We |
| 192 |
* move the OS file offset back to the start of this record and read it |
| 193 |
* up. We set the buffer write pointer to be at this byte (the byte where |
| 194 |
* the trailer starts). We then move the OS file pointer back to the |
| 195 |
* start of this record so a flush of this buffer will replace the record |
| 196 |
* in the archive. |
| 197 |
* A major problem is rewriting this last record. For archives stored |
| 198 |
* on disk files, this is trivial. However, many devices are really picky |
| 199 |
* about the conditions under which they will allow a write to occur. |
| 200 |
* Often devices restrict the conditions where writes can be made, |
| 201 |
* so it may not be feasible to append archives stored on all types of |
| 202 |
* devices. |
| 203 |
* Return: |
| 204 |
* 0 for success, -1 for failure |
| 205 |
*/ |
| 206 |
|
| 207 |
int |
| 208 |
appnd_start(off_t skcnt) |
| 209 |
{ |
| 210 |
int res; |
| 211 |
off_t cnt; |
| 212 |
|
| 213 |
if (exit_val != 0) { |
| 214 |
paxwarn(0, "Cannot append to an archive that may have flaws."); |
| 215 |
return(-1); |
| 216 |
} |
| 217 |
/* |
| 218 |
* if the user did not specify a write blocksize, inherit the size used |
| 219 |
* in the last archive volume read. (If a is set we still use rdblksz |
| 220 |
* until next volume, cannot shift sizes within a single volume). |
| 221 |
*/ |
| 222 |
if (!wrblksz) |
| 223 |
wrblksz = blksz = rdblksz; |
| 224 |
else |
| 225 |
blksz = rdblksz; |
| 226 |
|
| 227 |
/* |
| 228 |
* make sure that this volume allows appends |
| 229 |
*/ |
| 230 |
if (ar_app_ok() < 0) |
| 231 |
return(-1); |
| 232 |
|
| 233 |
/* |
| 234 |
* Calculate bytes to move back and move in front of record where we |
| 235 |
* need to start writing from. Remember we have to add in any padding |
| 236 |
* that might be in the buffer after the trailer in the last block. We |
| 237 |
* travel skcnt + padding ROUNDED UP to blksize. |
| 238 |
*/ |
| 239 |
skcnt += bufend - bufpt; |
| 240 |
if ((cnt = (skcnt/blksz) * blksz) < skcnt) |
| 241 |
cnt += blksz; |
| 242 |
if (ar_rev((off_t)cnt) < 0) |
| 243 |
goto out; |
| 244 |
|
| 245 |
/* |
| 246 |
* We may have gone too far if there is valid data in the block we are |
| 247 |
* now in front of, read up the block and position the pointer after |
| 248 |
* the valid data. |
| 249 |
*/ |
| 250 |
if ((cnt -= skcnt) > 0) { |
| 251 |
/* |
| 252 |
* watch out for stupid tape drives. ar_rev() will set rdblksz |
| 253 |
* to be real physical blocksize so we must loop until we get |
| 254 |
* the old rdblksz (now in blksz). If ar_rev() fouls up the |
| 255 |
* determination of the physical block size, we will fail. |
| 256 |
*/ |
| 257 |
bufpt = buf; |
| 258 |
bufend = buf + blksz; |
| 259 |
while (bufpt < bufend) { |
| 260 |
if ((res = ar_read(bufpt, rdblksz)) <= 0) |
| 261 |
goto out; |
| 262 |
bufpt += res; |
| 263 |
} |
| 264 |
if (ar_rev((off_t)(bufpt - buf)) < 0) |
| 265 |
goto out; |
| 266 |
bufpt = buf + cnt; |
| 267 |
bufend = buf + blksz; |
| 268 |
} else { |
| 269 |
/* |
| 270 |
* buffer is empty |
| 271 |
*/ |
| 272 |
bufend = buf + blksz; |
| 273 |
bufpt = buf; |
| 274 |
} |
| 275 |
rdblksz = blksz; |
| 276 |
rdcnt -= skcnt; |
| 277 |
wrcnt = 0; |
| 278 |
|
| 279 |
/* |
| 280 |
* At this point we are ready to write. If the device requires special |
| 281 |
* handling to write at a point were previously recorded data resides, |
| 282 |
* that is handled in ar_set_wr(). From now on we operate under normal |
| 283 |
* ARCHIVE mode (write) conditions |
| 284 |
*/ |
| 285 |
if (ar_set_wr() < 0) |
| 286 |
return(-1); |
| 287 |
act = ARCHIVE; |
| 288 |
return(0); |
| 289 |
|
| 290 |
out: |
| 291 |
paxwarn(1, "Unable to rewrite archive trailer, cannot append."); |
| 292 |
return(-1); |
| 293 |
} |
| 294 |
|
| 295 |
/* |
| 296 |
* rd_sync() |
| 297 |
* A read error occurred on this archive volume. Resync the buffer and |
| 298 |
* try to reset the device (if possible) so we can continue to read. Keep |
| 299 |
* trying to do this until we get a valid read, or we reach the limit on |
| 300 |
* consecutive read faults (at which point we give up). The user can |
| 301 |
* adjust the read error limit through a command line option. |
| 302 |
* Returns: |
| 303 |
* 0 on success, and -1 on failure |
| 304 |
*/ |
| 305 |
|
| 306 |
int |
| 307 |
rd_sync(void) |
| 308 |
{ |
| 309 |
int errcnt = 0; |
| 310 |
int res; |
| 311 |
|
| 312 |
/* |
| 313 |
* if the user says bail out on first fault, we are out of here... |
| 314 |
*/ |
| 315 |
if (maxflt == 0) |
| 316 |
return(-1); |
| 317 |
if (act == APPND) { |
| 318 |
paxwarn(1, "Unable to append when there are archive read errors."); |
| 319 |
return(-1); |
| 320 |
} |
| 321 |
|
| 322 |
/* |
| 323 |
* poke at device and try to get past media error |
| 324 |
*/ |
| 325 |
if (ar_rdsync() < 0) { |
| 326 |
if (ar_next() < 0) |
| 327 |
return(-1); |
| 328 |
else |
| 329 |
rdcnt = 0; |
| 330 |
} |
| 331 |
|
| 332 |
for (;;) { |
| 333 |
if ((res = ar_read(buf, blksz)) > 0) { |
| 334 |
/* |
| 335 |
* All right! got some data, fill that buffer |
| 336 |
*/ |
| 337 |
bufpt = buf; |
| 338 |
bufend = buf + res; |
| 339 |
rdcnt += res; |
| 340 |
return(0); |
| 341 |
} |
| 342 |
|
| 343 |
/* |
| 344 |
* Oh well, yet another failed read... |
| 345 |
* if error limit reached, ditch. o.w. poke device to move past |
| 346 |
* bad media and try again. if media is badly damaged, we ask |
| 347 |
* the poor (and upset user at this point) for the next archive |
| 348 |
* volume. remember the goal on reads is to get the most we |
| 349 |
* can extract out of the archive. |
| 350 |
*/ |
| 351 |
if ((maxflt > 0) && (++errcnt > maxflt)) |
| 352 |
paxwarn(0,"Archive read error limit (%d) reached",maxflt); |
| 353 |
else if (ar_rdsync() == 0) |
| 354 |
continue; |
| 355 |
if (ar_next() < 0) |
| 356 |
break; |
| 357 |
rdcnt = 0; |
| 358 |
errcnt = 0; |
| 359 |
} |
| 360 |
return(-1); |
| 361 |
} |
| 362 |
|
| 363 |
/* |
| 364 |
* pback() |
| 365 |
* push the data used during the archive id phase back into the I/O |
| 366 |
* buffer. This is required as we cannot be sure that the header does NOT |
| 367 |
* overlap a block boundary (as in the case we are trying to recover a |
| 368 |
* flawed archived). This was not designed to be used for any other |
| 369 |
* purpose. (What software engineering, HA!) |
| 370 |
* WARNING: do not even THINK of pback greater than BLKMULT, unless the |
| 371 |
* pback space is increased. |
| 372 |
*/ |
| 373 |
|
| 374 |
void |
| 375 |
pback(char *pt, int cnt) |
| 376 |
{ |
| 377 |
bufpt -= cnt; |
| 378 |
memcpy(bufpt, pt, cnt); |
| 379 |
return; |
| 380 |
} |
| 381 |
|
| 382 |
/* |
| 383 |
* rd_skip() |
| 384 |
* skip forward in the archive during a archive read. Used to get quickly |
| 385 |
* past file data and padding for files the user did NOT select. |
| 386 |
* Return: |
| 387 |
* 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected. |
| 388 |
*/ |
| 389 |
|
| 390 |
int |
| 391 |
rd_skip(off_t skcnt) |
| 392 |
{ |
| 393 |
off_t res; |
| 394 |
off_t cnt; |
| 395 |
off_t skipped = 0; |
| 396 |
|
| 397 |
/* |
| 398 |
* consume what data we have in the buffer. If we have to move forward |
| 399 |
* whole records, we call the low level skip function to see if we can |
| 400 |
* move within the archive without doing the expensive reads on data we |
| 401 |
* do not want. |
| 402 |
*/ |
| 403 |
if (skcnt == 0) |
| 404 |
return(0); |
| 405 |
res = MIN((bufend - bufpt), skcnt); |
| 406 |
bufpt += res; |
| 407 |
skcnt -= res; |
| 408 |
|
| 409 |
/* |
| 410 |
* if skcnt is now 0, then no additional i/o is needed |
| 411 |
*/ |
| 412 |
if (skcnt == 0) |
| 413 |
return(0); |
| 414 |
|
| 415 |
/* |
| 416 |
* We have to read more, calculate complete and partial record reads |
| 417 |
* based on rdblksz. we skip over "cnt" complete records |
| 418 |
*/ |
| 419 |
res = skcnt%rdblksz; |
| 420 |
cnt = (skcnt/rdblksz) * rdblksz; |
| 421 |
|
| 422 |
/* |
| 423 |
* if the skip fails, we will have to resync. ar_fow will tell us |
| 424 |
* how much it can skip over. We will have to read the rest. |
| 425 |
*/ |
| 426 |
if (ar_fow(cnt, &skipped) < 0) |
| 427 |
return(-1); |
| 428 |
res += cnt - skipped; |
| 429 |
rdcnt += skipped; |
| 430 |
|
| 431 |
/* |
| 432 |
* what is left we have to read (which may be the whole thing if |
| 433 |
* ar_fow() told us the device can only read to skip records); |
| 434 |
*/ |
| 435 |
while (res > 0L) { |
| 436 |
cnt = bufend - bufpt; |
| 437 |
/* |
| 438 |
* if the read fails, we will have to resync |
| 439 |
*/ |
| 440 |
if ((cnt <= 0) && ((cnt = buf_fill()) < 0)) |
| 441 |
return(-1); |
| 442 |
if (cnt == 0) |
| 443 |
return(1); |
| 444 |
cnt = MIN(cnt, res); |
| 445 |
bufpt += cnt; |
| 446 |
res -= cnt; |
| 447 |
} |
| 448 |
return(0); |
| 449 |
} |
| 450 |
|
| 451 |
/* |
| 452 |
* wr_fin() |
| 453 |
* flush out any data (and pad if required) the last block. We always pad |
| 454 |
* with zero (even though we do not have to). Padding with 0 makes it a |
| 455 |
* lot easier to recover if the archive is damaged. zero padding SHOULD |
| 456 |
* BE a requirement.... |
| 457 |
*/ |
| 458 |
|
| 459 |
void |
| 460 |
wr_fin(void) |
| 461 |
{ |
| 462 |
if (bufpt > buf) { |
| 463 |
memset(bufpt, 0, bufend - bufpt); |
| 464 |
bufpt = bufend; |
| 465 |
(void)buf_flush(blksz); |
| 466 |
} |
| 467 |
} |
| 468 |
|
| 469 |
/* |
| 470 |
* wr_rdbuf() |
| 471 |
* fill the write buffer from data passed to it in a buffer (usually used |
| 472 |
* by format specific write routines to pass a file header). On failure we |
| 473 |
* punt. We do not allow the user to continue to write flawed archives. |
| 474 |
* We assume these headers are not very large (the memory copy we use is |
| 475 |
* a bit expensive). |
| 476 |
* Return: |
| 477 |
* 0 if buffer was filled ok, -1 o.w. (buffer flush failure) |
| 478 |
*/ |
| 479 |
|
| 480 |
int |
| 481 |
wr_rdbuf(char *out, int outcnt) |
| 482 |
{ |
| 483 |
int cnt; |
| 484 |
|
| 485 |
/* |
| 486 |
* while there is data to copy copy into the write buffer. when the |
| 487 |
* write buffer fills, flush it to the archive and continue |
| 488 |
*/ |
| 489 |
while (outcnt > 0) { |
| 490 |
cnt = bufend - bufpt; |
| 491 |
if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) |
| 492 |
return(-1); |
| 493 |
/* |
| 494 |
* only move what we have space for |
| 495 |
*/ |
| 496 |
cnt = MIN(cnt, outcnt); |
| 497 |
memcpy(bufpt, out, cnt); |
| 498 |
bufpt += cnt; |
| 499 |
out += cnt; |
| 500 |
outcnt -= cnt; |
| 501 |
} |
| 502 |
return(0); |
| 503 |
} |
| 504 |
|
| 505 |
/* |
| 506 |
* rd_wrbuf() |
| 507 |
* copy from the read buffer into a supplied buffer a specified number of |
| 508 |
* bytes. If the read buffer is empty fill it and continue to copy. |
| 509 |
* usually used to obtain a file header for processing by a format |
| 510 |
* specific read routine. |
| 511 |
* Return |
| 512 |
* number of bytes copied to the buffer, 0 indicates EOF on archive volume, |
| 513 |
* -1 is a read error |
| 514 |
*/ |
| 515 |
|
| 516 |
int |
| 517 |
rd_wrbuf(char *in, int cpcnt) |
| 518 |
{ |
| 519 |
int res; |
| 520 |
int cnt; |
| 521 |
int incnt = cpcnt; |
| 522 |
|
| 523 |
/* |
| 524 |
* loop until we fill the buffer with the requested number of bytes |
| 525 |
*/ |
| 526 |
while (incnt > 0) { |
| 527 |
cnt = bufend - bufpt; |
| 528 |
if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) { |
| 529 |
/* |
| 530 |
* read error, return what we got (or the error if |
| 531 |
* no data was copied). The caller must know that an |
| 532 |
* error occurred and has the best knowledge what to |
| 533 |
* do with it |
| 534 |
*/ |
| 535 |
if ((res = cpcnt - incnt) > 0) |
| 536 |
return(res); |
| 537 |
return(cnt); |
| 538 |
} |
| 539 |
|
| 540 |
/* |
| 541 |
* calculate how much data to copy based on whats left and |
| 542 |
* state of buffer |
| 543 |
*/ |
| 544 |
cnt = MIN(cnt, incnt); |
| 545 |
memcpy(in, bufpt, cnt); |
| 546 |
bufpt += cnt; |
| 547 |
incnt -= cnt; |
| 548 |
in += cnt; |
| 549 |
} |
| 550 |
return(cpcnt); |
| 551 |
} |
| 552 |
|
| 553 |
/* |
| 554 |
* wr_skip() |
| 555 |
* skip forward during a write. In other words add padding to the file. |
| 556 |
* we add zero filled padding as it makes flawed archives much easier to |
| 557 |
* recover from. the caller tells us how many bytes of padding to add |
| 558 |
* This routine was not designed to add HUGE amount of padding, just small |
| 559 |
* amounts (a few 512 byte blocks at most) |
| 560 |
* Return: |
| 561 |
* 0 if ok, -1 if there was a buf_flush failure |
| 562 |
*/ |
| 563 |
|
| 564 |
int |
| 565 |
wr_skip(off_t skcnt) |
| 566 |
{ |
| 567 |
int cnt; |
| 568 |
|
| 569 |
/* |
| 570 |
* loop while there is more padding to add |
| 571 |
*/ |
| 572 |
while (skcnt > 0L) { |
| 573 |
cnt = bufend - bufpt; |
| 574 |
if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) |
| 575 |
return(-1); |
| 576 |
cnt = MIN(cnt, skcnt); |
| 577 |
memset(bufpt, 0, cnt); |
| 578 |
bufpt += cnt; |
| 579 |
skcnt -= cnt; |
| 580 |
} |
| 581 |
return(0); |
| 582 |
} |
| 583 |
|
| 584 |
/* |
| 585 |
* wr_rdfile() |
| 586 |
* fill write buffer with the contents of a file. We are passed an open |
| 587 |
* file descriptor to the file an the archive structure that describes the |
| 588 |
* file we are storing. The variable "left" is modified to contain the |
| 589 |
* number of bytes of the file we were NOT able to write to the archive. |
| 590 |
* it is important that we always write EXACTLY the number of bytes that |
| 591 |
* the format specific write routine told us to. The file can also get |
| 592 |
* bigger, so reading to the end of file would create an improper archive, |
| 593 |
* we just detect this case and warn the user. We never create a bad |
| 594 |
* archive if we can avoid it. Of course trying to archive files that are |
| 595 |
* active is asking for trouble. It we fail, we pass back how much we |
| 596 |
* could NOT copy and let the caller deal with it. |
| 597 |
* Return: |
| 598 |
* 0 ok, -1 if archive write failure. a short read of the file returns a |
| 599 |
* 0, but "left" is set to be greater than zero. |
| 600 |
*/ |
| 601 |
|
| 602 |
int |
| 603 |
wr_rdfile(ARCHD *arcn, int ifd, off_t *left) |
| 604 |
{ |
| 605 |
int cnt; |
| 606 |
int res = 0; |
| 607 |
off_t size = arcn->sb.st_size; |
| 608 |
struct stat sb; |
| 609 |
|
| 610 |
/* |
| 611 |
* while there are more bytes to write |
| 612 |
*/ |
| 613 |
while (size > 0L) { |
| 614 |
cnt = bufend - bufpt; |
| 615 |
if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) { |
| 616 |
*left = size; |
| 617 |
return(-1); |
| 618 |
} |
| 619 |
cnt = MIN(cnt, size); |
| 620 |
if ((res = read(ifd, bufpt, cnt)) <= 0) |
| 621 |
break; |
| 622 |
size -= res; |
| 623 |
bufpt += res; |
| 624 |
} |
| 625 |
|
| 626 |
/* |
| 627 |
* better check the file did not change during this operation |
| 628 |
* or the file read failed. |
| 629 |
*/ |
| 630 |
if (res < 0) |
| 631 |
syswarn(1, errno, "Read fault on %s", arcn->org_name); |
| 632 |
else if (size != 0L) |
| 633 |
paxwarn(1, "File changed size during read %s", arcn->org_name); |
| 634 |
else if (fstat(ifd, &sb) < 0) |
| 635 |
syswarn(1, errno, "Failed stat on %s", arcn->org_name); |
| 636 |
else if (arcn->sb.st_mtime != sb.st_mtime) |
| 637 |
paxwarn(1, "File %s was modified during copy to archive", |
| 638 |
arcn->org_name); |
| 639 |
*left = size; |
| 640 |
return(0); |
| 641 |
} |
| 642 |
|
| 643 |
/* |
| 644 |
* rd_wrfile() |
| 645 |
* extract the contents of a file from the archive. If we are unable to |
| 646 |
* extract the entire file (due to failure to write the file) we return |
| 647 |
* the numbers of bytes we did NOT process. This way the caller knows how |
| 648 |
* many bytes to skip past to find the next archive header. If the failure |
| 649 |
* was due to an archive read, we will catch that when we try to skip. If |
| 650 |
* the format supplies a file data crc value, we calculate the actual crc |
| 651 |
* so that it can be compared to the value stored in the header |
| 652 |
* NOTE: |
| 653 |
* We call a special function to write the file. This function attempts to |
| 654 |
* restore file holes (blocks of zeros) into the file. When files are |
| 655 |
* sparse this saves space, and is a LOT faster. For non sparse files |
| 656 |
* the performance hit is small. As of this writing, no archive supports |
| 657 |
* information on where the file holes are. |
| 658 |
* Return: |
| 659 |
* 0 ok, -1 if archive read failure. if we cannot write the entire file, |
| 660 |
* we return a 0 but "left" is set to be the amount unwritten |
| 661 |
*/ |
| 662 |
|
| 663 |
int |
| 664 |
rd_wrfile(ARCHD *arcn, int ofd, off_t *left) |
| 665 |
{ |
| 666 |
int cnt = 0; |
| 667 |
off_t size = arcn->sb.st_size; |
| 668 |
int res = 0; |
| 669 |
char *fnm = arcn->name; |
| 670 |
int isem = 1; |
| 671 |
int rem; |
| 672 |
int sz = MINFBSZ; |
| 673 |
struct stat sb; |
| 674 |
u_int32_t crc = 0; |
| 675 |
|
| 676 |
/* |
| 677 |
* pass the blocksize of the file being written to the write routine, |
| 678 |
* if the size is zero, use the default MINFBSZ |
| 679 |
*/ |
| 680 |
if (ofd < 0) |
| 681 |
sz = PAXPATHLEN + 1; /* GNU tar long link/file */ |
| 682 |
else if (fstat(ofd, &sb) == 0) { |
| 683 |
if (sb.st_blksize > 0) |
| 684 |
sz = (int)sb.st_blksize; |
| 685 |
} else |
| 686 |
syswarn(0,errno,"Unable to obtain block size for file %s",fnm); |
| 687 |
rem = sz; |
| 688 |
*left = 0L; |
| 689 |
|
| 690 |
/* |
| 691 |
* Copy the archive to the file the number of bytes specified. We have |
| 692 |
* to assume that we want to recover file holes as none of the archive |
| 693 |
* formats can record the location of file holes. |
| 694 |
*/ |
| 695 |
while (size > 0L) { |
| 696 |
cnt = bufend - bufpt; |
| 697 |
/* |
| 698 |
* if we get a read error, we do not want to skip, as we may |
| 699 |
* miss a header, so we do not set left, but if we get a write |
| 700 |
* error, we do want to skip over the unprocessed data. |
| 701 |
*/ |
| 702 |
if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) |
| 703 |
break; |
| 704 |
cnt = MIN(cnt, size); |
| 705 |
if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) { |
| 706 |
*left = size; |
| 707 |
break; |
| 708 |
} |
| 709 |
|
| 710 |
if (docrc) { |
| 711 |
/* |
| 712 |
* update the actual crc value |
| 713 |
*/ |
| 714 |
cnt = res; |
| 715 |
while (--cnt >= 0) |
| 716 |
crc += *bufpt++ & 0xff; |
| 717 |
} else |
| 718 |
bufpt += res; |
| 719 |
size -= res; |
| 720 |
} |
| 721 |
|
| 722 |
/* |
| 723 |
* if the last block has a file hole (all zero), we must make sure this |
| 724 |
* gets updated in the file. We force the last block of zeros to be |
| 725 |
* written. just closing with the file offset moved forward may not put |
| 726 |
* a hole at the end of the file. |
| 727 |
*/ |
| 728 |
if (isem && (arcn->sb.st_size > 0L)) |
| 729 |
file_flush(ofd, fnm, isem); |
| 730 |
|
| 731 |
/* |
| 732 |
* if we failed from archive read, we do not want to skip |
| 733 |
*/ |
| 734 |
if ((size > 0L) && (*left == 0L)) |
| 735 |
return(-1); |
| 736 |
|
| 737 |
/* |
| 738 |
* some formats record a crc on file data. If so, then we compare the |
| 739 |
* calculated crc to the crc stored in the archive |
| 740 |
*/ |
| 741 |
if (docrc && (size == 0L) && (arcn->crc != crc)) |
| 742 |
paxwarn(1,"Actual crc does not match expected crc %s",arcn->name); |
| 743 |
return(0); |
| 744 |
} |
| 745 |
|
| 746 |
/* |
| 747 |
* cp_file() |
| 748 |
* copy the contents of one file to another. used during -rw phase of pax |
| 749 |
* just as in rd_wrfile() we use a special write function to write the |
| 750 |
* destination file so we can properly copy files with holes. |
| 751 |
*/ |
| 752 |
|
| 753 |
void |
| 754 |
cp_file(ARCHD *arcn, int fd1, int fd2) |
| 755 |
{ |
| 756 |
int cnt; |
| 757 |
off_t cpcnt = 0L; |
| 758 |
int res = 0; |
| 759 |
char *fnm = arcn->name; |
| 760 |
int no_hole = 0; |
| 761 |
int isem = 1; |
| 762 |
int rem; |
| 763 |
int sz = MINFBSZ; |
| 764 |
struct stat sb; |
| 765 |
|
| 766 |
/* |
| 767 |
* check for holes in the source file. If none, we will use regular |
| 768 |
* write instead of file write. |
| 769 |
*/ |
| 770 |
if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size) |
| 771 |
++no_hole; |
| 772 |
|
| 773 |
/* |
| 774 |
* pass the blocksize of the file being written to the write routine, |
| 775 |
* if the size is zero, use the default MINFBSZ |
| 776 |
*/ |
| 777 |
if (fstat(fd2, &sb) == 0) { |
| 778 |
if (sb.st_blksize > 0) |
| 779 |
sz = sb.st_blksize; |
| 780 |
} else |
| 781 |
syswarn(0,errno,"Unable to obtain block size for file %s",fnm); |
| 782 |
rem = sz; |
| 783 |
|
| 784 |
/* |
| 785 |
* read the source file and copy to destination file until EOF |
| 786 |
*/ |
| 787 |
for (;;) { |
| 788 |
if ((cnt = read(fd1, buf, blksz)) <= 0) |
| 789 |
break; |
| 790 |
if (no_hole) |
| 791 |
res = write(fd2, buf, cnt); |
| 792 |
else |
| 793 |
res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm); |
| 794 |
if (res != cnt) |
| 795 |
break; |
| 796 |
cpcnt += cnt; |
| 797 |
} |
| 798 |
|
| 799 |
/* |
| 800 |
* check to make sure the copy is valid. |
| 801 |
*/ |
| 802 |
if (res < 0) |
| 803 |
syswarn(1, errno, "Failed write during copy of %s to %s", |
| 804 |
arcn->org_name, arcn->name); |
| 805 |
else if (cpcnt != arcn->sb.st_size) |
| 806 |
paxwarn(1, "File %s changed size during copy to %s", |
| 807 |
arcn->org_name, arcn->name); |
| 808 |
else if (fstat(fd1, &sb) < 0) |
| 809 |
syswarn(1, errno, "Failed stat of %s", arcn->org_name); |
| 810 |
else if (arcn->sb.st_mtime != sb.st_mtime) |
| 811 |
paxwarn(1, "File %s was modified during copy to %s", |
| 812 |
arcn->org_name, arcn->name); |
| 813 |
|
| 814 |
/* |
| 815 |
* if the last block has a file hole (all zero), we must make sure this |
| 816 |
* gets updated in the file. We force the last block of zeros to be |
| 817 |
* written. just closing with the file offset moved forward may not put |
| 818 |
* a hole at the end of the file. |
| 819 |
*/ |
| 820 |
if (!no_hole && isem && (arcn->sb.st_size > 0L)) |
| 821 |
file_flush(fd2, fnm, isem); |
| 822 |
return; |
| 823 |
} |
| 824 |
|
| 825 |
/* |
| 826 |
* buf_fill() |
| 827 |
* fill the read buffer with the next record (or what we can get) from |
| 828 |
* the archive volume. |
| 829 |
* Return: |
| 830 |
* Number of bytes of data in the read buffer, -1 for read error, and |
| 831 |
* 0 when finished (user specified termination in ar_next()). |
| 832 |
*/ |
| 833 |
|
| 834 |
int |
| 835 |
buf_fill(void) |
| 836 |
{ |
| 837 |
int cnt; |
| 838 |
static int fini = 0; |
| 839 |
|
| 840 |
if (fini) |
| 841 |
return(0); |
| 842 |
|
| 843 |
for (;;) { |
| 844 |
/* |
| 845 |
* try to fill the buffer. on error the next archive volume is |
| 846 |
* opened and we try again. |
| 847 |
*/ |
| 848 |
if ((cnt = ar_read(buf, blksz)) > 0) { |
| 849 |
bufpt = buf; |
| 850 |
bufend = buf + cnt; |
| 851 |
rdcnt += cnt; |
| 852 |
return(cnt); |
| 853 |
} |
| 854 |
|
| 855 |
/* |
| 856 |
* errors require resync, EOF goes to next archive |
| 857 |
*/ |
| 858 |
if (cnt < 0) |
| 859 |
break; |
| 860 |
if (ar_next() < 0) { |
| 861 |
fini = 1; |
| 862 |
return(0); |
| 863 |
} |
| 864 |
rdcnt = 0; |
| 865 |
} |
| 866 |
exit_val = 1; |
| 867 |
return(-1); |
| 868 |
} |
| 869 |
|
| 870 |
/* |
| 871 |
* buf_flush() |
| 872 |
* force the write buffer to the archive. We are passed the number of |
| 873 |
* bytes in the buffer at the point of the flush. When we change archives |
| 874 |
* the record size might change. (either larger or smaller). |
| 875 |
* Return: |
| 876 |
* 0 if all is ok, -1 when a write error occurs. |
| 877 |
*/ |
| 878 |
|
| 879 |
int |
| 880 |
buf_flush(int bufcnt) |
| 881 |
{ |
| 882 |
int cnt; |
| 883 |
int push = 0; |
| 884 |
int totcnt = 0; |
| 885 |
|
| 886 |
/* |
| 887 |
* if we have reached the user specified byte count for each archive |
| 888 |
* volume, prompt for the next volume. (The non-standard -R flag). |
| 889 |
* NOTE: If the wrlimit is smaller than wrcnt, we will always write |
| 890 |
* at least one record. We always round limit UP to next blocksize. |
| 891 |
*/ |
| 892 |
if ((wrlimit > 0) && (wrcnt > wrlimit)) { |
| 893 |
paxwarn(0, "User specified archive volume byte limit reached."); |
| 894 |
if (ar_next() < 0) { |
| 895 |
wrcnt = 0; |
| 896 |
exit_val = 1; |
| 897 |
return(-1); |
| 898 |
} |
| 899 |
wrcnt = 0; |
| 900 |
|
| 901 |
/* |
| 902 |
* The new archive volume might have changed the size of the |
| 903 |
* write blocksize. if so we figure out if we need to write |
| 904 |
* (one or more times), or if there is now free space left in |
| 905 |
* the buffer (it is no longer full). bufcnt has the number of |
| 906 |
* bytes in the buffer, (the blocksize, at the point we were |
| 907 |
* CALLED). Push has the amount of "extra" data in the buffer |
| 908 |
* if the block size has shrunk from a volume change. |
| 909 |
*/ |
| 910 |
bufend = buf + blksz; |
| 911 |
if (blksz > bufcnt) |
| 912 |
return(0); |
| 913 |
if (blksz < bufcnt) |
| 914 |
push = bufcnt - blksz; |
| 915 |
} |
| 916 |
|
| 917 |
/* |
| 918 |
* We have enough data to write at least one archive block |
| 919 |
*/ |
| 920 |
for (;;) { |
| 921 |
/* |
| 922 |
* write a block and check if it all went out ok |
| 923 |
*/ |
| 924 |
cnt = ar_write(buf, blksz); |
| 925 |
if (cnt == blksz) { |
| 926 |
/* |
| 927 |
* the write went ok |
| 928 |
*/ |
| 929 |
wrcnt += cnt; |
| 930 |
totcnt += cnt; |
| 931 |
if (push > 0) { |
| 932 |
/* we have extra data to push to the front. |
| 933 |
* check for more than 1 block of push, and if |
| 934 |
* so we loop back to write again |
| 935 |
*/ |
| 936 |
memcpy(buf, bufend, push); |
| 937 |
bufpt = buf + push; |
| 938 |
if (push >= blksz) { |
| 939 |
push -= blksz; |
| 940 |
continue; |
| 941 |
} |
| 942 |
} else |
| 943 |
bufpt = buf; |
| 944 |
return(totcnt); |
| 945 |
} else if (cnt > 0) { |
| 946 |
/* |
| 947 |
* Oh drat we got a partial write! |
| 948 |
* if format doesnt care about alignment let it go, |
| 949 |
* we warned the user in ar_write().... but this means |
| 950 |
* the last record on this volume violates pax spec.... |
| 951 |
*/ |
| 952 |
totcnt += cnt; |
| 953 |
wrcnt += cnt; |
| 954 |
bufpt = buf + cnt; |
| 955 |
cnt = bufcnt - cnt; |
| 956 |
memcpy(buf, bufpt, cnt); |
| 957 |
bufpt = buf + cnt; |
| 958 |
if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0)) |
| 959 |
return(totcnt); |
| 960 |
break; |
| 961 |
} |
| 962 |
|
| 963 |
/* |
| 964 |
* All done, go to next archive |
| 965 |
*/ |
| 966 |
wrcnt = 0; |
| 967 |
if (ar_next() < 0) |
| 968 |
break; |
| 969 |
|
| 970 |
/* |
| 971 |
* The new archive volume might also have changed the block |
| 972 |
* size. if so, figure out if we have too much or too little |
| 973 |
* data for using the new block size |
| 974 |
*/ |
| 975 |
bufend = buf + blksz; |
| 976 |
if (blksz > bufcnt) |
| 977 |
return(0); |
| 978 |
if (blksz < bufcnt) |
| 979 |
push = bufcnt - blksz; |
| 980 |
} |
| 981 |
|
| 982 |
/* |
| 983 |
* write failed, stop pax. we must not create a bad archive! |
| 984 |
*/ |
| 985 |
exit_val = 1; |
| 986 |
return(-1); |
| 987 |
} |