X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Fsparse.c;h=9fde5080d5304a32253fd67d72e1a99a0c69bf56;hb=338add8d10a787aafb6fd57aeae497a79a8d5855;hp=799a00fc0bc93256b78c1e1427ad4237defb588e;hpb=090d1d36ae038a82d2b4bb54a8464bb7629188b7;p=chaz%2Ftar diff --git a/src/sparse.c b/src/sparse.c index 799a00f..9fde508 100644 --- a/src/sparse.c +++ b/src/sparse.c @@ -1,10 +1,10 @@ /* Functions for dealing with sparse files - Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any later + Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but @@ -409,15 +409,6 @@ sparse_dump_file (int fd, struct tar_stat_info *st) return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short; } -/* Returns true if the file represented by stat is a sparse one */ -bool -sparse_file_p (struct tar_stat_info *st) -{ - return (ST_NBLOCKS (st->stat) - < (st->stat.st_size / ST_NBLOCKSIZE - + (st->stat.st_size % ST_NBLOCKSIZE != 0))); -} - bool sparse_member_p (struct tar_stat_info *st) { @@ -475,7 +466,7 @@ sparse_skip_file (struct tar_stat_info *st) file.fd = -1; rc = tar_sparse_decode_header (&file); - skip_file (file.stat_info->archive_file_size); + skip_file (file.stat_info->archive_file_size - file.dumped_size); return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short; } @@ -843,7 +834,6 @@ static struct tar_sparse_optab const star_optab = { /* GNU PAX sparse file format. There are several versions: - * 0.0 The initial version of sparse format used by tar 1.14-1.15.1. @@ -874,7 +864,7 @@ static struct tar_sparse_optab const star_optab = { GNU.sparse.size Real size of the stored file GNU.sparse.numblocks Number of blocks in the sparse map GNU.sparse.map Map of non-null data chunks. A string consisting - of comma-separated values "offset,size[,offset,size]..." + of comma-separated values "offset,size[,offset,size]..." The resulting GNU.sparse.map string can be *very* long. While POSIX does not impose any limit on the length of a x header variable, this can confuse some @@ -882,8 +872,8 @@ static struct tar_sparse_optab const star_optab = { * 1.0 - Starting from this version, the exact sparse format version is specified explicitely - in the header using the following variables: + Starting from this version, the exact sparse format version is specified + explicitely in the header using the following variables: GNU.sparse.major Major version GNU.sparse.minor Minor version @@ -898,22 +888,24 @@ static struct tar_sparse_optab const star_optab = { "%d/GNUSparseFile.%p/%f". The sparse map itself is stored in the file data block, preceding the actual - file data. It consists of a series of octal numbers of arbitrary length, delimited - by newlines. The map is padded with nulls to the nearest block boundary. + file data. It consists of a series of octal numbers of arbitrary length, + delimited by newlines. The map is padded with nulls to the nearest block + boundary. - The first number gives the number of entries in the map. Following are map entries, - each one consisting of two numbers giving the offset and size of the - data block it describes. + The first number gives the number of entries in the map. Following are map + entries, each one consisting of two numbers giving the offset and size of + the data block it describes. The format is designed in such a way that non-posix aware tars and tars not - supporting GNU.sparse.* keywords will extract each sparse file in its condensed - form with the file map attached and will place it into a separate directory. - Then, using a simple program it would be possible to expand the file to its - original form even without GNU tar. - - Bu default, v.1.0 archives are created. To use other formats, --sparse-version - option is provided. Additionally, v.0.0 can be obtained by deleting GNU.sparse.map - from 0.1 format: --sparse-version 0.1 --pax-option delete=GNU.sparse.map + supporting GNU.sparse.* keywords will extract each sparse file in its + condensed form with the file map attached and will place it into a separate + directory. Then, using a simple program it would be possible to expand the + file to its original form even without GNU tar. + + Bu default, v.1.0 archives are created. To use other formats, + --sparse-version option is provided. Additionally, v.0.0 can be obtained + by deleting GNU.sparse.map from 0.1 format: --sparse-version 0.1 + --pax-option delete=GNU.sparse.map */ static bool @@ -953,16 +945,24 @@ pax_dump_header_0 (struct tar_sparse_file *file) file->stat_info->file_name = xheader_format_name (file->stat_info, "%d/GNUSparseFile.%p/%f", 0); - xheader_string_begin (); + xheader_string_begin (&file->stat_info->xhdr); for (i = 0; i < file->stat_info->sparse_map_avail; i++) { if (i) - xheader_string_add (","); - xheader_string_add (umaxtostr (map[i].offset, nbuf)); - xheader_string_add (","); - xheader_string_add (umaxtostr (map[i].numbytes, nbuf)); + xheader_string_add (&file->stat_info->xhdr, ","); + xheader_string_add (&file->stat_info->xhdr, + umaxtostr (map[i].offset, nbuf)); + xheader_string_add (&file->stat_info->xhdr, ","); + xheader_string_add (&file->stat_info->xhdr, + umaxtostr (map[i].numbytes, nbuf)); + } + if (!xheader_string_end (&file->stat_info->xhdr, + "GNU.sparse.map")) + { + free (file->stat_info->file_name); + file->stat_info->file_name = save_file_name; + return false; } - xheader_string_end ("GNU.sparse.map"); } blk = start_header (file->stat_info); /* Store the effective (shrunken) file size */ @@ -1017,6 +1017,7 @@ pax_dump_header_1 (struct tar_sparse_file *file) } size = (size + BLOCKSIZE - 1) / BLOCKSIZE; file->stat_info->archive_file_size += size * BLOCKSIZE; + file->dumped_size += size * BLOCKSIZE; /* Store sparse file identification */ xheader_store ("GNU.sparse.major", file->stat_info, NULL); @@ -1058,11 +1059,9 @@ pax_dump_header (struct tar_sparse_file *file) { file->stat_info->sparse_major = tar_sparse_major; file->stat_info->sparse_minor = tar_sparse_minor; - - if (file->stat_info->sparse_major == 0) - pax_dump_header_0 (file); - else - pax_dump_header_1 (file); + + return (file->stat_info->sparse_major == 0) ? + pax_dump_header_0 (file) : pax_dump_header_1 (file); } static bool @@ -1102,14 +1101,15 @@ pax_decode_header (struct tar_sparse_file *file) { \ if (dst == buf + UINTMAX_STRSIZE_BOUND -1) \ { \ - ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"), \ + ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"), \ file->stat_info->orig_file_name)); \ return false; \ } \ - if (src == endp) \ + if (src == endp) \ { \ set_next_block_after (b); \ - b = find_next_block (); \ + file->dumped_size += BLOCKSIZE; \ + b = find_next_block (); \ src = b->buffer; \ endp = b->buffer + BLOCKSIZE; \ } \ @@ -1120,6 +1120,7 @@ pax_decode_header (struct tar_sparse_file *file) } while (0) set_next_block_after (current_header); + file->dumped_size += BLOCKSIZE; blk = find_next_block (); p = blk->buffer; COPY_BUF (blk,nbuf,p);