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