]> Dogcows Code - chaz/tar/blob - src/sparse.c
(tar_sparse_init): Fix recent bugfixes: Initialize dumped_size to 0.
[chaz/tar] / src / sparse.c
1 /* Functions for dealing with sparse files
2
3 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19 #include <system.h>
20 #include <inttostr.h>
21 #include <quotearg.h>
22 #include "common.h"
23
24 struct tar_sparse_file;
25
26 enum sparse_scan_state
27 {
28 scan_begin,
29 scan_block,
30 scan_end
31 };
32
33 struct tar_sparse_optab
34 {
35 bool (*init) (struct tar_sparse_file *);
36 bool (*done) (struct tar_sparse_file *);
37 bool (*sparse_member_p) (struct tar_sparse_file *);
38 bool (*dump_header) (struct tar_sparse_file *);
39 bool (*fixup_header) (struct tar_sparse_file *);
40 bool (*decode_header) (struct tar_sparse_file *);
41 bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,
42 void *);
43 bool (*dump_region) (struct tar_sparse_file *, size_t);
44 bool (*extract_region) (struct tar_sparse_file *, size_t);
45 };
46
47 struct tar_sparse_file
48 {
49 int fd; /* File descriptor */
50 bool seekable; /* Is fd seekable? */
51 off_t offset; /* Current offset in fd if seekable==false.
52 Otherwise unused */
53 off_t dumped_size; /* Number of bytes actually written
54 to the archive */
55 struct tar_stat_info *stat_info; /* Information about the file */
56 struct tar_sparse_optab const *optab;
57 void *closure; /* Any additional data optab calls might
58 require */
59 };
60
61 /* Dump zeros to file->fd until offset is reached. It is used instead of
62 lseek if the output file is not seekable */
63 static bool
64 dump_zeros (struct tar_sparse_file *file, off_t offset)
65 {
66 static char const zero_buf[BLOCKSIZE];
67
68 if (offset < file->offset)
69 {
70 errno = EINVAL;
71 return false;
72 }
73
74 while (file->offset < offset)
75 {
76 size_t size = (BLOCKSIZE < offset - file->offset
77 ? BLOCKSIZE
78 : offset - file->offset);
79 ssize_t wrbytes;
80
81 wrbytes = write (file->fd, zero_buf, size);
82 if (wrbytes <= 0)
83 {
84 if (wrbytes == 0)
85 errno = EINVAL;
86 return false;
87 }
88 file->offset += wrbytes;
89 }
90
91 return true;
92 }
93
94 static bool
95 tar_sparse_member_p (struct tar_sparse_file *file)
96 {
97 if (file->optab->sparse_member_p)
98 return file->optab->sparse_member_p (file);
99 return false;
100 }
101
102 static bool
103 tar_sparse_init (struct tar_sparse_file *file)
104 {
105 file->dumped_size = 0;
106 if (file->optab->init)
107 return file->optab->init (file);
108 return true;
109 }
110
111 static bool
112 tar_sparse_done (struct tar_sparse_file *file)
113 {
114 if (file->optab->done)
115 return file->optab->done (file);
116 return true;
117 }
118
119 static bool
120 tar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,
121 void *block)
122 {
123 if (file->optab->scan_block)
124 return file->optab->scan_block (file, state, block);
125 return true;
126 }
127
128 static bool
129 tar_sparse_dump_region (struct tar_sparse_file *file, size_t i)
130 {
131 if (file->optab->dump_region)
132 return file->optab->dump_region (file, i);
133 return false;
134 }
135
136 static bool
137 tar_sparse_extract_region (struct tar_sparse_file *file, size_t i)
138 {
139 if (file->optab->extract_region)
140 return file->optab->extract_region (file, i);
141 return false;
142 }
143
144 static bool
145 tar_sparse_dump_header (struct tar_sparse_file *file)
146 {
147 if (file->optab->dump_header)
148 return file->optab->dump_header (file);
149 return false;
150 }
151
152 static bool
153 tar_sparse_decode_header (struct tar_sparse_file *file)
154 {
155 if (file->optab->decode_header)
156 return file->optab->decode_header (file);
157 return true;
158 }
159
160 static bool
161 tar_sparse_fixup_header (struct tar_sparse_file *file)
162 {
163 if (file->optab->fixup_header)
164 return file->optab->fixup_header (file);
165 return true;
166 }
167
168 \f
169 static bool
170 lseek_or_error (struct tar_sparse_file *file, off_t offset)
171 {
172 if (file->seekable
173 ? lseek (file->fd, offset, SEEK_SET) < 0
174 : ! dump_zeros (file, offset))
175 {
176 seek_diag_details (file->stat_info->orig_file_name, offset);
177 return false;
178 }
179 return true;
180 }
181
182 /* Takes a blockful of data and basically cruises through it to see if
183 it's made *entirely* of zeros, returning a 0 the instant it finds
184 something that is a nonzero, i.e., useful data. */
185 static bool
186 zero_block_p (char const *buffer, size_t size)
187 {
188 while (size--)
189 if (*buffer++)
190 return false;
191 return true;
192 }
193
194 static void
195 sparse_add_map (struct tar_stat_info *st, struct sp_array const *sp)
196 {
197 struct sp_array *sparse_map = st->sparse_map;
198 size_t avail = st->sparse_map_avail;
199 if (avail == st->sparse_map_size)
200 st->sparse_map = sparse_map =
201 x2nrealloc (sparse_map, &st->sparse_map_size, sizeof *sparse_map);
202 sparse_map[avail] = *sp;
203 st->sparse_map_avail = avail + 1;
204 }
205
206 /* Scan the sparse file and create its map */
207 static bool
208 sparse_scan_file (struct tar_sparse_file *file)
209 {
210 struct tar_stat_info *st = file->stat_info;
211 int fd = file->fd;
212 char buffer[BLOCKSIZE];
213 size_t count;
214 off_t offset = 0;
215 struct sp_array sp = {0, 0};
216
217 if (!lseek_or_error (file, 0))
218 return false;
219
220 if (!tar_sparse_scan (file, scan_begin, NULL))
221 return false;
222
223 while ((count = safe_read (fd, buffer, sizeof buffer)) != 0
224 && count != SAFE_READ_ERROR)
225 {
226 /* Analyze the block. */
227 if (zero_block_p (buffer, count))
228 {
229 if (sp.numbytes)
230 {
231 sparse_add_map (st, &sp);
232 sp.numbytes = 0;
233 if (!tar_sparse_scan (file, scan_block, NULL))
234 return false;
235 }
236 }
237 else
238 {
239 if (sp.numbytes == 0)
240 sp.offset = offset;
241 sp.numbytes += count;
242 st->archive_file_size += count;
243 if (!tar_sparse_scan (file, scan_block, buffer))
244 return false;
245 }
246
247 offset += count;
248 }
249
250 if (sp.numbytes == 0)
251 sp.offset = offset;
252
253 sparse_add_map (st, &sp);
254 st->archive_file_size += count;
255 return tar_sparse_scan (file, scan_end, NULL);
256 }
257
258 static struct tar_sparse_optab const oldgnu_optab;
259 static struct tar_sparse_optab const star_optab;
260 static struct tar_sparse_optab const pax_optab;
261
262 static bool
263 sparse_select_optab (struct tar_sparse_file *file)
264 {
265 switch (current_format == DEFAULT_FORMAT ? archive_format : current_format)
266 {
267 case V7_FORMAT:
268 case USTAR_FORMAT:
269 return false;
270
271 case OLDGNU_FORMAT:
272 case GNU_FORMAT: /*FIXME: This one should disappear? */
273 file->optab = &oldgnu_optab;
274 break;
275
276 case POSIX_FORMAT:
277 file->optab = &pax_optab;
278 break;
279
280 case STAR_FORMAT:
281 file->optab = &star_optab;
282 break;
283
284 default:
285 return false;
286 }
287 return true;
288 }
289
290 static bool
291 sparse_dump_region (struct tar_sparse_file *file, size_t i)
292 {
293 union block *blk;
294 off_t bytes_left = file->stat_info->sparse_map[i].numbytes;
295
296 if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
297 return false;
298
299 while (bytes_left > 0)
300 {
301 size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
302 size_t bytes_read;
303
304 blk = find_next_block ();
305 bytes_read = safe_read (file->fd, blk->buffer, bufsize);
306 if (bytes_read == SAFE_READ_ERROR)
307 {
308 read_diag_details (file->stat_info->orig_file_name,
309 (file->stat_info->sparse_map[i].offset
310 + file->stat_info->sparse_map[i].numbytes
311 - bytes_left),
312 bufsize);
313 return false;
314 }
315
316 memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
317 bytes_left -= bytes_read;
318 file->dumped_size += bytes_read;
319 set_next_block_after (blk);
320 }
321
322 return true;
323 }
324
325 static bool
326 sparse_extract_region (struct tar_sparse_file *file, size_t i)
327 {
328 size_t write_size;
329
330 if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
331 return false;
332
333 write_size = file->stat_info->sparse_map[i].numbytes;
334
335 if (write_size == 0)
336 {
337 /* Last block of the file is a hole */
338 if (file->seekable && sys_truncate (file->fd))
339 truncate_warn (file->stat_info->orig_file_name);
340 }
341 else while (write_size > 0)
342 {
343 size_t count;
344 size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;
345 union block *blk = find_next_block ();
346 if (!blk)
347 {
348 ERROR ((0, 0, _("Unexpected EOF in archive")));
349 return false;
350 }
351 set_next_block_after (blk);
352 count = full_write (file->fd, blk->buffer, wrbytes);
353 write_size -= count;
354 file->dumped_size += count;
355 file->offset += count;
356 if (count != wrbytes)
357 {
358 write_error_details (file->stat_info->orig_file_name,
359 count, wrbytes);
360 return false;
361 }
362 }
363 return true;
364 }
365
366 \f
367
368 /* Interface functions */
369 enum dump_status
370 sparse_dump_file (int fd, struct tar_stat_info *st)
371 {
372 bool rc;
373 struct tar_sparse_file file = { 0, };
374
375 file.stat_info = st;
376 file.fd = fd;
377 file.seekable = true; /* File *must* be seekable for dump to work */
378
379 if (!sparse_select_optab (&file)
380 || !tar_sparse_init (&file))
381 return dump_status_not_implemented;
382
383 rc = sparse_scan_file (&file);
384 if (rc && file.optab->dump_region)
385 {
386 tar_sparse_dump_header (&file);
387
388 if (fd >= 0)
389 {
390 size_t i;
391
392 for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
393 rc = tar_sparse_dump_region (&file, i);
394 }
395 }
396
397 pad_archive (file.stat_info->archive_file_size - file.dumped_size);
398 return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
399 }
400
401 /* Returns true if the file represented by stat is a sparse one */
402 bool
403 sparse_file_p (struct tar_stat_info *st)
404 {
405 return (ST_NBLOCKS (st->stat)
406 < (st->stat.st_size / ST_NBLOCKSIZE
407 + (st->stat.st_size % ST_NBLOCKSIZE != 0)));
408 }
409
410 bool
411 sparse_member_p (struct tar_stat_info *st)
412 {
413 struct tar_sparse_file file;
414
415 if (!sparse_select_optab (&file))
416 return false;
417 file.stat_info = st;
418 return tar_sparse_member_p (&file);
419 }
420
421 bool
422 sparse_fixup_header (struct tar_stat_info *st)
423 {
424 struct tar_sparse_file file;
425
426 if (!sparse_select_optab (&file))
427 return false;
428 file.stat_info = st;
429 return tar_sparse_fixup_header (&file);
430 }
431
432 enum dump_status
433 sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
434 {
435 bool rc = true;
436 struct tar_sparse_file file;
437 size_t i;
438
439 file.stat_info = st;
440 file.fd = fd;
441 file.seekable = lseek (fd, 0, SEEK_SET) == 0;
442 file.offset = 0;
443
444 if (!sparse_select_optab (&file)
445 || !tar_sparse_init (&file))
446 return dump_status_not_implemented;
447
448 rc = tar_sparse_decode_header (&file);
449 for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
450 rc = tar_sparse_extract_region (&file, i);
451 *size = file.stat_info->archive_file_size - file.dumped_size;
452 return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
453 }
454
455 enum dump_status
456 sparse_skip_file (struct tar_stat_info *st)
457 {
458 bool rc = true;
459 struct tar_sparse_file file;
460
461 file.stat_info = st;
462 file.fd = -1;
463
464 if (!sparse_select_optab (&file)
465 || !tar_sparse_init (&file))
466 return dump_status_not_implemented;
467
468 rc = tar_sparse_decode_header (&file);
469 skip_file (file.stat_info->archive_file_size);
470 return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
471 }
472
473 \f
474 static bool
475 check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
476 {
477 if (!lseek_or_error (file, beg))
478 return false;
479
480 while (beg < end)
481 {
482 size_t bytes_read;
483 size_t rdsize = BLOCKSIZE < end - beg ? BLOCKSIZE : end - beg;
484 char diff_buffer[BLOCKSIZE];
485
486 bytes_read = safe_read (file->fd, diff_buffer, rdsize);
487 if (bytes_read == SAFE_READ_ERROR)
488 {
489 read_diag_details (file->stat_info->orig_file_name,
490 beg,
491 rdsize);
492 return false;
493 }
494 if (!zero_block_p (diff_buffer, bytes_read))
495 {
496 char begbuf[INT_BUFSIZE_BOUND (off_t)];
497 report_difference (file->stat_info,
498 _("File fragment at %s is not a hole"),
499 offtostr (beg, begbuf));
500 return false;
501 }
502
503 beg += bytes_read;
504 }
505 return true;
506 }
507
508 static bool
509 check_data_region (struct tar_sparse_file *file, size_t i)
510 {
511 size_t size_left;
512
513 if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
514 return false;
515 size_left = file->stat_info->sparse_map[i].numbytes;
516 while (size_left > 0)
517 {
518 size_t bytes_read;
519 size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left;
520 char diff_buffer[BLOCKSIZE];
521
522 union block *blk = find_next_block ();
523 if (!blk)
524 {
525 ERROR ((0, 0, _("Unexpected EOF in archive")));
526 return false;
527 }
528 set_next_block_after (blk);
529 bytes_read = safe_read (file->fd, diff_buffer, rdsize);
530 if (bytes_read == SAFE_READ_ERROR)
531 {
532 read_diag_details (file->stat_info->orig_file_name,
533 (file->stat_info->sparse_map[i].offset
534 + file->stat_info->sparse_map[i].numbytes
535 - size_left),
536 rdsize);
537 return false;
538 }
539 file->dumped_size += bytes_read;
540 size_left -= bytes_read;
541 if (memcmp (blk->buffer, diff_buffer, rdsize))
542 {
543 report_difference (file->stat_info, _("Contents differ"));
544 return false;
545 }
546 }
547 return true;
548 }
549
550 bool
551 sparse_diff_file (int fd, struct tar_stat_info *st)
552 {
553 bool rc = true;
554 struct tar_sparse_file file;
555 size_t i;
556 off_t offset = 0;
557
558 file.stat_info = st;
559 file.fd = fd;
560
561 if (!sparse_select_optab (&file)
562 || !tar_sparse_init (&file))
563 return dump_status_not_implemented;
564
565 rc = tar_sparse_decode_header (&file);
566 for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
567 {
568 rc = check_sparse_region (&file,
569 offset, file.stat_info->sparse_map[i].offset)
570 && check_data_region (&file, i);
571 offset = file.stat_info->sparse_map[i].offset
572 + file.stat_info->sparse_map[i].numbytes;
573 }
574
575 if (!rc)
576 skip_file (file.stat_info->archive_file_size - file.dumped_size);
577
578 tar_sparse_done (&file);
579 return rc;
580 }
581
582 \f
583 /* Old GNU Format. The sparse file information is stored in the
584 oldgnu_header in the following manner:
585
586 The header is marked with type 'S'. Its `size' field contains
587 the cumulative size of all non-empty blocks of the file. The
588 actual file size is stored in `realsize' member of oldgnu_header.
589
590 The map of the file is stored in a list of `struct sparse'.
591 Each struct contains offset to the block of data and its
592 size (both as octal numbers). The first file header contains
593 at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
594 contains more structs, then the field `isextended' of the main
595 header is set to 1 (binary) and the `struct sparse_header'
596 header follows, containing at most 21 following structs
597 (SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
598 field of the extended header is set and next next extension header
599 follows, etc... */
600
601 enum oldgnu_add_status
602 {
603 add_ok,
604 add_finish,
605 add_fail
606 };
607
608 static bool
609 oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
610 {
611 return current_header->header.typeflag == GNUTYPE_SPARSE;
612 }
613
614 /* Add a sparse item to the sparse file and its obstack */
615 static enum oldgnu_add_status
616 oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
617 {
618 struct sp_array sp;
619
620 if (s->numbytes[0] == '\0')
621 return add_finish;
622 sp.offset = OFF_FROM_HEADER (s->offset);
623 sp.numbytes = SIZE_FROM_HEADER (s->numbytes);
624 if (sp.offset < 0
625 || file->stat_info->stat.st_size < sp.offset + sp.numbytes
626 || file->stat_info->archive_file_size < 0)
627 return add_fail;
628
629 sparse_add_map (file->stat_info, &sp);
630 return add_ok;
631 }
632
633 static bool
634 oldgnu_fixup_header (struct tar_sparse_file *file)
635 {
636 /* NOTE! st_size was initialized from the header
637 which actually contains archived size. The following fixes it */
638 file->stat_info->archive_file_size = file->stat_info->stat.st_size;
639 file->stat_info->stat.st_size =
640 OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
641 return true;
642 }
643
644 /* Convert old GNU format sparse data to internal representation */
645 static bool
646 oldgnu_get_sparse_info (struct tar_sparse_file *file)
647 {
648 size_t i;
649 union block *h = current_header;
650 int ext_p;
651 enum oldgnu_add_status rc;
652
653 file->stat_info->sparse_map_avail = 0;
654 for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
655 {
656 rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
657 if (rc != add_ok)
658 break;
659 }
660
661 for (ext_p = h->oldgnu_header.isextended;
662 rc == add_ok && ext_p; ext_p = h->sparse_header.isextended)
663 {
664 h = find_next_block ();
665 if (!h)
666 {
667 ERROR ((0, 0, _("Unexpected EOF in archive")));
668 return false;
669 }
670 set_next_block_after (h);
671 for (i = 0; i < SPARSES_IN_SPARSE_HEADER && rc == add_ok; i++)
672 rc = oldgnu_add_sparse (file, &h->sparse_header.sp[i]);
673 }
674
675 if (rc == add_fail)
676 {
677 ERROR ((0, 0, _("%s: invalid sparse archive member"),
678 file->stat_info->orig_file_name));
679 return false;
680 }
681 return true;
682 }
683
684 static void
685 oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
686 struct sparse *sp, size_t sparse_size)
687 {
688 for (; *pindex < file->stat_info->sparse_map_avail
689 && sparse_size > 0; sparse_size--, sp++, ++*pindex)
690 {
691 OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
692 sp->offset);
693 SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
694 sp->numbytes);
695 }
696 }
697
698 static bool
699 oldgnu_dump_header (struct tar_sparse_file *file)
700 {
701 off_t block_ordinal = current_block_ordinal ();
702 union block *blk;
703 size_t i;
704
705 blk = start_header (file->stat_info);
706 blk->header.typeflag = GNUTYPE_SPARSE;
707 if (file->stat_info->sparse_map_avail > SPARSES_IN_OLDGNU_HEADER)
708 blk->oldgnu_header.isextended = 1;
709
710 /* Store the real file size */
711 OFF_TO_CHARS (file->stat_info->stat.st_size, blk->oldgnu_header.realsize);
712 /* Store the effective (shrunken) file size */
713 OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
714
715 i = 0;
716 oldgnu_store_sparse_info (file, &i,
717 blk->oldgnu_header.sp,
718 SPARSES_IN_OLDGNU_HEADER);
719 blk->oldgnu_header.isextended = i < file->stat_info->sparse_map_avail;
720 finish_header (file->stat_info, blk, block_ordinal);
721
722 while (i < file->stat_info->sparse_map_avail)
723 {
724 blk = find_next_block ();
725 memset (blk->buffer, 0, BLOCKSIZE);
726 oldgnu_store_sparse_info (file, &i,
727 blk->sparse_header.sp,
728 SPARSES_IN_SPARSE_HEADER);
729 set_next_block_after (blk);
730 if (i < file->stat_info->sparse_map_avail)
731 blk->sparse_header.isextended = 1;
732 else
733 break;
734 }
735 return true;
736 }
737
738 static struct tar_sparse_optab const oldgnu_optab = {
739 NULL, /* No init function */
740 NULL, /* No done function */
741 oldgnu_sparse_member_p,
742 oldgnu_dump_header,
743 oldgnu_fixup_header,
744 oldgnu_get_sparse_info,
745 NULL, /* No scan_block function */
746 sparse_dump_region,
747 sparse_extract_region,
748 };
749
750 \f
751 /* Star */
752
753 static bool
754 star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
755 {
756 return current_header->header.typeflag == GNUTYPE_SPARSE;
757 }
758
759 static bool
760 star_fixup_header (struct tar_sparse_file *file)
761 {
762 /* NOTE! st_size was initialized from the header
763 which actually contains archived size. The following fixes it */
764 file->stat_info->archive_file_size = file->stat_info->stat.st_size;
765 file->stat_info->stat.st_size =
766 OFF_FROM_HEADER (current_header->star_in_header.realsize);
767 return true;
768 }
769
770 /* Convert STAR format sparse data to internal representation */
771 static bool
772 star_get_sparse_info (struct tar_sparse_file *file)
773 {
774 size_t i;
775 union block *h = current_header;
776 int ext_p;
777 enum oldgnu_add_status rc = add_ok;
778
779 file->stat_info->sparse_map_avail = 0;
780
781 if (h->star_in_header.prefix[0] == '\0'
782 && h->star_in_header.sp[0].offset[10] != '\0')
783 {
784 /* Old star format */
785 for (i = 0; i < SPARSES_IN_STAR_HEADER; i++)
786 {
787 rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]);
788 if (rc != add_ok)
789 break;
790 }
791 ext_p = h->star_in_header.isextended;
792 }
793 else
794 ext_p = 1;
795
796 for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended)
797 {
798 h = find_next_block ();
799 if (!h)
800 {
801 ERROR ((0, 0, _("Unexpected EOF in archive")));
802 return false;
803 }
804 set_next_block_after (h);
805 for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
806 rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
807 }
808
809 if (rc == add_fail)
810 {
811 ERROR ((0, 0, _("%s: invalid sparse archive member"),
812 file->stat_info->orig_file_name));
813 return false;
814 }
815 return true;
816 }
817
818
819 static struct tar_sparse_optab const star_optab = {
820 NULL, /* No init function */
821 NULL, /* No done function */
822 star_sparse_member_p,
823 NULL,
824 star_fixup_header,
825 star_get_sparse_info,
826 NULL, /* No scan_block function */
827 NULL, /* No dump region function */
828 sparse_extract_region,
829 };
830
831 \f
832 /* GNU PAX sparse file format. The sparse file map is stored in
833 x header:
834
835 GNU.sparse.size Real size of the stored file
836 GNU.sparse.numblocks Number of blocks in the sparse map
837 repeat numblocks time
838 GNU.sparse.offset Offset of the next data block
839 GNU.sparse.numbytes Size of the next data block
840 end repeat
841 */
842
843 static bool
844 pax_sparse_member_p (struct tar_sparse_file *file)
845 {
846 return file->stat_info->archive_file_size != file->stat_info->stat.st_size;
847 }
848
849 static bool
850 pax_dump_header (struct tar_sparse_file *file)
851 {
852 off_t block_ordinal = current_block_ordinal ();
853 union block *blk;
854 size_t i;
855
856 /* Store the real file size */
857 xheader_store ("GNU.sparse.size", file->stat_info, NULL);
858 xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
859 for (i = 0; i < file->stat_info->sparse_map_avail; i++)
860 {
861 xheader_store ("GNU.sparse.offset", file->stat_info, &i);
862 xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
863 }
864
865 blk = start_header (file->stat_info);
866 /* Store the effective (shrunken) file size */
867 OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
868 finish_header (file->stat_info, blk, block_ordinal);
869 return true;
870 }
871
872 static struct tar_sparse_optab const pax_optab = {
873 NULL, /* No init function */
874 NULL, /* No done function */
875 pax_sparse_member_p,
876 pax_dump_header,
877 NULL, /* No decode_header function */
878 NULL, /* No fixup_header function */
879 NULL, /* No scan_block function */
880 sparse_dump_region,
881 sparse_extract_region,
882 };
This page took 0.077173 seconds and 5 git commands to generate.