]> Dogcows Code - chaz/tar/blobdiff - src/names.c
tar: fix bug with sparse files with effective size of 8 GiB or more
[chaz/tar] / src / names.c
index 2fc751d81fac59c0faab9515850f7e83891c9c76..32bd8e69d4f2cc1911fd1918b95a945f530e2017 100644 (file)
@@ -1,7 +1,7 @@
 /* Various processing of names.
 
-   Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright 1988, 1992, 1994, 1996-2001, 2003-2007, 2009, 2013 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
@@ -14,8 +14,7 @@
    Public License for more details.
 
    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.  */
+   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <system.h>
 
@@ -47,8 +46,6 @@ static char *cached_no_such_gname;
 static uid_t cached_no_such_uid;
 static gid_t cached_no_such_gid;
 
-static void register_individual_file (char const *name);
-
 /* Given UID, find the corresponding UNAME.  */
 void
 uid_to_uname (uid_t uid, char **uname)
@@ -360,8 +357,6 @@ name_next_elt (int change_dirs)
        {
          if (unquote_option)
            unquote_string (name_buffer);
-         if (incremental_option)
-           register_individual_file (name_buffer);
          entry.type = ep->type;
          entry.v.name = name_buffer;
          return &entry;
@@ -673,9 +668,9 @@ label_notfound (void)
 
 /* Sort *singly* linked LIST of names, of given LENGTH, using COMPARE
    to order names.  Return the sorted list.  Note that after calling
-   this function, the `prev' links in list elements are messed up.
+   this function, the 'prev' links in list elements are messed up.
 
-   Apart from the type `struct name' and the definition of SUCCESSOR,
+   Apart from the type 'struct name' and the definition of SUCCESSOR,
    this is a generic list-sorting function, but it's too painful to
    make it both generic and portable
    in C.  */
@@ -818,6 +813,7 @@ add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
            {
              struct name *np;
              struct tar_stat_info subdir;
+             int subfd;
 
              if (allocated_length <= name_length + string_length)
                {
@@ -841,21 +837,32 @@ add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
 
              tar_stat_init (&subdir);
              subdir.parent = st;
-             subdir.fd = openat (st->fd, string + 1,
-                                 open_read_flags | O_DIRECTORY);
-             if (subdir.fd < 0)
-               open_diag (namebuf);
-             else if (fstat (subdir.fd, &subdir.stat) != 0)
-               stat_diag (namebuf);
-             else if (! (O_DIRECTORY || S_ISDIR (subdir.stat.st_mode)))
+             if (st->fd < 0)
                {
-                 errno = ENOTDIR;
-                 open_diag (namebuf);
+                 subfd = -1;
+                 errno = - st->fd;
                }
+             else
+               subfd = subfile_open (st, string + 1,
+                                     open_read_flags | O_DIRECTORY);
+             if (subfd < 0)
+               open_diag (namebuf);
              else
                {
-                 subdir.orig_file_name = xstrdup (namebuf);
-                 add_hierarchy_to_namelist (&subdir, np);
+                 subdir.fd = subfd;
+                 if (fstat (subfd, &subdir.stat) != 0)
+                   stat_diag (namebuf);
+                 else if (! (O_DIRECTORY || S_ISDIR (subdir.stat.st_mode)))
+                   {
+                     errno = ENOTDIR;
+                     open_diag (namebuf);
+                   }
+                 else
+                   {
+                     subdir.orig_file_name = xstrdup (namebuf);
+                     add_hierarchy_to_namelist (&subdir, np);
+                     restore_parent_fd (&subdir);
+                   }
                }
 
              tar_stat_destroy (&subdir);
@@ -886,7 +893,7 @@ name_compare (void const *entry1, void const *entry2)
 }
 
 \f
-/* Rebase `name' member of CHILD and all its siblings to
+/* Rebase 'name' member of CHILD and all its siblings to
    the new PARENT. */
 static void
 rebase_child_list (struct name *child, struct name *parent)
@@ -969,23 +976,28 @@ collect_and_sort_names (void)
 
       tar_stat_init (&st);
 
-      if (deref_stat (dereference_option, name->name, &st.stat) != 0)
+      if (deref_stat (name->name, &st.stat) != 0)
        {
          stat_diag (name->name);
          continue;
        }
       if (S_ISDIR (st.stat.st_mode))
        {
-         st.fd = open (name->name, open_read_flags | O_DIRECTORY);
-         if (st.fd < 0)
+         int dir_fd = openat (chdir_fd, name->name,
+                              open_read_flags | O_DIRECTORY);
+         if (dir_fd < 0)
            open_diag (name->name);
-         else if (fstat (st.fd, &st.stat) != 0)
-           stat_diag (name->name);
-         else if (O_DIRECTORY || S_ISDIR (st.stat.st_mode))
+         else
            {
-             st.orig_file_name = xstrdup (name->name);
-             name->found_count++;
-             add_hierarchy_to_namelist (&st, name);
+             st.fd = dir_fd;
+             if (fstat (dir_fd, &st.stat) != 0)
+               stat_diag (name->name);
+             else if (O_DIRECTORY || S_ISDIR (st.stat.st_mode))
+               {
+                 st.orig_file_name = xstrdup (name->name);
+                 name->found_count++;
+                 add_hierarchy_to_namelist (&st, name);
+               }
            }
        }
 
@@ -1087,7 +1099,7 @@ name_scan (const char *file_name)
 struct name *gnu_list_name;
 
 struct name const *
-name_from_list ()
+name_from_list (void)
 {
   if (!gnu_list_name)
     gnu_list_name = namelist;
@@ -1134,28 +1146,6 @@ excluded_name (char const *name)
 {
   return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
 }
-\f
-static Hash_table *individual_file_table;
-
-static void
-register_individual_file (char const *name)
-{
-  struct stat st;
-
-  if (deref_stat (dereference_option, name, &st) != 0)
-    return; /* Will be complained about later */
-  if (S_ISDIR (st.st_mode))
-    return;
-
-  hash_string_insert (&individual_file_table, name);
-}
-
-bool
-is_individual_file (char const *name)
-{
-  return hash_string_lookup (individual_file_table, name);
-}
-
 \f
 
 /* Return the size of the prefix of FILE_NAME that is removed after
This page took 0.026624 seconds and 4 git commands to generate.