1 /* Functions for dealing with sparse files
3 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
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
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.
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. */
24 struct tar_sparse_file
;
25 static bool sparse_select_optab (struct tar_sparse_file
*file
);
27 enum sparse_scan_state
34 struct tar_sparse_optab
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
,
44 bool (*dump_region
) (struct tar_sparse_file
*, size_t);
45 bool (*extract_region
) (struct tar_sparse_file
*, size_t);
48 struct tar_sparse_file
50 int fd
; /* File descriptor */
51 bool seekable
; /* Is fd seekable? */
52 off_t offset
; /* Current offset in fd if seekable==false.
54 off_t dumped_size
; /* Number of bytes actually written
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
62 /* Dump zeros to file->fd until offset is reached. It is used instead of
63 lseek if the output file is not seekable */
65 dump_zeros (struct tar_sparse_file
*file
, off_t offset
)
67 static char const zero_buf
[BLOCKSIZE
];
69 if (offset
< file
->offset
)
75 while (file
->offset
< offset
)
77 size_t size
= (BLOCKSIZE
< offset
- file
->offset
79 : offset
- file
->offset
);
82 wrbytes
= write (file
->fd
, zero_buf
, size
);
89 file
->offset
+= wrbytes
;
96 tar_sparse_member_p (struct tar_sparse_file
*file
)
98 if (file
->optab
->sparse_member_p
)
99 return file
->optab
->sparse_member_p (file
);
104 tar_sparse_init (struct tar_sparse_file
*file
)
106 memset (file
, 0, sizeof *file
);
108 if (!sparse_select_optab (file
))
111 if (file
->optab
->init
)
112 return file
->optab
->init (file
);
118 tar_sparse_done (struct tar_sparse_file
*file
)
120 if (file
->optab
->done
)
121 return file
->optab
->done (file
);
126 tar_sparse_scan (struct tar_sparse_file
*file
, enum sparse_scan_state state
,
129 if (file
->optab
->scan_block
)
130 return file
->optab
->scan_block (file
, state
, block
);
135 tar_sparse_dump_region (struct tar_sparse_file
*file
, size_t i
)
137 if (file
->optab
->dump_region
)
138 return file
->optab
->dump_region (file
, i
);
143 tar_sparse_extract_region (struct tar_sparse_file
*file
, size_t i
)
145 if (file
->optab
->extract_region
)
146 return file
->optab
->extract_region (file
, i
);
151 tar_sparse_dump_header (struct tar_sparse_file
*file
)
153 if (file
->optab
->dump_header
)
154 return file
->optab
->dump_header (file
);
159 tar_sparse_decode_header (struct tar_sparse_file
*file
)
161 if (file
->optab
->decode_header
)
162 return file
->optab
->decode_header (file
);
167 tar_sparse_fixup_header (struct tar_sparse_file
*file
)
169 if (file
->optab
->fixup_header
)
170 return file
->optab
->fixup_header (file
);
176 lseek_or_error (struct tar_sparse_file
*file
, off_t offset
)
179 ? lseek (file
->fd
, offset
, SEEK_SET
) < 0
180 : ! dump_zeros (file
, offset
))
182 seek_diag_details (file
->stat_info
->orig_file_name
, offset
);
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. */
192 zero_block_p (char const *buffer
, size_t size
)
201 sparse_add_map (struct tar_stat_info
*st
, struct sp_array
const *sp
)
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;
212 /* Scan the sparse file and create its map */
214 sparse_scan_file (struct tar_sparse_file
*file
)
216 struct tar_stat_info
*st
= file
->stat_info
;
218 char buffer
[BLOCKSIZE
];
221 struct sp_array sp
= {0, 0};
223 if (!lseek_or_error (file
, 0))
226 st
->archive_file_size
= 0;
228 if (!tar_sparse_scan (file
, scan_begin
, NULL
))
231 while ((count
= safe_read (fd
, buffer
, sizeof buffer
)) != 0
232 && count
!= SAFE_READ_ERROR
)
234 /* Analyze the block. */
235 if (zero_block_p (buffer
, count
))
239 sparse_add_map (st
, &sp
);
241 if (!tar_sparse_scan (file
, scan_block
, NULL
))
247 if (sp
.numbytes
== 0)
249 sp
.numbytes
+= count
;
250 st
->archive_file_size
+= count
;
251 if (!tar_sparse_scan (file
, scan_block
, buffer
))
258 if (sp
.numbytes
== 0)
261 sparse_add_map (st
, &sp
);
262 st
->archive_file_size
+= count
;
263 return tar_sparse_scan (file
, scan_end
, NULL
);
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
;
271 sparse_select_optab (struct tar_sparse_file
*file
)
273 switch (current_format
== DEFAULT_FORMAT
? archive_format
: current_format
)
280 case GNU_FORMAT
: /*FIXME: This one should disappear? */
281 file
->optab
= &oldgnu_optab
;
285 file
->optab
= &pax_optab
;
289 file
->optab
= &star_optab
;
299 sparse_dump_region (struct tar_sparse_file
*file
, size_t i
)
302 off_t bytes_left
= file
->stat_info
->sparse_map
[i
].numbytes
;
304 if (!lseek_or_error (file
, file
->stat_info
->sparse_map
[i
].offset
))
307 while (bytes_left
> 0)
309 size_t bufsize
= (bytes_left
> BLOCKSIZE
) ? BLOCKSIZE
: bytes_left
;
312 blk
= find_next_block ();
313 bytes_read
= safe_read (file
->fd
, blk
->buffer
, bufsize
);
314 if (bytes_read
== SAFE_READ_ERROR
)
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
324 memset (blk
->buffer
+ bytes_read
, 0, BLOCKSIZE
- bytes_read
);
325 bytes_left
-= bytes_read
;
326 file
->dumped_size
+= bytes_read
;
327 mv_size_left (file
->stat_info
->archive_file_size
- file
->dumped_size
);
328 set_next_block_after (blk
);
335 sparse_extract_region (struct tar_sparse_file
*file
, size_t i
)
339 if (!lseek_or_error (file
, file
->stat_info
->sparse_map
[i
].offset
))
342 write_size
= file
->stat_info
->sparse_map
[i
].numbytes
;
346 /* Last block of the file is a hole */
347 if (file
->seekable
&& sys_truncate (file
->fd
))
348 truncate_warn (file
->stat_info
->orig_file_name
);
350 else while (write_size
> 0)
353 size_t wrbytes
= (write_size
> BLOCKSIZE
) ? BLOCKSIZE
: write_size
;
354 union block
*blk
= find_next_block ();
357 ERROR ((0, 0, _("Unexpected EOF in archive")));
360 set_next_block_after (blk
);
361 count
= full_write (file
->fd
, blk
->buffer
, wrbytes
);
363 file
->dumped_size
+= count
;
364 mv_size_left (file
->stat_info
->archive_file_size
- file
->dumped_size
);
365 file
->offset
+= count
;
366 if (count
!= wrbytes
)
368 write_error_details (file
->stat_info
->orig_file_name
,
378 /* Interface functions */
380 sparse_dump_file (int fd
, struct tar_stat_info
*st
)
383 struct tar_sparse_file file
;
385 if (!tar_sparse_init (&file
))
386 return dump_status_not_implemented
;
390 file
.seekable
= true; /* File *must* be seekable for dump to work */
392 rc
= sparse_scan_file (&file
);
393 if (rc
&& file
.optab
->dump_region
)
395 tar_sparse_dump_header (&file
);
401 mv_begin (file
.stat_info
);
402 for (i
= 0; rc
&& i
< file
.stat_info
->sparse_map_avail
; i
++)
403 rc
= tar_sparse_dump_region (&file
, i
);
408 pad_archive (file
.stat_info
->archive_file_size
- file
.dumped_size
);
409 return (tar_sparse_done (&file
) && rc
) ? dump_status_ok
: dump_status_short
;
412 /* Returns true if the file represented by stat is a sparse one */
414 sparse_file_p (struct tar_stat_info
*st
)
416 return (ST_NBLOCKS (st
->stat
)
417 < (st
->stat
.st_size
/ ST_NBLOCKSIZE
418 + (st
->stat
.st_size
% ST_NBLOCKSIZE
!= 0)));
422 sparse_member_p (struct tar_stat_info
*st
)
424 struct tar_sparse_file file
;
426 if (!tar_sparse_init (&file
))
429 return tar_sparse_member_p (&file
);
433 sparse_fixup_header (struct tar_stat_info
*st
)
435 struct tar_sparse_file file
;
437 if (!tar_sparse_init (&file
))
440 return tar_sparse_fixup_header (&file
);
444 sparse_extract_file (int fd
, struct tar_stat_info
*st
, off_t
*size
)
447 struct tar_sparse_file file
;
450 if (!tar_sparse_init (&file
))
451 return dump_status_not_implemented
;
455 file
.seekable
= lseek (fd
, 0, SEEK_SET
) == 0;
458 rc
= tar_sparse_decode_header (&file
);
459 for (i
= 0; rc
&& i
< file
.stat_info
->sparse_map_avail
; i
++)
460 rc
= tar_sparse_extract_region (&file
, i
);
461 *size
= file
.stat_info
->archive_file_size
- file
.dumped_size
;
462 return (tar_sparse_done (&file
) && rc
) ? dump_status_ok
: dump_status_short
;
466 sparse_skip_file (struct tar_stat_info
*st
)
469 struct tar_sparse_file file
;
471 if (!tar_sparse_init (&file
))
472 return dump_status_not_implemented
;
477 rc
= tar_sparse_decode_header (&file
);
478 skip_file (file
.stat_info
->archive_file_size
);
479 return (tar_sparse_done (&file
) && rc
) ? dump_status_ok
: dump_status_short
;
484 check_sparse_region (struct tar_sparse_file
*file
, off_t beg
, off_t end
)
486 if (!lseek_or_error (file
, beg
))
492 size_t rdsize
= BLOCKSIZE
< end
- beg
? BLOCKSIZE
: end
- beg
;
493 char diff_buffer
[BLOCKSIZE
];
495 bytes_read
= safe_read (file
->fd
, diff_buffer
, rdsize
);
496 if (bytes_read
== SAFE_READ_ERROR
)
498 read_diag_details (file
->stat_info
->orig_file_name
,
503 if (!zero_block_p (diff_buffer
, bytes_read
))
505 char begbuf
[INT_BUFSIZE_BOUND (off_t
)];
506 report_difference (file
->stat_info
,
507 _("File fragment at %s is not a hole"),
508 offtostr (beg
, begbuf
));
518 check_data_region (struct tar_sparse_file
*file
, size_t i
)
522 if (!lseek_or_error (file
, file
->stat_info
->sparse_map
[i
].offset
))
524 size_left
= file
->stat_info
->sparse_map
[i
].numbytes
;
525 mv_size_left (file
->stat_info
->archive_file_size
- file
->dumped_size
);
527 while (size_left
> 0)
530 size_t rdsize
= (size_left
> BLOCKSIZE
) ? BLOCKSIZE
: size_left
;
531 char diff_buffer
[BLOCKSIZE
];
533 union block
*blk
= find_next_block ();
536 ERROR ((0, 0, _("Unexpected EOF in archive")));
539 set_next_block_after (blk
);
540 bytes_read
= safe_read (file
->fd
, diff_buffer
, rdsize
);
541 if (bytes_read
== SAFE_READ_ERROR
)
543 read_diag_details (file
->stat_info
->orig_file_name
,
544 (file
->stat_info
->sparse_map
[i
].offset
545 + file
->stat_info
->sparse_map
[i
].numbytes
550 file
->dumped_size
+= bytes_read
;
551 size_left
-= bytes_read
;
552 mv_size_left (file
->stat_info
->archive_file_size
- file
->dumped_size
);
553 if (memcmp (blk
->buffer
, diff_buffer
, rdsize
))
555 report_difference (file
->stat_info
, _("Contents differ"));
563 sparse_diff_file (int fd
, struct tar_stat_info
*st
)
566 struct tar_sparse_file file
;
570 if (!tar_sparse_init (&file
))
571 return dump_status_not_implemented
;
575 file
.seekable
= true; /* File *must* be seekable for compare to work */
577 rc
= tar_sparse_decode_header (&file
);
579 for (i
= 0; rc
&& i
< file
.stat_info
->sparse_map_avail
; i
++)
581 rc
= check_sparse_region (&file
,
582 offset
, file
.stat_info
->sparse_map
[i
].offset
)
583 && check_data_region (&file
, i
);
584 offset
= file
.stat_info
->sparse_map
[i
].offset
585 + file
.stat_info
->sparse_map
[i
].numbytes
;
589 skip_file (file
.stat_info
->archive_file_size
- file
.dumped_size
);
592 tar_sparse_done (&file
);
597 /* Old GNU Format. The sparse file information is stored in the
598 oldgnu_header in the following manner:
600 The header is marked with type 'S'. Its `size' field contains
601 the cumulative size of all non-empty blocks of the file. The
602 actual file size is stored in `realsize' member of oldgnu_header.
604 The map of the file is stored in a list of `struct sparse'.
605 Each struct contains offset to the block of data and its
606 size (both as octal numbers). The first file header contains
607 at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
608 contains more structs, then the field `isextended' of the main
609 header is set to 1 (binary) and the `struct sparse_header'
610 header follows, containing at most 21 following structs
611 (SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
612 field of the extended header is set and next next extension header
615 enum oldgnu_add_status
623 oldgnu_sparse_member_p (struct tar_sparse_file
*file
__attribute__ ((unused
)))
625 return current_header
->header
.typeflag
== GNUTYPE_SPARSE
;
628 /* Add a sparse item to the sparse file and its obstack */
629 static enum oldgnu_add_status
630 oldgnu_add_sparse (struct tar_sparse_file
*file
, struct sparse
*s
)
634 if (s
->numbytes
[0] == '\0')
636 sp
.offset
= OFF_FROM_HEADER (s
->offset
);
637 sp
.numbytes
= SIZE_FROM_HEADER (s
->numbytes
);
639 || file
->stat_info
->stat
.st_size
< sp
.offset
+ sp
.numbytes
640 || file
->stat_info
->archive_file_size
< 0)
643 sparse_add_map (file
->stat_info
, &sp
);
648 oldgnu_fixup_header (struct tar_sparse_file
*file
)
650 /* NOTE! st_size was initialized from the header
651 which actually contains archived size. The following fixes it */
652 file
->stat_info
->archive_file_size
= file
->stat_info
->stat
.st_size
;
653 file
->stat_info
->stat
.st_size
=
654 OFF_FROM_HEADER (current_header
->oldgnu_header
.realsize
);
658 /* Convert old GNU format sparse data to internal representation */
660 oldgnu_get_sparse_info (struct tar_sparse_file
*file
)
663 union block
*h
= current_header
;
665 enum oldgnu_add_status rc
;
667 file
->stat_info
->sparse_map_avail
= 0;
668 for (i
= 0; i
< SPARSES_IN_OLDGNU_HEADER
; i
++)
670 rc
= oldgnu_add_sparse (file
, &h
->oldgnu_header
.sp
[i
]);
675 for (ext_p
= h
->oldgnu_header
.isextended
;
676 rc
== add_ok
&& ext_p
; ext_p
= h
->sparse_header
.isextended
)
678 h
= find_next_block ();
681 ERROR ((0, 0, _("Unexpected EOF in archive")));
684 set_next_block_after (h
);
685 for (i
= 0; i
< SPARSES_IN_SPARSE_HEADER
&& rc
== add_ok
; i
++)
686 rc
= oldgnu_add_sparse (file
, &h
->sparse_header
.sp
[i
]);
691 ERROR ((0, 0, _("%s: invalid sparse archive member"),
692 file
->stat_info
->orig_file_name
));
699 oldgnu_store_sparse_info (struct tar_sparse_file
*file
, size_t *pindex
,
700 struct sparse
*sp
, size_t sparse_size
)
702 for (; *pindex
< file
->stat_info
->sparse_map_avail
703 && sparse_size
> 0; sparse_size
--, sp
++, ++*pindex
)
705 OFF_TO_CHARS (file
->stat_info
->sparse_map
[*pindex
].offset
,
707 SIZE_TO_CHARS (file
->stat_info
->sparse_map
[*pindex
].numbytes
,
713 oldgnu_dump_header (struct tar_sparse_file
*file
)
715 off_t block_ordinal
= current_block_ordinal ();
719 blk
= start_header (file
->stat_info
);
720 blk
->header
.typeflag
= GNUTYPE_SPARSE
;
721 if (file
->stat_info
->sparse_map_avail
> SPARSES_IN_OLDGNU_HEADER
)
722 blk
->oldgnu_header
.isextended
= 1;
724 /* Store the real file size */
725 OFF_TO_CHARS (file
->stat_info
->stat
.st_size
, blk
->oldgnu_header
.realsize
);
726 /* Store the effective (shrunken) file size */
727 OFF_TO_CHARS (file
->stat_info
->archive_file_size
, blk
->header
.size
);
730 oldgnu_store_sparse_info (file
, &i
,
731 blk
->oldgnu_header
.sp
,
732 SPARSES_IN_OLDGNU_HEADER
);
733 blk
->oldgnu_header
.isextended
= i
< file
->stat_info
->sparse_map_avail
;
734 finish_header (file
->stat_info
, blk
, block_ordinal
);
736 while (i
< file
->stat_info
->sparse_map_avail
)
738 blk
= find_next_block ();
739 memset (blk
->buffer
, 0, BLOCKSIZE
);
740 oldgnu_store_sparse_info (file
, &i
,
741 blk
->sparse_header
.sp
,
742 SPARSES_IN_SPARSE_HEADER
);
743 set_next_block_after (blk
);
744 if (i
< file
->stat_info
->sparse_map_avail
)
745 blk
->sparse_header
.isextended
= 1;
752 static struct tar_sparse_optab
const oldgnu_optab
= {
753 NULL
, /* No init function */
754 NULL
, /* No done function */
755 oldgnu_sparse_member_p
,
758 oldgnu_get_sparse_info
,
759 NULL
, /* No scan_block function */
761 sparse_extract_region
,
768 star_sparse_member_p (struct tar_sparse_file
*file
__attribute__ ((unused
)))
770 return current_header
->header
.typeflag
== GNUTYPE_SPARSE
;
774 star_fixup_header (struct tar_sparse_file
*file
)
776 /* NOTE! st_size was initialized from the header
777 which actually contains archived size. The following fixes it */
778 file
->stat_info
->archive_file_size
= file
->stat_info
->stat
.st_size
;
779 file
->stat_info
->stat
.st_size
=
780 OFF_FROM_HEADER (current_header
->star_in_header
.realsize
);
784 /* Convert STAR format sparse data to internal representation */
786 star_get_sparse_info (struct tar_sparse_file
*file
)
789 union block
*h
= current_header
;
791 enum oldgnu_add_status rc
= add_ok
;
793 file
->stat_info
->sparse_map_avail
= 0;
795 if (h
->star_in_header
.prefix
[0] == '\0'
796 && h
->star_in_header
.sp
[0].offset
[10] != '\0')
798 /* Old star format */
799 for (i
= 0; i
< SPARSES_IN_STAR_HEADER
; i
++)
801 rc
= oldgnu_add_sparse (file
, &h
->star_in_header
.sp
[i
]);
805 ext_p
= h
->star_in_header
.isextended
;
810 for (; rc
== add_ok
&& ext_p
; ext_p
= h
->star_ext_header
.isextended
)
812 h
= find_next_block ();
815 ERROR ((0, 0, _("Unexpected EOF in archive")));
818 set_next_block_after (h
);
819 for (i
= 0; i
< SPARSES_IN_STAR_EXT_HEADER
&& rc
== add_ok
; i
++)
820 rc
= oldgnu_add_sparse (file
, &h
->star_ext_header
.sp
[i
]);
825 ERROR ((0, 0, _("%s: invalid sparse archive member"),
826 file
->stat_info
->orig_file_name
));
833 static struct tar_sparse_optab
const star_optab
= {
834 NULL
, /* No init function */
835 NULL
, /* No done function */
836 star_sparse_member_p
,
839 star_get_sparse_info
,
840 NULL
, /* No scan_block function */
841 NULL
, /* No dump region function */
842 sparse_extract_region
,
846 /* GNU PAX sparse file format. The sparse file map is stored in
849 GNU.sparse.size Real size of the stored file
850 GNU.sparse.numblocks Number of blocks in the sparse map
851 GNU.sparse.map Map of non-null data chunks. A string consisting
852 of comma-separated values "offset,size[,offset,size]..."
854 Tar versions 1.14-1.15.1 instead of the latter used:
856 repeat numblocks time
857 GNU.sparse.offset Offset of the next data block
858 GNU.sparse.numbytes Size of the next data block
861 This has been reported as conflicting with the POSIX specs. The reason is
862 that offsets and sizes of non-zero data blocks were stored in multiple
863 instances of GNU.sparse.offset/GNU.sparse.numbytes variables. However,
864 POSIX requires the latest occurrence of the variable to override all
865 previous occurrences.
867 To avoid this incompatibility new keyword GNU.sparse.map was introduced
868 in tar 1.15.2. Some people might still need the 1.14 way of handling
869 sparse files for the compatibility reasons: it can be achieved by
870 specifying `--pax-option delete=GNU.sparse.map' in the command line.
872 See FIXME-1.14-1.15.1-1.20, below.
876 pax_sparse_member_p (struct tar_sparse_file
*file
)
878 return file
->stat_info
->sparse_map_avail
> 0;
882 pax_dump_header (struct tar_sparse_file
*file
)
884 off_t block_ordinal
= current_block_ordinal ();
887 char nbuf
[UINTMAX_STRSIZE_BOUND
];
888 struct sp_array
*map
= file
->stat_info
->sparse_map
;
890 /* Store the real file size */
891 xheader_store ("GNU.sparse.size", file
->stat_info
, NULL
);
892 xheader_store ("GNU.sparse.numblocks", file
->stat_info
, NULL
);
894 /* FIXME-1.14-1.15.1-1.20: See the comment above.
895 Starting with 1.17 this should display a warning about POSIX-incompatible
896 keywords being generated. In 1.20, the true branch of the if block below
897 will be removed and GNU.sparse.map will be marked in xhdr_tab as
900 if (xheader_keyword_deleted_p ("GNU.sparse.map"))
902 for (i
= 0; i
< file
->stat_info
->sparse_map_avail
; i
++)
904 xheader_store ("GNU.sparse.offset", file
->stat_info
, &i
);
905 xheader_store ("GNU.sparse.numbytes", file
->stat_info
, &i
);
910 xheader_string_begin ();
911 for (i
= 0; i
< file
->stat_info
->sparse_map_avail
; i
++)
914 xheader_string_add (",");
915 xheader_string_add (umaxtostr (map
[i
].offset
, nbuf
));
916 xheader_string_add (",");
917 xheader_string_add (umaxtostr (map
[i
].numbytes
, nbuf
));
919 xheader_string_end ("GNU.sparse.map");
921 blk
= start_header (file
->stat_info
);
922 /* Store the effective (shrunken) file size */
923 OFF_TO_CHARS (file
->stat_info
->archive_file_size
, blk
->header
.size
);
924 finish_header (file
->stat_info
, blk
, block_ordinal
);
928 static struct tar_sparse_optab
const pax_optab
= {
929 NULL
, /* No init function */
930 NULL
, /* No done function */
933 NULL
, /* No decode_header function */
934 NULL
, /* No fixup_header function */
935 NULL
, /* No scan_block function */
937 sparse_extract_region
,