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