]> Dogcows Code - chaz/tar/blobdiff - src/create.c
(create_archive): Exclude pathnames if any of their components are
[chaz/tar] / src / create.c
index d5c8c9204987f09259b0b939ec4a1dafe459fd63..a7d134495caba826d63b15dd5d82d8ee42183b87 100644 (file)
@@ -1,5 +1,5 @@
 /* Create a tar archive.
-   Copyright (C) 1985, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
+   Copyright 1985, 92, 93, 94, 96, 97, 1999 Free Software Foundation, Inc.
    Written by John Gilmore, on 1985-08-25.
 
    This program is free software; you can redistribute it and/or modify it
@@ -14,7 +14,7 @@
 
    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.,
-   59 Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "system.h"
 
@@ -57,23 +57,34 @@ struct link *linklist = NULL;       /* points to first link in list */
 \f
 
 /*------------------------------------------------------------------------.
-| Convert VALUE into a size-SIZE field at WHERE, including a             |
+| 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!     |
 `------------------------------------------------------------------------*/
 
-/* This should be equivalent to: sprintf (WHERE, "%*lo ", SIZE - 1, VALUE);
-   except that we don't assume VALUE fits in an unsigned long, and
-   except that sprintf fills in the trailing NUL and we don't.  */
+/* Output VALUE in octal, 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 SIZE - 1 octal digits (with leading '0's), followed by '\0';
+   but if SIZE octal digits would fit, omit the '\0'.  */
 
 static void
-to_oct (uintmax_t value, char *where, size_t size, const char *type)
+to_oct (uintmax_t value, uintmax_t substitute, char *where, size_t size, const char *type)
 {
   uintmax_t v = value;
   size_t i = size;
-  where[--i] = ' ';            /* put in the space, though */
+
+# 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.  */
 
@@ -84,62 +95,103 @@ to_oct (uintmax_t value, char *where, size_t size, const char *type)
     }
   while (i != 0 && v != 0);
 
-  /* Leading spaces, if necessary.  */
+  /* Leading zeros, if necessary.  */
   while (i != 0)
-    where[--i] = ' ';
+    where[--i] = '0';
 
   if (v != 0)
     {
-      char buf[UINTMAX_STRSIZE_BOUND];
-      ERROR ((0, 0, _("%s value %s is too large to fit in a %u-bit field"),
-             type, STRINGIFY_BIGINT (value, buf),
-             (unsigned) ((size - 1) * 3)));
+      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);
+      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);
+       }
+      else
+       ERROR ((0, 0, _("%s value %s too large (max=%s)"),
+               type, value_string, maxval_string));
     }
 }
+#ifndef GID_NOBODY
+#define GID_NOBODY 0
+#endif
 void
 gid_to_oct (gid_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "gid_t");
+  to_oct ((uintmax_t) v, (uintmax_t) GID_NOBODY, p, s, "gid_t");
 }
 void
 major_to_oct (major_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "major_t");
+  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "major_t");
 }
 void
 minor_to_oct (minor_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "minor_t");
+  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "minor_t");
 }
 void
 mode_to_oct (mode_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "mode_t");
+  /* 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
+      && 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");
 }
 void
 off_to_oct (off_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "off_t");
+  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "off_t");
 }
 void
 size_to_oct (size_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "size_t");
+  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "size_t");
 }
 void
 time_to_oct (time_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "time_t");
+  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "time_t");
 }
+#ifndef UID_NOBODY
+#define UID_NOBODY 0
+#endif
 void
 uid_to_oct (uid_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "uid_t");
+  to_oct ((uintmax_t) v, (uintmax_t) UID_NOBODY, p, s, "uid_t");
 }
 void
 uintmax_to_oct (uintmax_t v, char *p, size_t s)
 {
-  to_oct (v, p, s, "uintmax_t");
+  to_oct (v, (uintmax_t) 0, p, s, "uintmax_t");
 }
 \f
 /* Writing routines.  */
@@ -275,7 +327,7 @@ Removing leading `/' from absolute path names in the archive")));
   if (group_option != (gid_t) -1)
     st->st_gid = group_option;
   if (mode_option)
-    st->st_mode = ((st->st_mode & S_IFMT)
+    st->st_mode = ((st->st_mode & ~MODE_ALL)
                   | mode_adjust (st->st_mode, mode_option));
 
   /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
@@ -302,7 +354,7 @@ 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 & 07777, header->header.mode);
+    MODE_TO_OCT (st->st_mode & MODE_ALL, header->header.mode);
   else
     MODE_TO_OCT (st->st_mode, header->header.mode);
 
@@ -373,16 +425,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, a space, then a null.  We use to_oct then write the null in
-     over to_oct's space.  The final space is already there, from
+     digits, then a null.  We use to_oct.
+     The final space is already there, from
      checksumming, and to_oct 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);
-  header->header.chksum[6] = '\0';     /* zap the space */
+  uintmax_to_oct ((uintmax_t) sum, header->header.chksum, 7);
 
   set_next_block_after (header);
 
@@ -489,7 +540,7 @@ deal_with_sparse (char *name, union block *header)
   init_sparsearray ();
   clear_buffer (buffer);
 
-  while (count = read (file, buffer, sizeof buffer), count != 0)
+  while (count = safe_read (file, buffer, sizeof buffer), count != 0)
     {
       /* Realloc the scratch area as necessary.  FIXME: should reallocate
         only at beginning of a new instance of non-zero data.  */
@@ -591,7 +642,7 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
          break;
        }
 
-      if (lseek (file, sparsearray[sparse_index++].offset, 0) < 0)
+      if (lseek (file, sparsearray[sparse_index++].offset, SEEK_SET) < 0)
        {
          char buf[UINTMAX_STRSIZE_BOUND];
          ERROR ((0, errno, _("lseek error at byte %s in file %s"),
@@ -608,8 +659,8 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
 #if 0
          if (amount_read)
            {
-             count = read (file, start->buffer + amount_read,
-                           BLOCKSIZE - amount_read);
+             count = safe_read (file, start->buffer + amount_read,
+                                BLOCKSIZE - amount_read);
              bufsize -= BLOCKSIZE - amount_read;
              amount_read = 0;
              set_next_block_after (start);
@@ -619,7 +670,7 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
 #endif
          /* Store the data.  */
 
-         count = read (file, start->buffer, BLOCKSIZE);
+         count = safe_read (file, start->buffer, BLOCKSIZE);
          if (count < 0)
            {
              char buf[UINTMAX_STRSIZE_BOUND];
@@ -640,7 +691,7 @@ Read error at byte %s, reading %lu bytes, in file %s"),
        char buffer[BLOCKSIZE];
 
        clear_buffer (buffer);
-       count = read (file, buffer, bufsize);
+       count = safe_read (file, buffer, bufsize);
        memcpy (start->buffer, buffer, BLOCKSIZE);
       }
 
@@ -704,7 +755,8 @@ create_archive (void)
       collect_and_sort_names ();
 
       while (p = name_from_list (), p)
-       dump_file (p, (dev_t) -1, 1);
+       if (!excluded_pathname (excluded, p))
+         dump_file (p, (dev_t) -1, 1);
 
       blank_name_list ();
       while (p = name_from_list (), p)
@@ -729,7 +781,8 @@ create_archive (void)
   else
     {
       while (p = name_next (1), p)
-       dump_file (p, (dev_t) -1, 1);
+       if (!excluded_pathname (excluded, p))
+         dump_file (p, (dev_t) -1, 1);
     }
 
   write_eot ();
@@ -758,6 +811,7 @@ dump_file (char *p, dev_t parent_device, int top_level)
   union block *exhdr;
   char save_typeflag;
   struct utimbuf restore_times;
+  off_t restore_size;
 
   /* FIXME: `header' and `upperbound' might be used uninitialized in this
      function.  Reported by Bruno Haible.  */
@@ -769,7 +823,7 @@ dump_file (char *p, dev_t parent_device, int top_level)
      Otherwise, use lstat (which falls back to stat if no symbolic links).  */
 
   if (dereference_option != 0
-#ifdef STX_HIDDEN              /* AIX */
+#if STX_HIDDEN && !_LARGE_FILES /* AIX */
       ? statx (p, &current_stat, STATSIZE, STX_HIDDEN)
       : statx (p, &current_stat, STATSIZE, STX_HIDDEN | STX_LINK)
 #else
@@ -785,6 +839,7 @@ dump_file (char *p, dev_t parent_device, int top_level)
 
   restore_times.actime = current_stat.st_atime;
   restore_times.modtime = current_stat.st_mtime;
+  restore_size = current_stat.st_size;
 
 #ifdef S_ISHIDDEN
   if (S_ISHIDDEN (current_stat.st_mode))
@@ -1030,7 +1085,8 @@ Removing leading `/' from absolute links")));
         files when archive is meant for /dev/null.  */
 
       if (dev_null_output
-         || (sizeleft == 0 && 0444 == (0444 & current_stat.st_mode)))
+         || (sizeleft == 0
+             && MODE_R == (MODE_R & current_stat.st_mode)))
        f = -1;
       else
        {
@@ -1113,7 +1169,8 @@ Removing leading `/' from absolute links")));
        }
       if (save_typeflag == GNUTYPE_SPARSE)
        {
-         if (finish_sparse_file (f, &sizeleft, current_stat.st_size, p))
+         if (f < 0
+             || finish_sparse_file (f, &sizeleft, current_stat.st_size, p))
            goto padit;
        }
       else
@@ -1142,7 +1199,7 @@ Removing leading `/' from absolute links")));
            if (f < 0)
              count = bufsize;
            else
-             count = read (f, start->buffer, bufsize);
+             count = safe_read (f, start->buffer, bufsize);
            if (count < 0)
              {
                char buf[UINTMAX_STRSIZE_BOUND];
@@ -1176,7 +1233,14 @@ Read error at byte %s, reading %lu bytes, in file %s"),
 
       if (f >= 0)
        {
-         close (f);
+         struct stat final_stat;
+         if (fstat (f, &final_stat) != 0)
+           ERROR ((0, errno, "%s: fstat", p));
+         else if (final_stat.st_mtime != restore_times.modtime
+                  || final_stat.st_size != restore_size)
+           ERROR ((0, errno, _("%s: file changed as we read it"), p));
+         if (close (f) != 0)
+           ERROR ((0, errno, _("%s: close"), p));
          if (atime_preserve_option)
            utime (p, &restore_times);
        }
@@ -1416,9 +1480,10 @@ Read error at byte %s, reading %lu bytes, in file %s"),
 
       while (entry = readdir (directory), entry)
        {
-         /* Skip `.' and `..'.  */
+         /* Skip `.', `..', and excluded file names.  */
 
-         if (is_dot_or_dotdot (entry->d_name))
+         if (is_dot_or_dotdot (entry->d_name)
+             || excluded_filename (excluded, entry->d_name))
            continue;
 
          if ((int) NAMLEN (entry) + len >= buflen)
@@ -1433,8 +1498,6 @@ Read error at byte %s, reading %lu bytes, in file %s"),
 #endif
            }
          strcpy (namebuf + len, entry->d_name);
-         if (exclude_option && check_exclude (namebuf))
-           continue;
          dump_file (namebuf, our_device, 0);
        }
 
@@ -1455,9 +1518,7 @@ Read error at byte %s, reading %lu bytes, in file %s"),
     type = BLKTYPE;
 #endif
 
-  /* Avoid screwy apollo lossage where S_IFIFO == S_IFSOCK.  */
-
-#if (_ISP__M68K == 0) && (_ISP__A88K == 0) && defined(S_ISFIFO)
+#ifdef S_ISFIFO
   else if (S_ISFIFO (current_stat.st_mode))
     type = FIFOTYPE;
 #endif
@@ -1483,7 +1544,7 @@ Read error at byte %s, reading %lu bytes, in file %s"),
 
   header->header.typeflag = type;
 
-#if defined(S_IFBLK) || defined(S_IFCHR)
+#if defined S_ISBLK || defined S_ISCHR
   if (type != FIFOTYPE)
     {
       MAJOR_TO_OCT (major (current_stat.st_rdev), header->header.devmajor);
This page took 0.029895 seconds and 4 git commands to generate.