X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=af2c4be0d4135e4f91d5208c36c390bc534d488e;hb=3710b34c7e5a5b84a5018176f23484bf6a28a16c;hp=3926a7f81ad2601437cec8afe6dbc9a1e1653786;hpb=3f998f69b9d3899e144323c322f8567237201cb1;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index 3926a7f..af2c4be 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -18,10 +18,9 @@ #include "system.h" -#include #include -#include #include +#include #include "common.h" @@ -34,11 +33,18 @@ struct xhdr_tab { char const *keyword; - void (*coder) (struct tar_stat_info const *, char const *, struct xheader *); + void (*coder) (struct tar_stat_info const *, char const *, + struct xheader *, void *data); void (*decoder) (struct tar_stat_info *, char const *); }; -static struct xhdr_tab const xhdr_tab[]; +/* This declaration must be extern, because ISO C99 section 6.9.2 + prohibits a tentative definition that has both internal linkage and + incomplete type. If we made it static, we'd have to declare its + size which would be a maintenance pain; if we put its initializer + here, we'd need a boatload of forward declarations, which would be + even more of a pain. */ +extern struct xhdr_tab const xhdr_tab[]; static struct xhdr_tab const * locate_handler (char const *keyword) @@ -107,7 +113,7 @@ decode_record (char **p, struct tar_stat_info *st) void xheader_decode (struct tar_stat_info *st) { - char *p = extended_header.buffer; + char *p = extended_header.buffer + BLOCKSIZE; char *endp = &extended_header.buffer[extended_header.size-1]; while (p < endp) @@ -116,7 +122,7 @@ xheader_decode (struct tar_stat_info *st) } void -xheader_store (char const *keyword, struct tar_stat_info const *st) +xheader_store (char const *keyword, struct tar_stat_info const *st, void *data) { struct xhdr_tab const *t; @@ -130,35 +136,37 @@ xheader_store (char const *keyword, struct tar_stat_info const *st) extended_header.stk = xmalloc (sizeof *extended_header.stk); obstack_init (extended_header.stk); } - t->coder (st, keyword, &extended_header); + t->coder (st, keyword, &extended_header, data); } void xheader_read (union block *p, size_t size) { - size_t i, j; + size_t j = 0; size_t nblocks; free (extended_header.buffer); + size += BLOCKSIZE; extended_header.size = size; nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE; extended_header.buffer = xmalloc (size + 1); - set_next_block_after (p); - for (i = j = 0; i < nblocks; i++) + do { - size_t len; + size_t len = size; - p = find_next_block (); - len = size; if (len > BLOCKSIZE) len = BLOCKSIZE; + memcpy (&extended_header.buffer[j], p->buffer, len); set_next_block_after (p); + p = find_next_block (); + j += len; size -= len; } + while (size > 0); } static size_t @@ -242,17 +250,33 @@ code_string (char const *string, char const *keyword, struct xheader *xhdr) } static void -code_time (time_t t, char const *keyword, struct xheader *xhdr) +code_time (time_t t, unsigned long nano, + char const *keyword, struct xheader *xhdr) { - char sbuf[100]; + char sbuf[200]; size_t s = format_uintmax (t, NULL, 0); + if (s + 11 >= sizeof sbuf) + return; format_uintmax (t, sbuf, s); sbuf[s++] = '.'; - format_uintmax (0, sbuf + s, 9); - sbuf[s+9] = 0; + s += format_uintmax (nano, sbuf + s, 9); + sbuf[s] = 0; xheader_print (xhdr, keyword, sbuf); } +static void +decode_time (char const *arg, time_t *secs, unsigned long *nsecs) +{ + uintmax_t u; + char *p; + if (xstrtoumax (arg, &p, 10, &u, "") == LONGINT_OK) + { + *secs = u; + if (*p == '.' && xstrtoumax (p+1, NULL, 10, &u, "") == LONGINT_OK) + *nsecs = u; + } +} + static void code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) { @@ -265,7 +289,7 @@ code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) static void dummy_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { } @@ -276,20 +300,20 @@ dummy_decoder (struct tar_stat_info *st, char const *arg) static void atime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { - code_time (st->stat.st_atime, keyword, xhdr); + code_time (st->stat.st_atime, st->atime_nsec, keyword, xhdr); } static void atime_decoder (struct tar_stat_info *st, char const *arg) { - st->stat.st_atime = strtoul (arg, NULL, 0); + decode_time (arg, &st->stat.st_atime, &st->atime_nsec); } static void gid_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_num (st->stat.st_gid, keyword, xhdr); } @@ -297,12 +321,14 @@ gid_coder (struct tar_stat_info const *st, char const *keyword, static void gid_decoder (struct tar_stat_info *st, char const *arg) { - st->stat.st_gid = strtoul (arg, NULL, 0); + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + st->stat.st_gid = u; } static void gname_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_string (st->gname, keyword, xhdr); } @@ -315,7 +341,7 @@ gname_decoder (struct tar_stat_info *st, char const *arg) static void linkpath_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_string (st->link_name, keyword, xhdr); } @@ -328,33 +354,33 @@ linkpath_decoder (struct tar_stat_info *st, char const *arg) static void ctime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { - code_time (st->stat.st_ctime, keyword, xhdr); + code_time (st->stat.st_ctime, st->ctime_nsec, keyword, xhdr); } static void ctime_decoder (struct tar_stat_info *st, char const *arg) { - st->stat.st_ctime = strtoul (arg, NULL, 0); + decode_time (arg, &st->stat.st_ctime, &st->ctime_nsec); } static void mtime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { - code_time (st->stat.st_mtime, keyword, xhdr); + code_time (st->stat.st_mtime, st->mtime_nsec, keyword, xhdr); } static void mtime_decoder (struct tar_stat_info *st, char const *arg) { - st->stat.st_mtime = strtoul (arg, NULL, 0); + decode_time (arg, &st->stat.st_mtime, &st->mtime_nsec); } static void path_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_string (st->file_name, keyword, xhdr); } @@ -369,7 +395,7 @@ path_decoder (struct tar_stat_info *st, char const *arg) static void size_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_num (st->stat.st_size, keyword, xhdr); } @@ -377,12 +403,14 @@ size_coder (struct tar_stat_info const *st, char const *keyword, static void size_decoder (struct tar_stat_info *st, char const *arg) { - st->stat.st_size = strtoul (arg, NULL, 0); + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + st->stat.st_size = u; } static void uid_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_num (st->stat.st_uid, keyword, xhdr); } @@ -390,12 +418,14 @@ uid_coder (struct tar_stat_info const *st, char const *keyword, static void uid_decoder (struct tar_stat_info *st, char const *arg) { - st->stat.st_uid = strtoul (arg, NULL, 0); + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + st->stat.st_uid = u; } static void uname_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr) + struct xheader *xhdr, void *data) { code_string (st->uname, keyword, xhdr); } @@ -406,7 +436,82 @@ uname_decoder (struct tar_stat_info *st, char const *arg) assign_string (&st->uname, arg); } -static struct xhdr_tab const xhdr_tab[] = { +static void +sparse_size_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void *data) +{ + size_coder (st, keyword, xhdr, data); +} + +static void +sparse_size_decoder (struct tar_stat_info *st, char const *arg) +{ + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + st->archive_file_size = u; +} + +static void +sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void *data) +{ + code_num (st->sparse_map_avail, keyword, xhdr); +} + +static void +sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg) +{ + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + { + st->sparse_map_size = u; + st->sparse_map = calloc(st->sparse_map_size, sizeof(st->sparse_map[0])); + st->sparse_map_avail = 0; + } +} + +static void +sparse_offset_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void *data) +{ + size_t i = *(size_t*)data; + code_num (st->sparse_map[i].offset, keyword, xhdr); +} + +static void +sparse_offset_decoder (struct tar_stat_info *st, char const *arg) +{ + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + st->sparse_map[st->sparse_map_avail].offset = u; +} + +static void +sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void *data) +{ + size_t i = *(size_t*)data; + code_num (st->sparse_map[i].numbytes, keyword, xhdr); +} + +static void +sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg) +{ + uintmax_t u; + if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + { + if (st->sparse_map_avail == st->sparse_map_size) + { + size_t newsize = st->sparse_map_size *= 2; + st->sparse_map = xrealloc (st->sparse_map, + st->sparse_map_size + * sizeof st->sparse_map[0]); + } + st->sparse_map[st->sparse_map_avail++].numbytes = u; + } +} + +struct xhdr_tab const xhdr_tab[] = { { "atime", atime_coder, atime_decoder }, { "comment", dummy_coder, dummy_decoder }, { "charset", dummy_coder, dummy_decoder }, @@ -420,11 +525,14 @@ static struct xhdr_tab const xhdr_tab[] = { { "uid", uid_coder, uid_decoder }, { "uname", uname_coder, uname_decoder }, -#if 0 /* GNU private keywords (not yet implemented) */ /* Sparse file handling */ + { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder }, + { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder }, { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder }, { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder }, +#if 0 /* GNU private keywords (not yet implemented) */ + /* The next directory entry actually contains the names of files that were in the directory at the time the dump was made. Supersedes GNUTYPE_DUMPDIR header type. */