]> Dogcows Code - chaz/tar/blobdiff - src/xheader.c
(code_time,decode_time): Support for subsecond precision. (atime_coder,atime_decoder...
[chaz/tar] / src / xheader.c
index 3926a7f81ad2601437cec8afe6dbc9a1e1653786..af2c4be0d4135e4f91d5208c36c390bc534d488e 100644 (file)
 
 #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)
@@ -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.  */
This page took 0.030127 seconds and 4 git commands to generate.