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