]> Dogcows Code - chaz/tar/blobdiff - src/names.c
Started merging with cpio into paxutils.
[chaz/tar] / src / names.c
index 5cb1aa544a8588d20f12e75ea4c53e0eb330baba..a5f2f7e70f346ff1c24e757501fb63790fdfad46 100644 (file)
@@ -1,7 +1,7 @@
 /* Various processing of names.
 
    Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
-   2003 Free Software Foundation, Inc.
+   2003, 2004 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
@@ -17,7 +17,7 @@
    with this program; if not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#include "system.h"
+#include <system.h>
 
 #include <fnmatch.h>
 #include <hash.h>
@@ -56,6 +56,8 @@ 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)
@@ -118,7 +120,7 @@ gid_to_gname (gid_t gid, char **gname)
 
 /* Given UNAME, set the corresponding UID and return 1, or else, return 0.  */
 int
-uname_to_uid (char *uname, uid_t *uidp)
+uname_to_uid (char const *uname, uid_t *uidp)
 {
   struct passwd *passwd;
 
@@ -148,7 +150,7 @@ uname_to_uid (char *uname, uid_t *uidp)
 
 /* Given GNAME, set the corresponding GID and return 1, or else, return 0.  */
 int
-gname_to_gid (char *gname, gid_t *gidp)
+gname_to_gid (char const *gname, gid_t *gidp)
 {
   struct group *group;
 
@@ -227,7 +229,7 @@ is_pattern (const char *string)
 /* Set up to gather file names for tar.  They can either come from a
    file or were saved from decoding arguments.  */
 void
-name_init (int argc, char *const *argv)
+name_init (void)
 {
   name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
   name_buffer_length = NAME_FIELD_SIZE;
@@ -358,6 +360,8 @@ name_next (int change_dirs)
       else
        {
          unquote_string (name_buffer);
+         if (incremental_option)
+           register_individual_file (name_buffer);
          return name_buffer;
        }
     }
@@ -443,6 +447,8 @@ name_gather (void)
          namelist = buffer;
          nametail = &namelist->next;
        }
+      else if (change_dir)
+       addname (0, change_dir);
     }
   else
     {
@@ -513,10 +519,10 @@ addname (char const *string, int change_dir)
   return name;
 }
 
-/* Find a match for PATH (whose string length is LENGTH) in the name
+/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
    list.  */
 static struct name *
-namelist_match (char const *path, size_t length)
+namelist_match (char const *file_name, size_t length)
 {
   struct name *p;
 
@@ -524,27 +530,27 @@ namelist_match (char const *path, size_t length)
     {
       /* If first chars don't match, quick skip.  */
 
-      if (p->firstch && p->name[0] != path[0])
+      if (p->firstch && p->name[0] != file_name[0])
        continue;
 
       if (p->regexp
-         ? fnmatch (p->name, path, recursion_option) == 0
+         ? fnmatch (p->name, file_name, recursion_option) == 0
          : (p->length <= length
-            && (path[p->length] == '\0'
-                || (ISSLASH (path[p->length]) && recursion_option))
-            && memcmp (path, p->name, p->length) == 0))
+            && (file_name[p->length] == '\0'
+                || (ISSLASH (file_name[p->length]) && recursion_option))
+            && memcmp (file_name, p->name, p->length) == 0))
        return p;
     }
 
   return 0;
 }
 
-/* Return true if and only if name PATH (from an archive) matches any
+/* Return true if and only if name FILE_NAME (from an archive) matches any
    name from the namelist.  */
 int
-name_match (const char *path)
+name_match (const char *file_name)
 {
-  size_t length = strlen (path);
+  size_t length = strlen (file_name);
 
   while (1)
     {
@@ -561,10 +567,10 @@ name_match (const char *path)
          return ! files_from_option;
        }
 
-      cursor = namelist_match (path, length);
+      cursor = namelist_match (file_name, length);
       if (cursor)
        {
-         if (!(ISSLASH (path[cursor->length]) && recursion_option)
+         if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
              || cursor->found_count == 0)
            cursor->found_count++; /* remember it matched */
          if (starting_file_option)
@@ -639,7 +645,7 @@ names_notfound (void)
          ERROR ((0, 0, _("%s: Required occurrence not found in archive"),
                  quotearg_colon (cursor->name)));
       }
-  
+
   /* Don't bother freeing the name list; we're about to exit.  */
   namelist = 0;
   nametail = &namelist;
@@ -748,8 +754,8 @@ compare_names (struct name const *n1, struct name const *n2)
 static void
 add_hierarchy_to_namelist (struct name *name, dev_t device)
 {
-  char *path = name->name;
-  char *buffer = get_directory_contents (path, device);
+  char *file_name = name->name;
+  char *buffer = get_directory_contents (file_name, device);
 
   if (! buffer)
     name->dir_contents = "\0\0\0\0";
@@ -759,18 +765,18 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
       size_t allocated_length = (name_length >= NAME_FIELD_SIZE
                                 ? name_length + NAME_FIELD_SIZE
                                 : NAME_FIELD_SIZE);
-      char *name_buffer = xmalloc (allocated_length + 1);
+      char *namebuf = xmalloc (allocated_length + 1);
                                /* FIXME: + 2 above?  */
       char *string;
       size_t string_length;
       int change_dir = name->change_dir;
 
       name->dir_contents = buffer;
-      strcpy (name_buffer, path);
-      if (! ISSLASH (name_buffer[name_length - 1]))
+      strcpy (namebuf, file_name);
+      if (! ISSLASH (namebuf[name_length - 1]))
        {
-         name_buffer[name_length++] = '/';
-         name_buffer[name_length] = '\0';
+         namebuf[name_length++] = '/';
+         namebuf[name_length] = '\0';
        }
 
       for (string = buffer; *string; string += string_length + 1)
@@ -788,15 +794,15 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
                    }
                  while (allocated_length <= name_length + string_length);
 
-                 name_buffer = xrealloc (name_buffer, allocated_length + 1);
+                 namebuf = xrealloc (namebuf, allocated_length + 1);
                }
-             strcpy (name_buffer + name_length, string + 1);
-             add_hierarchy_to_namelist (addname (name_buffer, change_dir),
+             strcpy (namebuf + name_length, string + 1);
+             add_hierarchy_to_namelist (addname (namebuf, change_dir),
                                         device);
            }
        }
 
-      free (name_buffer);
+      free (namebuf);
     }
 }
 \f
@@ -857,13 +863,13 @@ collect_and_sort_names (void)
    will have to do that if it wants to.  Oh, and if the namelist is
    empty, it returns null, unlike name_match, which returns TRUE.  */
 struct name *
-name_scan (const char *path)
+name_scan (const char *file_name)
 {
-  size_t length = strlen (path);
+  size_t length = strlen (file_name);
 
   while (1)
     {
-      struct name *cursor = namelist_match (path, length);
+      struct name *cursor = namelist_match (file_name, length);
       if (cursor)
        return cursor;
 
@@ -914,18 +920,18 @@ blank_name_list (void)
     name->found_count = 0;
 }
 
-/* Yield a newly allocated file name consisting of PATH concatenated to
-   NAME, with an intervening slash if PATH does not already end in one.  */
+/* Yield a newly allocated file name consisting of FILE_NAME concatenated to
+   NAME, with an intervening slash if FILE_NAME does not already end in one.  */
 char *
-new_name (const char *path, const char *name)
+new_name (const char *file_name, const char *name)
 {
-  size_t pathlen = strlen (path);
+  size_t file_name_len = strlen (file_name);
   size_t namesize = strlen (name) + 1;
-  int slash = pathlen && ! ISSLASH (path[pathlen - 1]);
-  char *buffer = xmalloc (pathlen + slash + namesize);
-  memcpy (buffer, path, pathlen);
-  buffer[pathlen] = '/';
-  memcpy (buffer + pathlen + slash, name, namesize);
+  int slash = file_name_len && ! ISSLASH (file_name[file_name_len - 1]);
+  char *buffer = xmalloc (file_name_len + slash + namesize);
+  memcpy (buffer, file_name, file_name_len);
+  buffer[file_name_len] = '/';
+  memcpy (buffer + file_name_len + slash, name, namesize);
   return buffer;
 }
 
@@ -933,7 +939,7 @@ new_name (const char *path, const char *name)
 bool
 excluded_name (char const *name)
 {
-  return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
+  return excluded_filename (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
 }
 \f
 /* Hash tables of strings.  */
@@ -999,7 +1005,44 @@ is_avoided_name (char const *name)
 {
   return hash_string_lookup (avoided_name_table, 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
+
+static Hash_table *prefix_table[2];
+
+/* Return true if file names of some members in the archive were stripped off
+   their leading components. We could have used
+        return prefix_table[0] || prefix_table[1]
+   but the following seems to be safer: */
+bool
+removed_prefixes_p (void)
+{
+  return (prefix_table[0] && hash_get_n_entries (prefix_table[0]) != 0)
+         || (prefix_table[1] && hash_get_n_entries (prefix_table[1]) != 0);
+}
+
 /* Return a safer suffix of FILE_NAME, or "." if it has no safer
    suffix.  Check for fully specified file names and other atrocities.
    Warn the user if we do not return NAME.  If LINK_TARGET is 1,
@@ -1014,21 +1057,16 @@ safer_name_suffix (char const *file_name, bool link_target)
     p = file_name;
   else
     {
-      /* Skip file system prefixes, leading pathnames that contain
+      /* Skip file system prefixes, leading file name components that contain
         "..", and leading slashes.  */
 
-      size_t prefix_len = FILESYSTEM_PREFIX_LEN (file_name);
+      size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name);
 
       for (p = file_name + prefix_len; *p; )
        {
-         if (p[0] == '.')
-           {
-             if (p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
-               prefix_len = p + 2 - file_name;
-             else if (ISSLASH (p[1]))
-               prefix_len = p + 1 - file_name;
-           }
-         
+          if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
+           prefix_len = p + 2 - file_name;
+
          do
            {
              char c = *p++;
@@ -1044,7 +1082,6 @@ safer_name_suffix (char const *file_name, bool link_target)
 
       if (prefix_len)
        {
-         static Hash_table *prefix_table[2];
          char *prefix = alloca (prefix_len + 1);
          memcpy (prefix, file_name, prefix_len);
          prefix[prefix_len] = '\0';
@@ -1070,23 +1107,23 @@ safer_name_suffix (char const *file_name, bool link_target)
            N_("Substituting `.' for empty member name"),
            N_("Substituting `.' for empty hard link target")
          };
-         WARN ((0, 0, _(diagnostic[link_target])));
+         WARN ((0, 0, "%s", _(diagnostic[link_target])));
        }
 
-      p = ISSLASH (file_name[strlen(file_name)-1]) ? "./" : ".";
+      p = ".";
     }
 
   return (char *) p;
 }
 \f
 /* Return the size of the prefix of FILE_NAME that is removed after
-   stripping NUM leading path name components.  NUM must be
+   stripping NUM leading file name components.  NUM must be
    positive.  */
 
 size_t
 stripped_prefix_len (char const *file_name, size_t num)
 {
-  char const *p = file_name + FILESYSTEM_PREFIX_LEN (file_name);
+  char const *p = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
   while (ISSLASH (*p))
     p++;
   while (*p)
@@ -1104,11 +1141,11 @@ stripped_prefix_len (char const *file_name, size_t num)
   return -1;
 }
 \f
-/* Return nonzero if NAME contains ".." as a path name component.  */
+/* Return nonzero if NAME contains ".." as a file name component.  */
 bool
 contains_dot_dot (char const *name)
 {
-  char const *p = name + FILESYSTEM_PREFIX_LEN (name);
+  char const *p = name + FILE_SYSTEM_PREFIX_LEN (name);
 
   for (;; p++)
     {
This page took 0.03355 seconds and 4 git commands to generate.