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