/* 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
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)
{
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;
}
\f
/* 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.
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
* 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
"%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
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 */
}
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);
{
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
{ \
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; \
} \
} while (0)
set_next_block_after (current_header);
+ file->dumped_size += BLOCKSIZE;
blk = find_next_block ();
p = blk->buffer;
COPY_BUF (blk,nbuf,p);