]> Dogcows Code - chaz/tar/commitdiff
(base_64_digits): New constant.
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 11 Aug 1999 12:47:01 +0000 (12:47 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 11 Aug 1999 12:47:01 +0000 (12:47 +0000)
(base_8_digits): New macro.
(MAX_VAL_WITH_DIGITS): New macro.
(to_base): Renamed from to_oct.  Support base 64 too.
New parameters specifying bits per digit and digits.
Remove `type' parameter.  The result is now undefined if it doesn't fit;
it's the caller's responsibility to check this.
(to_chars): Other half of old to_oct, for 64-bit support.
Mostly a new function.
(GID_NOBODY, UID_NOBODY): Don't define if the headers don't.
(gid_substitute, uid_substitute): Look up names dynamically if
GID_NOBODY and UID_NOBODY aren't defined; use -2 if all else fails.
(mode_to_chars): Renamed from mode_to_oct.
Support negative values in all the _to_chars functions.
(start_header): Use FILESYSTEM_PREFIX_LEN instead of MSDOS ifdef.
Abort if archive format is DEFAULT_FORMAT when it shouldn't be.
(dump_file): Inspect entire pathname, not just new file name
component, when deciding whether to exclude it.

src/create.c

index 9769d0b245b12ee57714a20fa56106af7c34d6ad..c6d78b280e9399f45881a8ac93e4230c62670b93 100644 (file)
@@ -55,143 +55,233 @@ struct link
 
 struct link *linklist = NULL;  /* points to first link in list */
 \f
-
-/*------------------------------------------------------------------------.
-| Convert VALUE (with substitute SUBSTITUTE if VALUE is out of range)    |
-| into a size-SIZE field at WHERE, including a                           |
-| trailing space.  For example, 3 for SIZE means two digits and a space.  |
-|                                                                         |
-| We assume the trailing NUL is already there and don't fill it in.  This |
-| fact is used by start_header and finish_header, so don't change it!     |
-`------------------------------------------------------------------------*/
-
-/* Output VALUE in octal, using SUBSTITUTE if value won't fit.
+/* Base 64 digits; see Internet RFC 2045 Table 1.  */
+char const base_64_digits[64] =
+{
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+#define base_8_digits (base_64_digits + 26 * 2)
+
+/* The maximum uintmax_t value that can be represented with DIGITS digits,
+   assuming that each digit is BITS_PER_DIGIT wide.  */
+#define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
+   ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
+    ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
+    : (uintmax_t) -1)
+
+/* Convert VALUE to a representation suitable for tar headers,
+   using base 1 << BITS_PER_DIGIT.
+   Use the digits in DIGIT_CHAR[0] ... DIGIT_CHAR[base - 1].
    Output to buffer WHERE with size SIZE.
-   TYPE is the kind of value being output (useful for diagnostics).
-   Prefer SIZE - 1 octal digits (with leading '0's), followed by '\0';
-   but if SIZE octal digits would fit, omit the '\0'.  */
+   The result is undefined if SIZE is 0 or if VALUE is too large to fit.  */
 
 static void
-to_oct (uintmax_t value, uintmax_t substitute, char *where, size_t size, const char *type)
+to_base (uintmax_t value, int bits_per_digit, char const *digit_char,
+        char *where, size_t size)
 {
   uintmax_t v = value;
   size_t i = size;
-
-# define MAX_OCTAL_VAL_WITH_DIGITS(digits) \
-    ((digits) * 3 < sizeof (uintmax_t) * CHAR_BIT \
-     ? ((uintmax_t) 1 << ((digits) * 3)) - 1 \
-     : (uintmax_t) -1)
-
-  /* Output a trailing NUL unless the value is too large.  */
-  if (value <= MAX_OCTAL_VAL_WITH_DIGITS (size - 1))
-    where[--i] = '\0';
-
-  /* Produce the digits -- at least one.  */
+  unsigned digit_mask = (1 << bits_per_digit) - 1;
 
   do
     {
-      where[--i] = '0' + (int) (v & 7);        /* one octal digit */
-      v >>= 3;
+      where[--i] = digit_char[v & digit_mask];
+      v >>= bits_per_digit;
     }
-  while (i != 0 && v != 0);
+  while (i);
+}
 
-  /* Leading zeros, if necessary.  */
-  while (i != 0)
-    where[--i] = '0';
+/* NEGATIVE is nonzero if VALUE was negative before being cast to
+   uintmax_t; its original bitpattern can be deduced from VALSIZE, its
+   original size before casting.  Convert VALUE to external form,
+   using SUBSTITUTE (...)  if VALUE won't fit.  Output to buffer WHERE
+   with size SIZE.  TYPE is the kind of value being output (useful for
+   diagnostics).  Prefer the POSIX format of SIZE - 1 octal digits
+   (with leading zero digits), followed by '\0'.  If this won't work,
+   and if GNU format is allowed, use '+' or '-' followed by SIZE - 1
+   base-64 digits.  If neither format works, use SUBSTITUTE (...)
+   instead.  Pass to SUBSTITUTE the address of an 0-or-1 flag
+   recording whether the substitute value is negative.  */
 
-  if (v != 0)
+static void
+to_chars (int negative, uintmax_t value, size_t valsize,
+         uintmax_t (*substitute) PARAMS ((int *)),
+         char *where, size_t size, const char *type)
+{
+  uintmax_t v = negative ? -value : value;
+
+  if (! negative && v <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
     {
-      uintmax_t maxval = MAX_OCTAL_VAL_WITH_DIGITS (size);
-      char buf1[UINTMAX_STRSIZE_BOUND];
-      char buf2[UINTMAX_STRSIZE_BOUND];
-      char buf3[UINTMAX_STRSIZE_BOUND];
-      char *value_string = STRINGIFY_BIGINT (value, buf1);
-      char *maxval_string = STRINGIFY_BIGINT (maxval, buf2);
+      where[size - 1] = '\0';
+      to_base (v, LG_8, base_8_digits, where, size - 1);
+    }
+  else if (v <= MAX_VAL_WITH_DIGITS (size - 1, LG_64)
+          && archive_format == GNU_FORMAT)
+    {
+      where[0] = negative ? '-' : '+';
+      to_base (v, LG_64, base_64_digits, where + 1, size - 1);
+    }
+  else if (negative
+          && archive_format != GNU_FORMAT
+          && valsize * CHAR_BIT <= (size - 1) * LG_8)
+    {
+      where[size - 1] = '\0';
+      to_base (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
+              LG_8, base_8_digits, where, size - 1);
+    }
+  else
+    {
+      uintmax_t maxval = (archive_format == GNU_FORMAT
+                         ? MAX_VAL_WITH_DIGITS (size - 1, LG_64)
+                         : MAX_VAL_WITH_DIGITS (size - 1, LG_8));
+      char buf1[UINTMAX_STRSIZE_BOUND + 1];
+      char buf2[UINTMAX_STRSIZE_BOUND + 1];
+      char buf3[UINTMAX_STRSIZE_BOUND + 1];
+      char *value_string = STRINGIFY_BIGINT (v, buf1 + 1);
+      char *maxval_string = STRINGIFY_BIGINT (maxval, buf2 + 1);
+      char const *minval_string =
+       (archive_format == GNU_FORMAT
+        ? "0"
+        : (maxval_string[-1] = '-', maxval_string - 1));
+      if (negative)
+       *--value_string = '-';
       if (substitute)
        {
-         substitute &= maxval;
-         WARN ((0, 0, _("%s value %s too large (max=%s); substituting %s"),
-                type, value_string, maxval_string,
-                STRINGIFY_BIGINT (substitute, buf3)));
-         to_oct (substitute, (uintmax_t) 0, where, size, type);
+         int negsub;
+         uintmax_t sub = substitute (&negsub) & maxval;
+         uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? -sub : sub;
+         char *sub_string = STRINGIFY_BIGINT (s, buf3 + 1);
+         if (negsub)
+           *--sub_string = '-';
+         WARN ((0, 0, _("%s value %s out of range %s..%s; substituting %s"),
+                type, value_string, minval_string, maxval_string,
+                sub_string));
+         to_chars (negsub, s, valsize, NULL, where, size, type);
        }
       else
-       ERROR ((0, 0, _("%s value %s too large (max=%s)"),
-               type, value_string, maxval_string));
+       ERROR ((0, 0, _("%s value %s out of range %s..%s"),
+               type, value_string, minval_string, maxval_string));
     }
 }
-#ifndef GID_NOBODY
-#define GID_NOBODY 0
+
+static uintmax_t
+gid_substitute (int *negative)
+{
+  gid_t r;
+#ifdef GID_NOBODY
+  r = GID_NOBODY;
+#else
+  static gid_t gid_nobody;
+  if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
+    gid_nobody = -2;
+  r = gid_nobody;
 #endif
+  *negative = r < 0;
+  return r;
+}
+
 void
-gid_to_oct (gid_t v, char *p, size_t s)
+gid_to_chars (gid_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) GID_NOBODY, p, s, "gid_t");
+  to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
 }
+
 void
-major_to_oct (major_t v, char *p, size_t s)
+major_to_chars (major_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "major_t");
+  to_chars (v < 0, (uintmax_t) v, sizeof v, NULL, p, s, "major_t");
 }
+
 void
-minor_to_oct (minor_t v, char *p, size_t s)
+minor_to_chars (minor_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "minor_t");
+  to_chars (v < 0, (uintmax_t) v, sizeof v, NULL, p, s, "minor_t");
 }
+
 void
-mode_to_oct (mode_t v, char *p, size_t s)
+mode_to_chars (mode_t v, char *p, size_t s)
 {
   /* In the common case where the internal and external mode bits are the same,
      propagate all unknown bits to the external mode.
      This matches historical practice.
      Otherwise, just copy the bits we know about.  */
-  uintmax_t u =
-    ((S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
+  int negative;
+  uintmax_t u;
+  if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
       && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
       && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
       && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC)
-     ? v
-     : ((v & S_ISUID ? TSUID : 0)
-       | (v & S_ISGID ? TSGID : 0)
-       | (v & S_ISVTX ? TSVTX : 0)
-       | (v & S_IRUSR ? TUREAD : 0)
-       | (v & S_IWUSR ? TUWRITE : 0)
-       | (v & S_IXUSR ? TUEXEC : 0)
-       | (v & S_IRGRP ? TGREAD : 0)
-       | (v & S_IWGRP ? TGWRITE : 0)
-       | (v & S_IXGRP ? TGEXEC : 0)
-       | (v & S_IROTH ? TOREAD : 0)
-       | (v & S_IWOTH ? TOWRITE : 0)
-       | (v & S_IXOTH ? TOEXEC : 0)));
-  to_oct (u, (uintmax_t) 0, p, s, "mode_t");
+    {
+      negative = v < 0;
+      u = v;
+    }
+  else
+    {
+      negative = 0;
+      u = ((v & S_ISUID ? TSUID : 0)
+          | (v & S_ISGID ? TSGID : 0)
+          | (v & S_ISVTX ? TSVTX : 0)
+          | (v & S_IRUSR ? TUREAD : 0)
+          | (v & S_IWUSR ? TUWRITE : 0)
+          | (v & S_IXUSR ? TUEXEC : 0)
+          | (v & S_IRGRP ? TGREAD : 0)
+          | (v & S_IWGRP ? TGWRITE : 0)
+          | (v & S_IXGRP ? TGEXEC : 0)
+          | (v & S_IROTH ? TOREAD : 0)
+          | (v & S_IWOTH ? TOWRITE : 0)
+          | (v & S_IXOTH ? TOEXEC : 0));
+    }
+  to_chars (negative, u, sizeof v, NULL, p, s, "mode_t");
 }
+
 void
-off_to_oct (off_t v, char *p, size_t s)
+off_to_chars (off_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "off_t");
+  to_chars (v < 0, (uintmax_t) v, sizeof v, NULL, p, s, "off_t");
 }
+
 void
-size_to_oct (size_t v, char *p, size_t s)
+size_to_chars (size_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "size_t");
+  to_chars (0, (uintmax_t) v, sizeof v, NULL, p, s, "size_t");
 }
+
 void
-time_to_oct (time_t v, char *p, size_t s)
+time_to_chars (time_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "time_t");
+  to_chars (v < 0, (uintmax_t) v, sizeof v, NULL, p, s, "time_t");
 }
-#ifndef UID_NOBODY
-#define UID_NOBODY 0
+
+static uintmax_t
+uid_substitute (int *negative)
+{
+  uid_t r;
+#ifdef UID_NOBODY
+  r = UID_NOBODY;
+#else
+  static uid_t uid_nobody;
+  if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody))
+    uid_nobody = -2;
+  r = uid_nobody;
 #endif
+  *negative = r < 0;
+  return r;
+}
+
 void
-uid_to_oct (uid_t v, char *p, size_t s)
+uid_to_chars (uid_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) UID_NOBODY, p, s, "uid_t");
+  to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
 }
+
 void
-uintmax_to_oct (uintmax_t v, char *p, size_t s)
+uintmax_to_chars (uintmax_t v, char *p, size_t s)
 {
-  to_oct (v, (uintmax_t) 0, p, s, "uintmax_t");
+  to_chars (0, v, sizeof v, NULL, p, s, "uintmax_t");
 }
 \f
 /* Writing routines.  */
@@ -283,18 +373,17 @@ start_header (const char *name, struct stat *st)
   if (!absolute_names_option)
     {
       static int warned_once = 0;
+      size_t prefix_len = FILESYSTEM_PREFIX_LEN (name);
 
-#if MSDOS
-      if (name[1] == ':')
+      if (prefix_len)
        {
-         name += 2;
+         name += prefix_len;
          if (!warned_once)
            {
              warned_once = 1;
-             WARN ((0, 0, _("Removing drive spec from names in the archive")));
+             WARN ((0, 0, _("Removing filesystem prefix from names in the archive")));
            }
        }
-#endif
 
       while (*name == '/')
        {
@@ -354,27 +443,26 @@ Removing leading `/' from absolute path names in the archive")));
      acceptor for Paul's test.  */
 
   if (archive_format == V7_FORMAT)
-    MODE_TO_OCT (st->st_mode & MODE_ALL, header->header.mode);
+    MODE_TO_CHARS (st->st_mode & MODE_ALL, header->header.mode);
   else
-    MODE_TO_OCT (st->st_mode, header->header.mode);
+    MODE_TO_CHARS (st->st_mode, header->header.mode);
 
-  UID_TO_OCT (st->st_uid, header->header.uid);
-  GID_TO_OCT (st->st_gid, header->header.gid);
-  OFF_TO_OCT (st->st_size, header->header.size);
-  TIME_TO_OCT (st->st_mtime, header->header.mtime);
+  UID_TO_CHARS (st->st_uid, header->header.uid);
+  GID_TO_CHARS (st->st_gid, header->header.gid);
+  OFF_TO_CHARS (st->st_size, header->header.size);
+  TIME_TO_CHARS (st->st_mtime, header->header.mtime);
 
   if (incremental_option)
     if (archive_format == OLDGNU_FORMAT)
       {
-       TIME_TO_OCT (st->st_atime, header->oldgnu_header.atime);
-       TIME_TO_OCT (st->st_ctime, header->oldgnu_header.ctime);
+       TIME_TO_CHARS (st->st_atime, header->oldgnu_header.atime);
+       TIME_TO_CHARS (st->st_ctime, header->oldgnu_header.ctime);
       }
 
   header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
 
   switch (archive_format)
     {
-    case DEFAULT_FORMAT:
     case V7_FORMAT:
       break;
 
@@ -388,6 +476,9 @@ Removing leading `/' from absolute path names in the archive")));
       strncpy (header->header.magic, TMAGIC, TMAGLEN);
       strncpy (header->header.version, TVERSION, TVERSLEN);
       break;
+
+    default:
+      abort ();
     }
 
   if (archive_format == V7_FORMAT || numeric_owner_option)
@@ -425,15 +516,15 @@ finish_header (union block *header)
 
   /* Fill in the checksum field.  It's formatted differently from the
      other fields: it has [6] digits, a null, then a space -- rather than
-     digits, then a null.  We use to_oct.
+     digits, then a null.  We use to_chars.
      The final space is already there, from
-     checksumming, and to_oct doesn't modify it.
+     checksumming, and to_chars doesn't modify it.
 
      This is a fast way to do:
 
      sprintf(header->header.chksum, "%6o", sum);  */
 
-  uintmax_to_oct ((uintmax_t) sum, header->header.chksum, 7);
+  uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
 
   set_next_block_after (header);
 
@@ -755,7 +846,7 @@ create_archive (void)
       collect_and_sort_names ();
 
       while (p = name_from_list (), p)
-       if (!excluded_pathname (excluded, p))
+       if (!excluded_name (p))
          dump_file (p, (dev_t) -1, 1);
 
       blank_name_list ();
@@ -781,7 +872,7 @@ create_archive (void)
   else
     {
       while (p = name_next (1), p)
-       if (!excluded_pathname (excluded, p))
+       if (!excluded_name (p))
          dump_file (p, (dev_t) -1, 1);
     }
 
@@ -1040,8 +1131,8 @@ Removing leading `/' from absolute links")));
                 <file>.  It might be kind of disconcerting if the
                 shrunken file size was the one that showed up.  */
 
-             OFF_TO_OCT (current_stat.st_size,
-                         header->oldgnu_header.realsize);
+             OFF_TO_CHARS (current_stat.st_size,
+                           header->oldgnu_header.realsize);
 
              /* This will be the new "size" of the file, i.e., the size
                 of the file minus the blocks of holes that we're
@@ -1049,17 +1140,17 @@ Removing leading `/' from absolute links")));
 
              find_new_file_size (&filesize, upperbound);
              current_stat.st_size = filesize;
-             OFF_TO_OCT (filesize, header->header.size);
+             OFF_TO_CHARS (filesize, header->header.size);
 
              for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
                {
                  if (!sparsearray[counter].numbytes)
                    break;
 
-                 OFF_TO_OCT (sparsearray[counter].offset,
-                             header->oldgnu_header.sp[counter].offset);
-                 SIZE_TO_OCT (sparsearray[counter].numbytes,
-                              header->oldgnu_header.sp[counter].numbytes);
+                 OFF_TO_CHARS (sparsearray[counter].offset,
+                               header->oldgnu_header.sp[counter].offset);
+                 SIZE_TO_CHARS (sparsearray[counter].numbytes,
+                                header->oldgnu_header.sp[counter].numbytes);
                }
 
            }
@@ -1136,10 +1227,10 @@ Removing leading `/' from absolute links")));
              if (counter + index_offset > upperbound)
                break;
 
-             SIZE_TO_OCT (sparsearray[counter + index_offset].numbytes,
-                          exhdr->sparse_header.sp[counter].numbytes);
-             OFF_TO_OCT (sparsearray[counter + index_offset].offset,
-                         exhdr->sparse_header.sp[counter].offset);
+             SIZE_TO_CHARS (sparsearray[counter + index_offset].numbytes,
+                            exhdr->sparse_header.sp[counter].numbytes);
+             OFF_TO_CHARS (sparsearray[counter + index_offset].offset,
+                           exhdr->sparse_header.sp[counter].offset);
            }
          set_next_block_after (exhdr);
 #if 0
@@ -1397,7 +1488,7 @@ Read error at byte %s, reading %lu bytes, in file %s"),
              p_buffer += tmp;
            }
          totsize++;
-         OFF_TO_OCT (totsize, header->header.size);
+         OFF_TO_CHARS (totsize, header->header.size);
          finish_header (header);
          p_buffer = buffer;
          sizeleft = totsize;
@@ -1470,8 +1561,7 @@ Read error at byte %s, reading %lu bytes, in file %s"),
        {
          /* Skip `.', `..', and excluded file names.  */
 
-         if (is_dot_or_dotdot (entry->d_name)
-             || excluded_filename (excluded, entry->d_name))
+         if (is_dot_or_dotdot (entry->d_name))
            continue;
 
          if ((int) NAMLEN (entry) + len >= buflen)
@@ -1486,7 +1576,8 @@ Read error at byte %s, reading %lu bytes, in file %s"),
 #endif
            }
          strcpy (namebuf + len, entry->d_name);
-         dump_file (namebuf, our_device, 0);
+         if (!excluded_name (namebuf))
+           dump_file (namebuf, our_device, 0);
        }
 
       closedir (directory);
@@ -1521,8 +1612,8 @@ Read error at byte %s, reading %lu bytes, in file %s"),
 
   if (type != FIFOTYPE)
     {
-      MAJOR_TO_OCT (major (current_stat.st_rdev), header->header.devmajor);
-      MINOR_TO_OCT (minor (current_stat.st_rdev), header->header.devminor);
+      MAJOR_TO_CHARS (major (current_stat.st_rdev), header->header.devmajor);
+      MINOR_TO_CHARS (minor (current_stat.st_rdev), header->header.devminor);
     }
 
   finish_header (header);
This page took 0.044689 seconds and 4 git commands to generate.