]> Dogcows Code - chaz/tar/blobdiff - src/create.c
tar: don't export names that aren't used elsewhere
[chaz/tar] / src / create.c
index 4ff30542ba8fb27e0d7c268ce09c0f8163165f40..fbd7165aceee32e79a193e123148cfddca77dc45 100644 (file)
@@ -1,13 +1,13 @@
 /* Create a tar archive.
 
    Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
 /* Create a tar archive.
 
    Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2009, 2010 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
    under the terms of the GNU General Public License as published by the
 
    Written by John Gilmore, on 1985-08-25.
 
    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 2, or (at your option) any later
+   Free Software Foundation; either version 3, or (at your option) any later
    version.
 
    This program is distributed in the hope that it will be useful, but
    version.
 
    This program is distributed in the hope that it will be useful, but
@@ -58,43 +58,46 @@ add_exclusion_tag (const char *name, enum exclusion_tag_type type,
   exclusion_tags = tag;
 }
 
   exclusion_tags = tag;
 }
 
-static void
+void
 exclusion_tag_warning (const char *dirname, const char *tagname,
                       const char *message)
 {
   if (verbose_option)
 exclusion_tag_warning (const char *dirname, const char *tagname,
                       const char *message)
 {
   if (verbose_option)
-    WARN ((0, 0,
-          _("%s: contains a cache directory tag %s; %s"),
-          quotearg_colon (dirname),
-          quotearg_n (1, tagname),
-          message));
+    WARNOPT (WARN_CACHEDIR,
+            (0, 0,
+             _("%s: contains a cache directory tag %s; %s"),
+             quotearg_colon (dirname),
+             quotearg_n (1, tagname),
+             message));
 }
 
 }
 
-static enum exclusion_tag_type 
-check_exclusion_tags (char *dirname, const char **tag_file_name)
+enum exclusion_tag_type
+check_exclusion_tags (const char *dirname, const char **tag_file_name)
 {
   static char *tagname;
   static size_t tagsize;
   struct exclusion_tag *tag;
   size_t dlen = strlen (dirname);
 {
   static char *tagname;
   static size_t tagsize;
   struct exclusion_tag *tag;
   size_t dlen = strlen (dirname);
-  char *nptr = NULL;
-  char *ret = NULL;
-  
+  int addslash = !ISSLASH (dirname[dlen-1]);
+  size_t noff = 0;
+
   for (tag = exclusion_tags; tag; tag = tag->next)
     {
   for (tag = exclusion_tags; tag; tag = tag->next)
     {
-      size_t size = dlen + tag->length + 1;
+      size_t size = dlen + addslash + tag->length + 1;
       if (size > tagsize)
        {
          tagsize = size;
          tagname = xrealloc (tagname, tagsize);
        }
 
       if (size > tagsize)
        {
          tagsize = size;
          tagname = xrealloc (tagname, tagsize);
        }
 
-      if (!nptr)
+      if (noff == 0)
        {
          strcpy (tagname, dirname);
        {
          strcpy (tagname, dirname);
-         nptr = tagname + dlen;
+         noff = dlen;
+         if (addslash)
+           tagname[noff++] = '/';
        }
        }
-      strcpy (nptr, tag->name);
+      strcpy (tagname + noff, tag->name);
       if (access (tagname, F_OK) == 0
          && (!tag->predicate || tag->predicate (tagname)))
        {
       if (access (tagname, F_OK) == 0
          && (!tag->predicate || tag->predicate (tagname)))
        {
@@ -211,6 +214,14 @@ to_base256 (int negative, uintmax_t value, char *where, size_t size)
   while (i);
 }
 
   while (i);
 }
 
+#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
+#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
+#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
+#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
+#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
+#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
+#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
+#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
 
 static bool
 to_chars (int negative, uintmax_t value, size_t valsize,
 
 static bool
 to_chars (int negative, uintmax_t value, size_t valsize,
@@ -260,7 +271,7 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
 
         1. In OLDGNU_FORMAT all strings in a tar header end in \0
         2. Incremental archives use oldgnu_header.
 
         1. In OLDGNU_FORMAT all strings in a tar header end in \0
         2. Incremental archives use oldgnu_header.
-        
+
         Apart from this they are completely identical. */
       uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
       char subbuf[UINTMAX_STRSIZE_BOUND + 1];
         Apart from this they are completely identical. */
       uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
       char subbuf[UINTMAX_STRSIZE_BOUND + 1];
@@ -365,25 +376,25 @@ gid_substitute (int *negative)
   return r;
 }
 
   return r;
 }
 
-bool
+static bool
 gid_to_chars (gid_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
 }
 
 gid_to_chars (gid_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
 }
 
-bool
+static bool
 major_to_chars (major_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
 }
 
 major_to_chars (major_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
 }
 
-bool
+static bool
 minor_to_chars (minor_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
 }
 
 minor_to_chars (minor_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
 }
 
-bool
+static bool
 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,
 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,
@@ -399,8 +410,7 @@ mode_to_chars (mode_t v, char *p, size_t s)
       && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
       && archive_format != POSIX_FORMAT
       && archive_format != USTAR_FORMAT
       && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
       && archive_format != POSIX_FORMAT
       && archive_format != USTAR_FORMAT
-      && archive_format != GNU_FORMAT
-      && archive_format != OLDGNU_FORMAT)
+      && archive_format != GNU_FORMAT)
     {
       negative = v < 0;
       u = v;
     {
       negative = v < 0;
       u = v;
@@ -458,19 +468,19 @@ uid_substitute (int *negative)
   return r;
 }
 
   return r;
 }
 
-bool
+static bool
 uid_to_chars (uid_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
 }
 
 uid_to_chars (uid_t v, char *p, size_t s)
 {
   return to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
 }
 
-bool
+static bool
 uintmax_to_chars (uintmax_t v, char *p, size_t s)
 {
   return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
 }
 
 uintmax_to_chars (uintmax_t v, char *p, size_t s)
 {
   return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
 }
 
-void
+static void
 string_to_chars (char const *str, char *p, size_t s)
 {
   tar_copy_str (p, str, s);
 string_to_chars (char const *str, char *p, size_t s)
 {
   tar_copy_str (p, str, s);
@@ -485,7 +495,7 @@ string_to_chars (char const *str, char *p, size_t s)
    a) it is empty *and* world-readable, or
    b) current archive is /dev/null */
 
    a) it is empty *and* world-readable, or
    b) current archive is /dev/null */
 
-bool
+static bool
 file_dumpable_p (struct tar_stat_info *st)
 {
   if (dev_null_output)
 file_dumpable_p (struct tar_stat_info *st)
 {
   if (dev_null_output)
@@ -513,9 +523,8 @@ write_eot (void)
 
 /* Write a "private" header */
 union block *
 
 /* Write a "private" header */
 union block *
-start_private_header (const char *name, size_t size)
+start_private_header (const char *name, size_t size, time_t t)
 {
 {
-  time_t t;
   union block *header = find_next_block ();
 
   memset (header->buffer, 0, sizeof (union block));
   union block *header = find_next_block ();
 
   memset (header->buffer, 0, sizeof (union block));
@@ -523,7 +532,6 @@ start_private_header (const char *name, size_t size)
   tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE);
   OFF_TO_CHARS (size, header->header.size);
 
   tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE);
   OFF_TO_CHARS (size, header->header.size);
 
-  time (&t);
   TIME_TO_CHARS (t, header->header.mtime);
   MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
   UID_TO_CHARS (getuid (), header->header.uid);
   TIME_TO_CHARS (t, header->header.mtime);
   MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
   UID_TO_CHARS (getuid (), header->header.uid);
@@ -561,13 +569,13 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
   union block *header;
   char *tmpname;
 
   union block *header;
   char *tmpname;
 
-  header = start_private_header ("././@LongLink", size);
-  FILL(header->header.mtime, '0');
-  FILL(header->header.mode, '0');
-  FILL(header->header.uid, '0');
-  FILL(header->header.gid, '0');
-  FILL(header->header.devmajor, 0);
-  FILL(header->header.devminor, 0);
+  header = start_private_header ("././@LongLink", size, time (NULL));
+  FILL (header->header.mtime, '0');
+  FILL (header->header.mode, '0');
+  FILL (header->header.uid, '0');
+  FILL (header->header.gid, '0');
+  FILL (header->header.devmajor, 0);
+  FILL (header->header.devminor, 0);
   uid_to_uname (0, &tmpname);
   UNAME_TO_CHARS (tmpname, header->header.uname);
   free (tmpname);
   uid_to_uname (0, &tmpname);
   UNAME_TO_CHARS (tmpname, header->header.uname);
   free (tmpname);
@@ -602,8 +610,10 @@ split_long_name (const char *name, size_t length)
 {
   size_t i;
 
 {
   size_t i;
 
-  if (length > PREFIX_FIELD_SIZE)
+  if (length > PREFIX_FIELD_SIZE + 1)
     length = PREFIX_FIELD_SIZE + 1;
     length = PREFIX_FIELD_SIZE + 1;
+  else if (ISSLASH (name[length - 1]))
+    length--;
   for (i = length - 1; i > 0; i--)
     if (ISSLASH (name[i]))
       break;
   for (i = length - 1; i > 0; i--)
     if (ISSLASH (name[i]))
       break;
@@ -614,7 +624,7 @@ static union block *
 write_ustar_long_name (const char *name)
 {
   size_t length = strlen (name);
 write_ustar_long_name (const char *name)
 {
   size_t length = strlen (name);
-  size_t i;
+  size_t i, nlen;
   union block *header;
 
   if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)
   union block *header;
 
   if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)
@@ -626,7 +636,7 @@ write_ustar_long_name (const char *name)
     }
 
   i = split_long_name (name, length);
     }
 
   i = split_long_name (name, length);
-  if (i == 0 || length - i - 1 > NAME_FIELD_SIZE)
+  if (i == 0 || (nlen = length - i - 1) > NAME_FIELD_SIZE || nlen == 0)
     {
       ERROR ((0, 0,
              _("%s: file name is too long (cannot be split); not dumped"),
     {
       ERROR ((0, 0,
              _("%s: file name is too long (cannot be split); not dumped"),
@@ -710,23 +720,26 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header)
   union block *header, hp;
   char *p;
   int type;
   union block *header, hp;
   char *p;
   int type;
+  time_t t;
 
 
-  if (extended_header.buffer || extended_header.stk == NULL)
+  if (st->xhdr.buffer || st->xhdr.stk == NULL)
     return old_header;
 
     return old_header;
 
-  xheader_finish (&extended_header);
+  xheader_finish (&st->xhdr);
   memcpy (hp.buffer, old_header, sizeof (hp));
   if (global)
     {
       type = XGLTYPE;
       p = xheader_ghdr_name ();
   memcpy (hp.buffer, old_header, sizeof (hp));
   if (global)
     {
       type = XGLTYPE;
       p = xheader_ghdr_name ();
+      time (&t);
     }
   else
     {
       type = XHDTYPE;
       p = xheader_xhdr_name (st);
     }
   else
     {
       type = XHDTYPE;
       p = xheader_xhdr_name (st);
+      t = st->stat.st_mtime;
     }
     }
-  xheader_write (type, p, &extended_header);
+  xheader_write (type, p, t, &st->xhdr);
   free (p);
   header = find_next_block ();
   memcpy (header, &hp.buffer, sizeof (hp.buffer));
   free (p);
   header = find_next_block ();
   memcpy (header, &hp.buffer, sizeof (hp.buffer));
@@ -991,11 +1004,9 @@ finish_header (struct tar_stat_info *st,
       && header->header.typeflag != XHDTYPE
       && header->header.typeflag != XGLTYPE)
     {
       && header->header.typeflag != XHDTYPE
       && header->header.typeflag != XGLTYPE)
     {
-      /* These globals are parameters to print_header, sigh.  */
-
-      current_header = header;
+      /* FIXME: This global is used in print_header, sigh.  */
       current_format = archive_format;
       current_format = archive_format;
-      print_header (st, block_ordinal);
+      print_header (st, header, block_ordinal);
     }
 
   header = write_extended (false, st, header);
     }
 
   header = write_extended (false, st, header);
@@ -1009,7 +1020,6 @@ pad_archive (off_t size_left)
   union block *blk;
   while (size_left > 0)
     {
   union block *blk;
   while (size_left > 0)
     {
-      mv_size_left (size_left);
       blk = find_next_block ();
       memset (blk->buffer, 0, BLOCKSIZE);
       set_next_block_after (blk);
       blk = find_next_block ();
       memset (blk->buffer, 0, BLOCKSIZE);
       set_next_block_after (blk);
@@ -1035,13 +1045,11 @@ dump_regular_file (int fd, struct tar_stat_info *st)
 
   finish_header (st, blk, block_ordinal);
 
 
   finish_header (st, blk, block_ordinal);
 
-  mv_begin (st);
+  mv_begin_write (st->file_name, st->stat.st_size, st->stat.st_size);
   while (size_left > 0)
     {
       size_t bufsize, count;
 
   while (size_left > 0)
     {
       size_t bufsize, count;
 
-      mv_size_left (size_left);
-
       blk = find_next_block ();
 
       bufsize = available_space_after (blk);
       blk = find_next_block ();
 
       bufsize = available_space_after (blk);
@@ -1064,22 +1072,22 @@ dump_regular_file (int fd, struct tar_stat_info *st)
          return dump_status_short;
        }
       size_left -= count;
          return dump_status_short;
        }
       size_left -= count;
-      if (count)
-       set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
+      set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
 
       if (count != bufsize)
        {
          char buf[UINTMAX_STRSIZE_BOUND];
          memset (blk->buffer + count, 0, bufsize - count);
 
       if (count != bufsize)
        {
          char buf[UINTMAX_STRSIZE_BOUND];
          memset (blk->buffer + count, 0, bufsize - count);
-         WARN ((0, 0,
-                ngettext ("%s: File shrank by %s byte; padding with zeros",
-                          "%s: File shrank by %s bytes; padding with zeros",
-                          size_left),
-                quotearg_colon (st->orig_file_name),
-                STRINGIFY_BIGINT (size_left, buf)));
-         if (! ignore_failed_read_option) 
-           exit_status = TAREXIT_DIFFERS;
-         pad_archive (size_left - (bufsize-count));
+         WARNOPT (WARN_FILE_SHRANK,
+                  (0, 0,
+                   ngettext ("%s: File shrank by %s byte; padding with zeros",
+                             "%s: File shrank by %s bytes; padding with zeros",
+                             size_left),
+                   quotearg_colon (st->orig_file_name),
+                   STRINGIFY_BIGINT (size_left, buf)));
+         if (! ignore_failed_read_option)
+           set_exit_status (TAREXIT_DIFFERS);
+         pad_archive (size_left - (bufsize - count));
          return dump_status_short;
        }
     }
          return dump_status_short;
        }
     }
@@ -1089,79 +1097,71 @@ dump_regular_file (int fd, struct tar_stat_info *st)
 \f
 static void
 dump_dir0 (char *directory,
 \f
 static void
 dump_dir0 (char *directory,
-          struct tar_stat_info *st, int top_level, dev_t parent_device)
+          struct tar_stat_info *st, bool top_level, dev_t parent_device)
 {
   dev_t our_device = st->stat.st_dev;
   const char *tag_file_name;
 {
   dev_t our_device = st->stat.st_dev;
   const char *tag_file_name;
-  
-  if (!is_avoided_name (st->orig_file_name))
-    {
-      union block *blk = NULL;
-      off_t block_ordinal = current_block_ordinal ();
-      st->stat.st_size = 0;    /* force 0 size on dir */
+  union block *blk = NULL;
+  off_t block_ordinal = current_block_ordinal ();
 
 
-      blk = start_header (st);
-      if (!blk)
-       return;
+  st->stat.st_size = 0;        /* force 0 size on dir */
 
 
-      if (incremental_option && archive_format != POSIX_FORMAT)
-       blk->header.typeflag = GNUTYPE_DUMPDIR;
-      else /* if (standard_option) */
-       blk->header.typeflag = DIRTYPE;
+  blk = start_header (st);
+  if (!blk)
+    return;
+
+  if (incremental_option && archive_format != POSIX_FORMAT)
+    blk->header.typeflag = GNUTYPE_DUMPDIR;
+  else /* if (standard_option) */
+    blk->header.typeflag = DIRTYPE;
 
 
-      /* If we're gnudumping, we aren't done yet so don't close it.  */
+  /* If we're gnudumping, we aren't done yet so don't close it.  */
 
 
-      if (!incremental_option)
-       finish_header (st, blk, block_ordinal);
-      else if (gnu_list_name->dir_contents)
+  if (!incremental_option)
+    finish_header (st, blk, block_ordinal);
+  else if (gnu_list_name->directory)
+    {
+      if (archive_format == POSIX_FORMAT)
        {
        {
-         if (archive_format == POSIX_FORMAT)
-           {
-             xheader_store ("GNU.dumpdir", st, gnu_list_name->dir_contents);
-             finish_header (st, blk, block_ordinal);
-           }
-         else
+         xheader_store ("GNU.dumpdir", st,
+                        safe_directory_contents (gnu_list_name->directory));
+         finish_header (st, blk, block_ordinal);
+       }
+      else
+       {
+         off_t size_left;
+         off_t totsize;
+         size_t bufsize;
+         ssize_t count;
+         const char *buffer, *p_buffer;
+
+         block_ordinal = current_block_ordinal ();
+         buffer = safe_directory_contents (gnu_list_name->directory);
+         totsize = dumpdir_size (buffer);
+         OFF_TO_CHARS (totsize, blk->header.size);
+         finish_header (st, blk, block_ordinal);
+         p_buffer = buffer;
+         size_left = totsize;
+
+         mv_begin_write (st->file_name, totsize, totsize);
+         while (size_left > 0)
            {
            {
-             off_t size_left;
-             off_t totsize;
-             size_t bufsize;
-             ssize_t count;
-             const char *buffer, *p_buffer;
-
-             block_ordinal = current_block_ordinal ();
-             buffer = gnu_list_name->dir_contents;
-             if (buffer)
-               totsize = dumpdir_size (buffer);
-             else
-               totsize = 0;
-             OFF_TO_CHARS (totsize, blk->header.size);
-             finish_header (st, blk, block_ordinal);
-             p_buffer = buffer;
-             size_left = totsize;
-
-             mv_begin (st);
-             mv_total_size (totsize);
-             while (size_left > 0)
+             blk = find_next_block ();
+             bufsize = available_space_after (blk);
+             if (size_left < bufsize)
                {
                {
-                 mv_size_left (size_left);
-                 blk = find_next_block ();
-                 bufsize = available_space_after (blk);
-                 if (size_left < bufsize)
-                   {
-                     bufsize = size_left;
-                     count = bufsize % BLOCKSIZE;
-                     if (count)
-                       memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
-                   }
-                 memcpy (blk->buffer, p_buffer, bufsize);
-                 size_left -= bufsize;
-                 p_buffer += bufsize;
-                 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
+                 bufsize = size_left;
+                 count = bufsize % BLOCKSIZE;
+                 if (count)
+                   memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
                }
                }
-             mv_end ();
+             memcpy (blk->buffer, p_buffer, bufsize);
+             size_left -= bufsize;
+             p_buffer += bufsize;
+             set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
            }
            }
-         return;
        }
        }
+      return;
     }
 
   if (!recursion_option)
     }
 
   if (!recursion_option)
@@ -1172,19 +1172,23 @@ dump_dir0 (char *directory,
       && parent_device != st->stat.st_dev)
     {
       if (verbose_option)
       && parent_device != st->stat.st_dev)
     {
       if (verbose_option)
-       WARN ((0, 0,
-              _("%s: file is on a different filesystem; not dumped"),
-              quotearg_colon (st->orig_file_name)));
+       WARNOPT (WARN_XDEV,
+                (0, 0,
+                 _("%s: file is on a different filesystem; not dumped"),
+                 quotearg_colon (st->orig_file_name)));
     }
   else
     {
       char *name_buf;
       size_t name_size;
     }
   else
     {
       char *name_buf;
       size_t name_size;
-      
+
       switch (check_exclusion_tags (st->orig_file_name, &tag_file_name))
        {
       switch (check_exclusion_tags (st->orig_file_name, &tag_file_name))
        {
-       case exclusion_tag_none:
        case exclusion_tag_all:
        case exclusion_tag_all:
+         /* Handled in dump_file0 */
+         break;
+
+       case exclusion_tag_none:
          {
            char const *entry;
            size_t entry_len;
          {
            char const *entry;
            size_t entry_len;
@@ -1195,7 +1199,6 @@ dump_dir0 (char *directory,
 
            /* Now output all the files in the directory.  */
            /* FIXME: Should speed this up by cd-ing into the dir.  */
 
            /* Now output all the files in the directory.  */
            /* FIXME: Should speed this up by cd-ing into the dir.  */
-
            for (entry = directory; (entry_len = strlen (entry)) != 0;
                 entry += entry_len + 1)
              {
            for (entry = directory; (entry_len = strlen (entry)) != 0;
                 entry += entry_len + 1)
              {
@@ -1206,9 +1209,9 @@ dump_dir0 (char *directory,
                  }
                strcpy (name_buf + name_len, entry);
                if (!excluded_name (name_buf))
                  }
                strcpy (name_buf + name_len, entry);
                if (!excluded_name (name_buf))
-                 dump_file (name_buf, 0, our_device);
+                 dump_file (name_buf, false, our_device);
              }
              }
-           
+
            free (name_buf);
          }
          break;
            free (name_buf);
          }
          break;
@@ -1220,10 +1223,10 @@ dump_dir0 (char *directory,
          name_buf = xmalloc (name_size);
          strcpy (name_buf, st->orig_file_name);
          strcat (name_buf, tag_file_name);
          name_buf = xmalloc (name_size);
          strcpy (name_buf, st->orig_file_name);
          strcat (name_buf, tag_file_name);
-         dump_file (name_buf, 0, our_device);
+         dump_file (name_buf, false, our_device);
          free (name_buf);
          break;
          free (name_buf);
          break;
-      
+
        case exclusion_tag_under:
          exclusion_tag_warning (st->orig_file_name, tag_file_name,
                                 _("contents not dumped"));
        case exclusion_tag_under:
          exclusion_tag_warning (st->orig_file_name, tag_file_name,
                                 _("contents not dumped"));
@@ -1246,7 +1249,8 @@ ensure_slash (char **pstr)
 }
 
 static bool
 }
 
 static bool
-dump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device)
+dump_dir (int fd, struct tar_stat_info *st, bool top_level,
+         dev_t parent_device)
 {
   char *directory = fdsavedir (fd);
   if (!directory)
 {
   char *directory = fdsavedir (fd);
   if (!directory)
@@ -1267,10 +1271,10 @@ dump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device)
 void
 create_archive (void)
 {
 void
 create_archive (void)
 {
-  const char *p;
+  struct name const *p;
 
   open_archive (ACCESS_WRITE);
 
   open_archive (ACCESS_WRITE);
-  xheader_write_global ();
+  buffer_write_global_xheader ();
 
   if (incremental_option)
     {
 
   if (incremental_option)
     {
@@ -1281,24 +1285,24 @@ create_archive (void)
       collect_and_sort_names ();
 
       while ((p = name_from_list ()) != NULL)
       collect_and_sort_names ();
 
       while ((p = name_from_list ()) != NULL)
-       if (!excluded_name (p))
-         dump_file (p, -1, (dev_t) 0);
+       if (!excluded_name (p->name))
+         dump_file (p->name, p->cmdline, (dev_t) 0);
 
       blank_name_list ();
       while ((p = name_from_list ()) != NULL)
 
       blank_name_list ();
       while ((p = name_from_list ()) != NULL)
-       if (!excluded_name (p))
+       if (!excluded_name (p->name))
          {
          {
-           size_t plen = strlen (p);
+           size_t plen = strlen (p->name);
            if (buffer_size <= plen)
              {
                while ((buffer_size *= 2) <= plen)
                  continue;
                buffer = xrealloc (buffer, buffer_size);
              }
            if (buffer_size <= plen)
              {
                while ((buffer_size *= 2) <= plen)
                  continue;
                buffer = xrealloc (buffer, buffer_size);
              }
-           memcpy (buffer, p, plen);
+           memcpy (buffer, p->name, plen);
            if (! ISSLASH (buffer[plen - 1]))
            if (! ISSLASH (buffer[plen - 1]))
-             buffer[plen++] = '/';
-           q = gnu_list_name->dir_contents;
+             buffer[plen++] = DIRECTORY_SEPARATOR;
+           q = directory_contents (gnu_list_name->directory);
            if (q)
              while (*q)
                {
            if (q)
              while (*q)
                {
@@ -1312,7 +1316,7 @@ create_archive (void)
                          buffer = xrealloc (buffer, buffer_size);
                        }
                      strcpy (buffer + plen, q + 1);
                          buffer = xrealloc (buffer, buffer_size);
                        }
                      strcpy (buffer + plen, q + 1);
-                     dump_file (buffer, -1, (dev_t) 0);
+                     dump_file (buffer, false, (dev_t) 0);
                    }
                  q += qlen + 1;
                }
                    }
                  q += qlen + 1;
                }
@@ -1321,14 +1325,15 @@ create_archive (void)
     }
   else
     {
     }
   else
     {
-      while ((p = name_next (1)) != NULL)
-       if (!excluded_name (p))
-         dump_file (p, 1, (dev_t) 0);
+      const char *name;
+      while ((name = name_next (1)) != NULL)
+       if (!excluded_name (name))
+         dump_file (name, true, (dev_t) 0);
     }
 
   write_eot ();
   close_archive ();
     }
 
   write_eot ();
   close_archive ();
-
+  finish_deferred_unlinks ();
   if (listed_incremental_option)
     write_directory_file ();
 }
   if (listed_incremental_option)
     write_directory_file ();
 }
@@ -1355,10 +1360,11 @@ compare_links (void const *entry1, void const *entry2)
 static void
 unknown_file_error (char const *p)
 {
 static void
 unknown_file_error (char const *p)
 {
-  WARN ((0, 0, _("%s: Unknown file type; file ignored"),
-        quotearg_colon (p)));
+  WARNOPT (WARN_FILE_IGNORED,
+          (0, 0, _("%s: Unknown file type; file ignored"),
+           quotearg_colon (p)));
   if (!ignore_failed_read_option)
   if (!ignore_failed_read_option)
-    exit_status = TAREXIT_FAILURE;
+    set_exit_status (TAREXIT_FAILURE);
 }
 
 \f
 }
 
 \f
@@ -1374,7 +1380,7 @@ static Hash_table *link_table;
 static bool
 dump_hard_link (struct tar_stat_info *st)
 {
 static bool
 dump_hard_link (struct tar_stat_info *st)
 {
-  if (link_table && st->stat.st_nlink > 1)
+  if (link_table && (st->stat.st_nlink > 1 || remove_files_option))
     {
       struct link lp;
       struct link *duplicate;
     {
       struct link lp;
       struct link *duplicate;
@@ -1407,8 +1413,8 @@ dump_hard_link (struct tar_stat_info *st)
          blk->header.typeflag = LNKTYPE;
          finish_header (st, blk, block_ordinal);
 
          blk->header.typeflag = LNKTYPE;
          finish_header (st, blk, block_ordinal);
 
-         if (remove_files_option && unlink (st->orig_file_name) != 0)
-           unlink_error (st->orig_file_name);
+         if (remove_files_option)
+           queue_deferred_unlink (st->orig_file_name, false);
 
          return true;
        }
 
          return true;
        }
@@ -1419,15 +1425,24 @@ dump_hard_link (struct tar_stat_info *st)
 static void
 file_count_links (struct tar_stat_info *st)
 {
 static void
 file_count_links (struct tar_stat_info *st)
 {
+  if (hard_dereference_option)
+    return;
   if (st->stat.st_nlink > 1)
     {
       struct link *duplicate;
   if (st->stat.st_nlink > 1)
     {
       struct link *duplicate;
-      struct link *lp = xmalloc (offsetof (struct link, name)
-                                + strlen (st->orig_file_name) + 1);
+      char *linkname = NULL;
+      struct link *lp;
+
+      assign_string (&linkname, st->orig_file_name);
+      transform_name (&linkname, XFORM_LINK);
+
+      lp = xmalloc (offsetof (struct link, name)
+                                + strlen (linkname) + 1);
       lp->ino = st->stat.st_ino;
       lp->dev = st->stat.st_dev;
       lp->nlink = st->stat.st_nlink;
       lp->ino = st->stat.st_ino;
       lp->dev = st->stat.st_dev;
       lp->nlink = st->stat.st_nlink;
-      strcpy (lp->name, st->orig_file_name);
+      strcpy (lp->name, linkname);
+      free (linkname);
 
       if (! ((link_table
              || (link_table = hash_initialize (0, 0, hash_link,
 
       if (! ((link_table
              || (link_table = hash_initialize (0, 0, hash_link,
@@ -1456,12 +1471,11 @@ check_links (void)
     {
       if (lp->nlink)
        {
     {
       if (lp->nlink)
        {
-         WARN ((0, 0, _("Missing links to %s.\n"), quote (lp->name)));
+         WARN ((0, 0, _("Missing links to %s."), quote (lp->name)));
        }
     }
 }
 
        }
     }
 }
 
-
 /* Dump a single file, recursing on directories.  P is the file name
    to dump.  TOP_LEVEL tells whether this is a top-level call; zero
    means no, positive means yes, and negative means the top level
 /* Dump a single file, recursing on directories.  P is the file name
    to dump.  TOP_LEVEL tells whether this is a top-level call; zero
    means no, positive means yes, and negative means the top level
@@ -1473,7 +1487,7 @@ check_links (void)
 
 static void
 dump_file0 (struct tar_stat_info *st, const char *p,
 
 static void
 dump_file0 (struct tar_stat_info *st, const char *p,
-           int top_level, dev_t parent_device)
+           bool top_level, dev_t parent_device)
 {
   union block *header;
   char type;
 {
   union block *header;
   char type;
@@ -1490,11 +1504,11 @@ dump_file0 (struct tar_stat_info *st, const char *p,
   assign_string (&st->file_name,
                  safer_name_suffix (p, false, absolute_names_option));
 
   assign_string (&st->file_name,
                  safer_name_suffix (p, false, absolute_names_option));
 
-  transform_name (&st->file_name);
+  transform_name (&st->file_name, XFORM_REGFILE);
 
   if (deref_stat (dereference_option, p, &st->stat) != 0)
     {
 
   if (deref_stat (dereference_option, p, &st->stat) != 0)
     {
-      stat_diag (p);
+      file_removed_diag (p, top_level, stat_diag);
       return;
     }
   st->archive_file_size = original_size = st->stat.st_size;
       return;
     }
   st->archive_file_size = original_size = st->stat.st_size;
@@ -1527,22 +1541,21 @@ dump_file0 (struct tar_stat_info *st, const char *p,
       && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c)))
     {
       if (!incremental_option && verbose_option)
       && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c)))
     {
       if (!incremental_option && verbose_option)
-       WARN ((0, 0, _("%s: file is unchanged; not dumped"),
-              quotearg_colon (p)));
+       WARNOPT (WARN_FILE_UNCHANGED,
+                (0, 0, _("%s: file is unchanged; not dumped"),
+                 quotearg_colon (p)));
       return;
     }
 
   /* See if we are trying to dump the archive.  */
   if (sys_file_is_archive (st))
     {
       return;
     }
 
   /* See if we are trying to dump the archive.  */
   if (sys_file_is_archive (st))
     {
-      WARN ((0, 0, _("%s: file is the archive; not dumped"),
-            quotearg_colon (p)));
+      WARNOPT (WARN_IGNORE_ARCHIVE,
+              (0, 0, _("%s: file is the archive; not dumped"),
+               quotearg_colon (p)));
       return;
     }
 
       return;
     }
 
-  if (is_avoided_name (p))
-    return;
-
   is_dir = S_ISDIR (st->stat.st_mode) != 0;
 
   if (!is_dir && dump_hard_link (st))
   is_dir = S_ISDIR (st->stat.st_mode) != 0;
 
   if (!is_dir && dump_hard_link (st))
@@ -1564,11 +1577,7 @@ dump_file0 (struct tar_stat_info *st, const char *p,
                         : 0)));
          if (fd < 0)
            {
                         : 0)));
          if (fd < 0)
            {
-             if (!top_level && errno == ENOENT)
-               WARN ((0, 0, _("%s: File removed before we read it"),
-                      quotearg_colon (p)));
-             else
-               open_diag (p);
+             file_removed_diag (p, top_level, open_diag);
              return;
            }
        }
              return;
            }
        }
@@ -1584,9 +1593,11 @@ dump_file0 (struct tar_stat_info *st, const char *p,
            {
              exclusion_tag_warning (st->orig_file_name, tag_file_name,
                                     _("directory not dumped"));
            {
              exclusion_tag_warning (st->orig_file_name, tag_file_name,
                                     _("directory not dumped"));
+             if (fd >= 0)
+               close (fd);
              return;
            }
              return;
            }
-         
+
          ok = dump_dir (fd, st, top_level, parent_device);
 
          /* dump_dir consumes FD if successful.  */
          ok = dump_dir (fd, st, top_level, parent_device);
 
          /* dump_dir consumes FD if successful.  */
@@ -1610,7 +1621,7 @@ dump_file0 (struct tar_stat_info *st, const char *p,
            {
            case dump_status_ok:
            case dump_status_short:
            {
            case dump_status_ok:
            case dump_status_short:
-             mv_end ();
+             file_count_links (st);
              break;
 
            case dump_status_fail:
              break;
 
            case dump_status_fail:
@@ -1620,8 +1631,6 @@ dump_file0 (struct tar_stat_info *st, const char *p,
              abort ();
            }
 
              abort ();
            }
 
-         file_count_links (st);
-
          ok = status == dump_status_ok;
        }
 
          ok = status == dump_status_ok;
        }
 
@@ -1639,20 +1648,23 @@ dump_file0 (struct tar_stat_info *st, const char *p,
               : fstat (fd, &final_stat))
              != 0)
            {
               : fstat (fd, &final_stat))
              != 0)
            {
-             stat_diag (p);
+             file_removed_diag (p, top_level, stat_diag);
              ok = false;
            }
        }
 
       if (ok)
        {
              ok = false;
            }
        }
 
       if (ok)
        {
-         if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
+         if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
+              /* Original ctime will change if the file is a directory and
+                 --remove-files is given */
+              && !(remove_files_option && is_dir))
              || original_size < final_stat.st_size)
            {
              || original_size < final_stat.st_size)
            {
-             WARN ((0, 0, _("%s: file changed as we read it"),
-                    quotearg_colon (p)));
-             if (exit_status == TAREXIT_SUCCESS)
-               exit_status = TAREXIT_DIFFERS;
+             WARNOPT (WARN_FILE_CHANGED,
+                      (0, 0, _("%s: file changed as we read it"),
+                       quotearg_colon (p)));
+             set_exit_status (TAREXIT_DIFFERS);
            }
          else if (atime_preserve_option == replace_atime_preserve
                   && set_file_atime (fd, p, restore_times) != 0)
            }
          else if (atime_preserve_option == replace_atime_preserve
                   && set_file_atime (fd, p, restore_times) != 0)
@@ -1666,18 +1678,7 @@ dump_file0 (struct tar_stat_info *st, const char *p,
        }
 
       if (ok && remove_files_option)
        }
 
       if (ok && remove_files_option)
-       {
-         if (is_dir)
-           {
-             if (rmdir (p) != 0 && errno != ENOTEMPTY)
-               rmdir_error (p);
-           }
-         else
-           {
-             if (unlink (p) != 0)
-               unlink_error (p);
-           }
-       }
+       queue_deferred_unlink (p, is_dir);
 
       return;
     }
 
       return;
     }
@@ -1693,11 +1694,12 @@ dump_file0 (struct tar_stat_info *st, const char *p,
       size = readlink (p, buffer, linklen + 1);
       if (size < 0)
        {
       size = readlink (p, buffer, linklen + 1);
       if (size < 0)
        {
-         readlink_diag (p);
+         file_removed_diag (p, top_level, readlink_diag);
          return;
        }
       buffer[size] = '\0';
       assign_string (&st->link_name, buffer);
          return;
        }
       buffer[size] = '\0';
       assign_string (&st->link_name, buffer);
+      transform_name (&st->link_name, XFORM_SYMLINK);
       if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
        write_long_link (st);
 
       if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
        write_long_link (st);
 
@@ -1706,16 +1708,14 @@ dump_file0 (struct tar_stat_info *st, const char *p,
       header = start_header (st);
       if (!header)
        return;
       header = start_header (st);
       if (!header)
        return;
-      tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
+      tar_copy_str (header->header.linkname, st->link_name, NAME_FIELD_SIZE);
       header->header.typeflag = SYMTYPE;
       finish_header (st, header, block_ordinal);
       /* nothing more to do to it */
 
       if (remove_files_option)
       header->header.typeflag = SYMTYPE;
       finish_header (st, header, block_ordinal);
       /* nothing more to do to it */
 
       if (remove_files_option)
-       {
-         if (unlink (p) == -1)
-           unlink_error (p);
-       }
+       queue_deferred_unlink (p, false);
+
       file_count_links (st);
       return;
     }
       file_count_links (st);
       return;
     }
@@ -1728,12 +1728,14 @@ dump_file0 (struct tar_stat_info *st, const char *p,
     type = FIFOTYPE;
   else if (S_ISSOCK (st->stat.st_mode))
     {
     type = FIFOTYPE;
   else if (S_ISSOCK (st->stat.st_mode))
     {
-      WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
+      WARNOPT (WARN_FILE_IGNORED,
+              (0, 0, _("%s: socket ignored"), quotearg_colon (p)));
       return;
     }
   else if (S_ISDOOR (st->stat.st_mode))
     {
       return;
     }
   else if (S_ISDOOR (st->stat.st_mode))
     {
-      WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
+      WARNOPT (WARN_FILE_IGNORED,
+              (0, 0, _("%s: door ignored"), quotearg_colon (p)));
       return;
     }
   else
       return;
     }
   else
@@ -1765,14 +1767,11 @@ dump_file0 (struct tar_stat_info *st, const char *p,
 
   finish_header (st, header, block_ordinal);
   if (remove_files_option)
 
   finish_header (st, header, block_ordinal);
   if (remove_files_option)
-    {
-      if (unlink (p) == -1)
-       unlink_error (p);
-    }
+    queue_deferred_unlink (p, false);
 }
 
 void
 }
 
 void
-dump_file (const char *p, int top_level, dev_t parent_device)
+dump_file (const char *p, bool top_level, dev_t parent_device)
 {
   struct tar_stat_info st;
   tar_stat_init (&st);
 {
   struct tar_stat_info st;
   tar_stat_init (&st);
This page took 0.044839 seconds and 4 git commands to generate.