#include "system.h"
-#include <grp.h>
#include <hash.h>
-#include <pwd.h>
#include <quotearg.h>
+#include <xstrtol.h>
#include "common.h"
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)
}
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;
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
}
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)
{
static void
dummy_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr)
+ struct xheader *xhdr, void *data)
{
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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 },
{ "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. */