]> Dogcows Code - chaz/tar/blobdiff - src/xheader.c
Update copyright years.
[chaz/tar] / src / xheader.c
index 50fd3e754dbd8bca19964d7eecf5be6c3dc2aa7c..c94c6d39f1e2437a3caa8ea577d436cd77275143 100644 (file)
@@ -1,21 +1,22 @@
 /* POSIX extended headers for tar.
 
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2007, 2009-2010, 2012-2014 Free Software
+   Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3, or (at your option) any later
-   version.
+   This file is part of GNU tar.
 
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-   Public License for more details.
+   GNU tar is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation, Inc.,
-   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   GNU tar is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <system.h>
 
@@ -167,14 +168,13 @@ xheader_set_single_keyword (char *kw)
 static void
 assign_time_option (char **sval, time_t *tval, const char *input)
 {
-  uintmax_t u;
   char *p;
-  time_t t = u = strtoumax (input, &p, 10);
-  if (t != u || *p || errno == ERANGE)
+  struct timespec t = decode_timespec (input, &p, false);
+  if (! valid_timespec (t) || *p)
     ERROR ((0, 0, _("Time stamp is out of allowed range")));
   else
     {
-      *tval = t;
+      *tval = t.tv_sec;
       assign_string (sval, input);
     }
 }
@@ -262,7 +262,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
   char *dir = NULL;
   char *base = NULL;
   char pidbuf[UINTMAX_STRSIZE_BOUND];
-  char const *pptr;
+  char const *pptr = NULL;
   char nbuf[UINTMAX_STRSIZE_BOUND];
   char const *nptr = NULL;
 
@@ -335,13 +335,10 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
              break;
 
            case 'n':
-             if (nptr)
-               {
-                 q = stpcpy (q, nptr);
-                 p += 2;
-                 break;
-               }
-             /* else fall through */
+             q = stpcpy (q, nptr);
+             p += 2;
+             break;
+
 
            default:
              *q++ = *p++;
@@ -455,7 +452,8 @@ xheader_write_global (struct xheader *xhdr)
       char *name;
 
       xheader_finish (xhdr);
-      xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
+      name = xheader_ghdr_name ();
+      xheader_write (XGLTYPE, name, start_time.tv_sec, xhdr);
       free (name);
     }
 }
@@ -655,7 +653,6 @@ decode_record (struct xheader *xhdr,
 {
   char *start = *ptr;
   char *p = start;
-  uintmax_t u;
   size_t len;
   char *len_lim;
   char const *keyword;
@@ -672,13 +669,7 @@ decode_record (struct xheader *xhdr,
       return false;
     }
 
-  errno = 0;
-  len = u = strtoumax (p, &len_lim, 10);
-  if (len != u || errno == ERANGE)
-    {
-      ERROR ((0, 0, _("Extended header length is out of allowed range")));
-      return false;
-    }
+  len = strtoumax (p, &len_lim, 10);
 
   if (len_max < len)
     {
@@ -820,10 +811,16 @@ xheader_store (char const *keyword, struct tar_stat_info *st,
 }
 
 void
-xheader_read (struct xheader *xhdr, union block *p, size_t size)
+xheader_read (struct xheader *xhdr, union block *p, off_t size)
 {
   size_t j = 0;
 
+  if (size < 0)
+    size = 0; /* Already diagnosed.  */
+
+  if (SIZE_MAX - BLOCKSIZE <= size)
+    xalloc_die ();
+
   size += BLOCKSIZE;
   xhdr->size = size;
   xhdr->buffer = xmalloc (size + 1);
@@ -1034,14 +1031,12 @@ xheader_string_end (struct xheader *xhdr, char const *keyword)
 
 static void
 out_of_range_header (char const *keyword, char const *value,
-                    uintmax_t minus_minval, uintmax_t maxval)
+                    intmax_t minval, uintmax_t maxval)
 {
-  char minval_buf[UINTMAX_STRSIZE_BOUND + 1];
+  char minval_buf[INT_BUFSIZE_BOUND (intmax_t)];
   char maxval_buf[UINTMAX_STRSIZE_BOUND];
-  char *minval_string = umaxtostr (minus_minval, minval_buf + 1);
+  char *minval_string = imaxtostr (minval, minval_buf);
   char *maxval_string = umaxtostr (maxval, maxval_buf);
-  if (minus_minval)
-    *--minval_string = '-';
 
   /* TRANSLATORS: The first %s is the pax extended header keyword
      (atime, gid, etc.).  */
@@ -1084,134 +1079,59 @@ code_time (struct timespec t, char const *keyword, struct xheader *xhdr)
   xheader_print (xhdr, keyword, code_timespec (t, buf));
 }
 
-enum decode_time_status
-  {
-    decode_time_success,
-    decode_time_range,
-    decode_time_bad_header
-  };
-
-static enum decode_time_status
-_decode_time (struct timespec *ts, char const *arg, char const *keyword)
+static bool
+decode_time (struct timespec *ts, char const *arg, char const *keyword)
 {
-  time_t s;
-  unsigned long int ns = 0;
-  char *p;
   char *arg_lim;
-  bool negative = *arg == '-';
+  struct timespec t = decode_timespec (arg, &arg_lim, true);
 
-  errno = 0;
-
-  if (ISDIGIT (arg[negative]))
+  if (! valid_timespec (t))
     {
-      if (negative)
-       {
-         intmax_t i = strtoimax (arg, &arg_lim, 10);
-         if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
-           return decode_time_range;
-         s = i;
-       }
+      if (arg < arg_lim && !*arg_lim)
+       out_of_range_header (keyword, arg, TYPE_MINIMUM (time_t),
+                            TYPE_MAXIMUM (time_t));
       else
-       {
-         uintmax_t i = strtoumax (arg, &arg_lim, 10);
-         if (TYPE_MAXIMUM (time_t) < i)
-           return decode_time_range;
-         s = i;
-       }
-
-      p = arg_lim;
-
-      if (errno == ERANGE)
-       return decode_time_range;
-
-      if (*p == '.')
-       {
-         int digits = 0;
-         bool trailing_nonzero = false;
-
-         while (ISDIGIT (*++p))
-           if (digits < LOG10_BILLION)
-             {
-               ns = 10 * ns + (*p - '0');
-               digits++;
-             }
-           else
-             trailing_nonzero |= *p != '0';
-
-         while (digits++ < LOG10_BILLION)
-           ns *= 10;
-
-         if (negative)
-           {
-             /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
-                I.e., truncate time stamps towards minus infinity while
-                converting them to internal form.  */
-             ns += trailing_nonzero;
-             if (ns != 0)
-               {
-                 if (s == TYPE_MINIMUM (time_t))
-                   return decode_time_range;
-                 s--;
-                 ns = BILLION - ns;
-               }
-           }
-       }
-
-      if (! *p)
-       {
-         ts->tv_sec = s;
-         ts->tv_nsec = ns;
-         return decode_time_success;
-       }
+       ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
+               keyword, arg));
+      return false;
     }
 
-  return decode_time_bad_header;
+  *ts = t;
+  return true;
 }
 
-static bool
-decode_time (struct timespec *ts, char const *arg, char const *keyword)
+static void
+code_signed_num (uintmax_t value, char const *keyword,
+                intmax_t minval, uintmax_t maxval, struct xheader *xhdr)
 {
-  switch (_decode_time (ts, arg, keyword))
-    {
-    case decode_time_success:
-      return true;
-    case decode_time_bad_header:
-      ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
-             keyword, arg));
-      return false;
-    case decode_time_range:
-      out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
-                          TYPE_MAXIMUM (time_t));
-      return false;
-    }
-  return true;
+  char sbuf[SYSINT_BUFSIZE];
+  xheader_print (xhdr, keyword, sysinttostr (value, minval, maxval, sbuf));
 }
 
 static void
 code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
 {
-  char sbuf[UINTMAX_STRSIZE_BOUND];
-  xheader_print (xhdr, keyword, umaxtostr (value, sbuf));
+  code_signed_num (value, keyword, 0, UINTMAX_MAX, xhdr);
 }
 
 static bool
-decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
-           char const *keyword)
+decode_signed_num (intmax_t *num, char const *arg,
+                  intmax_t minval, uintmax_t maxval,
+                  char const *keyword)
 {
-  uintmax_t u;
   char *arg_lim;
+  intmax_t u = strtosysint (arg, &arg_lim, minval, maxval);
 
-  if (! (ISDIGIT (*arg)
-        && (errno = 0, u = strtoumax (arg, &arg_lim, 10), !*arg_lim)))
+  if (errno == EINVAL || *arg_lim)
     {
       ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
              keyword, arg));
       return false;
     }
 
-  if (! (u <= maxval && errno != ERANGE))
+  if (errno == ERANGE)
     {
-      out_of_range_header (keyword, arg, 0, maxval);
+      out_of_range_header (keyword, arg, minval, maxval);
       return false;
     }
 
@@ -1219,6 +1139,17 @@ decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
   return true;
 }
 
+static bool
+decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
+           char const *keyword)
+{
+  intmax_t i;
+  if (! decode_signed_num (&i, arg, 0, maxval, keyword))
+    return false;
+  *num = i;
+  return true;
+}
+
 static void
 dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
             char const *keyword __attribute__ ((unused)),
@@ -1257,7 +1188,8 @@ static void
 gid_coder (struct tar_stat_info const *st, char const *keyword,
           struct xheader *xhdr, void const *data __attribute__ ((unused)))
 {
-  code_num (st->stat.st_gid, keyword, xhdr);
+  code_signed_num (st->stat.st_gid, keyword,
+                  TYPE_MINIMUM (gid_t), TYPE_MAXIMUM (gid_t), xhdr);
 }
 
 static void
@@ -1266,8 +1198,9 @@ gid_decoder (struct tar_stat_info *st,
             char const *arg,
             size_t size __attribute__((unused)))
 {
-  uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), keyword))
+  intmax_t u;
+  if (decode_signed_num (&u, arg, TYPE_MINIMUM (gid_t),
+                        TYPE_MAXIMUM (gid_t), keyword))
     st->stat.st_gid = u;
 }
 
@@ -1380,7 +1313,8 @@ static void
 uid_coder (struct tar_stat_info const *st, char const *keyword,
           struct xheader *xhdr, void const *data __attribute__ ((unused)))
 {
-  code_num (st->stat.st_uid, keyword, xhdr);
+  code_signed_num (st->stat.st_uid, keyword,
+                  TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t), xhdr);
 }
 
 static void
@@ -1389,8 +1323,9 @@ uid_decoder (struct tar_stat_info *st,
             char const *arg,
             size_t size __attribute__((unused)))
 {
-  uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), keyword))
+  intmax_t u;
+  if (decode_signed_num (&u, arg, TYPE_MINIMUM (uid_t),
+                        TYPE_MAXIMUM (uid_t), keyword))
     st->stat.st_uid = u;
 }
 
@@ -1512,7 +1447,7 @@ sparse_map_decoder (struct tar_stat_info *st,
   st->sparse_map_avail = 0;
   while (1)
     {
-      uintmax_t u;
+      intmax_t u;
       char *delim;
       struct sp_array e;
 
@@ -1524,11 +1459,16 @@ sparse_map_decoder (struct tar_stat_info *st,
        }
 
       errno = 0;
-      u = strtoumax (arg, &delim, 10);
+      u = strtoimax (arg, &delim, 10);
+      if (TYPE_MAXIMUM (off_t) < u)
+       {
+         u = TYPE_MAXIMUM (off_t);
+         errno = ERANGE;
+       }
       if (offset)
        {
          e.offset = u;
-         if (!(u == e.offset && errno != ERANGE))
+         if (errno == ERANGE)
            {
              out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
              return;
@@ -1537,7 +1477,7 @@ sparse_map_decoder (struct tar_stat_info *st,
       else
        {
          e.numbytes = u;
-         if (!(u == e.numbytes && errno != ERANGE))
+         if (errno == ERANGE)
            {
              out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
              return;
This page took 0.028768 seconds and 4 git commands to generate.