return true;
}
+/* An output block BLOCK, and a pointer PTR into it. */
+struct block_ptr
+{
+ union block *block;
+ char *ptr;
+};
+
+/* Append to BP the contents of the string SRC, followed by a newline.
+ If the string doesn’t fit, put any overflow into the succeeding blocks.
+ Return the updated BP. */
+static struct block_ptr
+dump_str_nl (struct block_ptr bp, char const *str)
+{
+ char *endp = bp.block->buffer + BLOCKSIZE;
+ char c;
+ do
+ {
+ c = *str++;
+ if (bp.ptr == endp)
+ {
+ set_next_block_after (bp.block);
+ bp.block = find_next_block ();
+ bp.ptr = bp.block->buffer;
+ endp = bp.block->buffer + BLOCKSIZE;
+ }
+ *bp.ptr++ = c ? c : '\n';
+ }
+ while (c);
+
+ return bp;
+}
+
+/* Return the floor of the log base 10 of N. If N is 0, return 0. */
+static int
+floorlog10 (uintmax_t n)
+{
+ for (int f = 0; ; f++)
+ if ((n /= 10) == 0)
+ return f;
+}
+
static bool
pax_dump_header_1 (struct tar_sparse_file *file)
{
off_t block_ordinal = current_block_ordinal ();
- union block *blk;
- char *p, *q;
- size_t i;
char nbuf[UINTMAX_STRSIZE_BOUND];
- off_t size = 0;
struct sp_array *map = file->stat_info->sparse_map;
char *save_file_name = file->stat_info->file_name;
-#define COPY_STRING(b,dst,src) do \
- { \
- char *endp = b->buffer + BLOCKSIZE; \
- char const *srcp = src; \
- while (*srcp) \
- { \
- if (dst == endp) \
- { \
- set_next_block_after (b); \
- b = find_next_block (); \
- dst = b->buffer; \
- endp = b->buffer + BLOCKSIZE; \
- } \
- *dst++ = *srcp++; \
- } \
- } while (0)
-
/* Compute stored file size */
- p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
- size += strlen (p) + 1;
- for (i = 0; i < file->stat_info->sparse_map_avail; i++)
+ off_t size = floorlog10 (file->stat_info->sparse_map_avail) + 2;
+ for (idx_t i = 0; i < file->stat_info->sparse_map_avail; i++)
{
- p = umaxtostr (map[i].offset, nbuf);
- size += strlen (p) + 1;
- p = umaxtostr (map[i].numbytes, nbuf);
- size += strlen (p) + 1;
+ size += floorlog10 (map[i].offset) + 2;
+ size += floorlog10 (map[i].numbytes) + 2;
}
- size = (size + BLOCKSIZE - 1) / BLOCKSIZE;
- file->stat_info->archive_file_size += size * BLOCKSIZE;
- file->dumped_size += size * BLOCKSIZE;
+ size = (size + BLOCKSIZE - 1) / BLOCKSIZE * BLOCKSIZE;
+ file->stat_info->archive_file_size += size;
+ file->dumped_size += size;
/* Store sparse file identification */
xheader_store ("GNU.sparse.major", file->stat_info, NULL);
if (strlen (file->stat_info->file_name) > NAME_FIELD_SIZE)
file->stat_info->file_name[NAME_FIELD_SIZE] = 0;
- blk = pax_start_header (file->stat_info);
- finish_header (file->stat_info, blk, block_ordinal);
+ struct block_ptr bp;
+ bp.block = pax_start_header (file->stat_info);
+ finish_header (file->stat_info, bp.block, block_ordinal);
free (file->stat_info->file_name);
file->stat_info->file_name = save_file_name;
- blk = find_next_block ();
- q = blk->buffer;
- p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
- COPY_STRING (blk, q, p);
- COPY_STRING (blk, q, "\n");
- for (i = 0; i < file->stat_info->sparse_map_avail; i++)
+ bp.block = find_next_block ();
+ bp.ptr = bp.block->buffer;
+ bp = dump_str_nl (bp, umaxtostr (file->stat_info->sparse_map_avail, nbuf));
+ for (idx_t i = 0; i < file->stat_info->sparse_map_avail; i++)
{
- p = umaxtostr (map[i].offset, nbuf);
- COPY_STRING (blk, q, p);
- COPY_STRING (blk, q, "\n");
- p = umaxtostr (map[i].numbytes, nbuf);
- COPY_STRING (blk, q, p);
- COPY_STRING (blk, q, "\n");
+ bp = dump_str_nl (bp, umaxtostr (map[i].offset, nbuf));
+ bp = dump_str_nl (bp, umaxtostr (map[i].numbytes, nbuf));
}
- memset (q, 0, BLOCKSIZE - (q - blk->buffer));
- set_next_block_after (blk);
+ memset (bp.ptr, 0, BLOCKSIZE - (bp.ptr - bp.block->buffer));
+ set_next_block_after (bp.block);
return true;
}