}
if (sp.numbytes == 0)
- {
- sp.offset = offset - 1;
- sp.numbytes = 1;
- }
+ sp.offset = offset;
+
sparse_add_map (file, &sp);
file->stat_info->archive_file_size += count;
return tar_sparse_scan (file, scan_end, NULL);
static struct tar_sparse_optab oldgnu_optab;
static struct tar_sparse_optab star_optab;
+static struct tar_sparse_optab pax_optab;
static bool
sparse_select_optab (struct tar_sparse_file *file)
break;
case POSIX_FORMAT:
- /* FIXME: Add method */
- return false;
+ file->optab = &pax_optab;
+ break;
case STAR_FORMAT:
file->optab = &star_optab;
SEEK_SET))
return false;
- do
+ while (bytes_left > 0)
{
size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
off_t bytes_read;
file->dumped_size += bytes_read;
set_next_block_after (blk);
}
- while (bytes_left > 0);
+
return true;
}
if (!lseek_or_error (file, file->stat_info->sparse_map[index].offset,
SEEK_SET))
return false;
+
write_size = file->stat_info->sparse_map[index].numbytes;
- while (write_size > 0)
+
+ if (write_size == 0)
+ {
+ /* Last block of the file is a hole */
+ if (sys_truncate (file->fd))
+ truncate_warn (file->stat_info->orig_file_name);
+ }
+ else while (write_size > 0)
{
size_t count;
size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;
+ file.stat_info->sparse_map[i].numbytes;
}
- if (rc)
+ if (!rc)
skip_file (file.stat_info->archive_file_size - file.dumped_size);
tar_sparse_done (&file);
NULL, /* No dump region function */
sparse_extract_region,
};
+
+\f
+/* GNU PAX sparse file format. The sparse file map is stored in
+ x header:
+
+ GNU.sparse.size Real size of the stored file
+ GNU.sparse.numblocks Number of blocks in the sparse map
+ repeat numblocks time
+ GNU.sparse.offset Offset of the next data block
+ GNU.sparse.numbytes Size of the next data block
+ end repeat
+*/
+
+static bool
+pax_dump_header (struct tar_sparse_file *file)
+{
+ off_t block_ordinal = current_block_ordinal ();
+ union block *blk;
+ size_t i;
+
+ /* Store the real file size */
+ xheader_store ("GNU.sparse.size", file->stat_info, NULL);
+ xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
+ for (i = 0; i < file->stat_info->sparse_map_avail; i++)
+ {
+ xheader_store ("GNU.sparse.offset", file->stat_info, &i);
+ xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
+ }
+
+ blk = start_header (file->stat_info);
+ /* Store the effective (shrunken) file size */
+ OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
+ finish_header (file->stat_info, blk, block_ordinal);
+ return true;
+}
+
+static bool
+pax_decode_header (struct tar_sparse_file *file)
+{
+ /* Restore actual size */
+ size_t s = file->stat_info->archive_file_size;
+ file->stat_info->archive_file_size = file->stat_info->stat.st_size;
+ file->stat_info->stat.st_size = s;
+ return true;
+}
+
+static struct tar_sparse_optab pax_optab = {
+ NULL, /* No init function */
+ NULL, /* No done function */
+ pax_dump_header,
+ pax_decode_header,
+ NULL, /* No scan_block function */
+ sparse_dump_region,
+ sparse_extract_region,
+};
+