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