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