]> Dogcows Code - chaz/tar/blobdiff - src/names.c
(name_next): Use chdir_from_initial_wd, not chdir.
[chaz/tar] / src / names.c
index 5db518e11753313efebb5e58603701daa1fcecc7..16cba031e72e0c4a63c244def2db49676db052b5 100644 (file)
@@ -1,5 +1,5 @@
 /* Various processing of names.
-   Copyright (C) 1988, 92, 94, 96, 97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 94, 96, 97, 98, 1999 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
 
    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.  */
+
+/* Enable GNU extensions in fnmatch.h.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
 
 #include "system.h"
 
 #include <pwd.h>
 #include <grp.h>
-
-#ifndef FNM_LEADING_DIR
-# include <fnmatch.h>
-#endif
+#include <fnmatch.h>
 
 #include "common.h"
 \f
@@ -48,6 +50,15 @@ static char cached_gname[GNAME_FIELD_SIZE] = "";
 static uid_t cached_uid;       /* valid only if cached_uname is not empty */
 static gid_t cached_gid;       /* valid only if cached_gname is not empty */
 
+/* These variables are valid only if nonempty.  */
+static char cached_no_such_uname[UNAME_FIELD_SIZE] = "";
+static char cached_no_such_gname[GNAME_FIELD_SIZE] = "";
+
+/* These variables are valid only if nonzero.  It's not worth optimizing
+   the case for weird systems where 0 is not a valid uid or gid.  */
+static uid_t cached_no_such_uid = 0;
+static gid_t cached_no_such_gid = 0;
+
 /*------------------------------------------.
 | Given UID, find the corresponding UNAME.  |
 `------------------------------------------*/
@@ -57,6 +68,12 @@ uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
 {
   struct passwd *passwd;
 
+  if (uid != 0 && uid == cached_no_such_uid)
+    {
+      *uname = '\0';
+      return;
+    }
+
   if (!cached_uname[0] || uid != cached_uid)
     {
       passwd = getpwuid (uid);
@@ -67,6 +84,7 @@ uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
        }
       else
        {
+         cached_no_such_uid = uid;
          *uname = '\0';
          return;
        }
@@ -83,6 +101,12 @@ gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
 {
   struct group *group;
 
+  if (gid != 0 && gid == cached_no_such_gid)
+    {
+      *gname = '\0';
+      return;
+    }
+
   if (!cached_gname[0] || gid != cached_gid)
     {
       setgrent ();             /* FIXME: why?! */
@@ -94,6 +118,7 @@ gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
        }
       else
        {
+         cached_no_such_gid = gid;
          *gname = '\0';
          return;
        }
@@ -110,6 +135,10 @@ uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
 {
   struct passwd *passwd;
 
+  if (cached_no_such_uname[0]
+      && strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
+    return 0;
+
   if (!cached_uname[0]
       || uname[0] != cached_uname[0]
       || strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
@@ -121,7 +150,10 @@ uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
          strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
        }
       else
-       return 0;
+       {
+         strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
+         return 0;
+       }
     }
   *uidp = cached_uid;
   return 1;
@@ -136,6 +168,10 @@ gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
 {
   struct group *group;
 
+  if (cached_no_such_gname[0]
+      && strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
+    return 0;
+
   if (!cached_gname[0]
       || gname[0] != cached_gname[0]
       || strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
@@ -147,7 +183,10 @@ gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
          strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
        }
       else
-       return 0;
+       {
+         strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
+         return 0;
+       }
     }
   *gidp = cached_gid;
   return 1;
@@ -334,21 +373,16 @@ name_next (int change_dirs)
 
       if (chdir_flag)
        {
-         if (chdir (name_buffer) < 0)
-           FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
-                         name_buffer));
+         chdir_from_initial_wd (name_buffer);
          chdir_flag = 0;
        }
       else if (change_dirs && strcmp (name_buffer, "-C") == 0)
        chdir_flag = 1;
       else
-#if 0
-       if (!exclude_option || !check_exclude (name_buffer))
-#endif
-         {
-           unquote_string (name_buffer);
-           return name_buffer;
-         }
+       {
+         unquote_string (name_buffer);
+         return name_buffer;
+       }
     }
 
   /* No more names in file.  */
@@ -390,10 +424,12 @@ name_gather (void)
   static struct name *buffer;
   static size_t allocated_length = 0;
 
-  char *name;
+  char const *name;
 
   if (same_order_option)
     {
+      char *change_dir = NULL;
+
       if (allocated_length == 0)
        {
          allocated_length = sizeof (struct name) + NAME_FIELD_SIZE;
@@ -401,24 +437,26 @@ name_gather (void)
          /* FIXME: This memset is overkill, and ugly...  */
          memset (buffer, 0, allocated_length);
        }
-      name = name_next (0);
-      if (name)
+
+      while ((name = name_next (0)) && strcmp (name, "-C") == 0)
        {
-         if (strcmp (name, "-C") == 0)
-           {
-             char *copy = xstrdup (name_next (0));
+         char const *dir = name_next (0);
+         if (! dir)
+           FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+         if (change_dir)
+           free (change_dir);
+         change_dir = xstrdup (dir);
+       }
 
-             name = name_next (0);
-             if (!name)
-               FATAL_ERROR ((0, 0, _("Missing file name after -C")));
-             buffer->change_dir = copy;
-           }
+      if (name)
+       {
          buffer->length = strlen (name);
          if (sizeof (struct name) + buffer->length >= allocated_length)
            {
              allocated_length = sizeof (struct name) + buffer->length;
              buffer = (struct name *) xrealloc (buffer, allocated_length);
            }
+         buffer->change_dir = change_dir;
          strncpy (buffer->name, name, (size_t) buffer->length);
          buffer->name[buffer->length] = 0;
          buffer->next = NULL;
@@ -428,13 +466,35 @@ name_gather (void)
          namelist = buffer;
          namelast = namelist;
        }
+      else if (change_dir)
+       free (change_dir);
+
       return;
     }
 
   /* Non sorted names -- read them all in.  */
 
-  while (name = name_next (0), name)
-    addname (name);
+  for (;;)
+    {
+      char *change_dir = NULL;
+      while ((name = name_next (0)) && strcmp (name, "-C") == 0)
+       {
+         char const *dir = name_next (0);
+         if (! dir)
+           FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+         if (change_dir)
+           free (change_dir);
+         change_dir = xstrdup (dir);
+       }
+      if (name)
+       addname (name, change_dir);
+      else
+       {
+         if (change_dir)
+           free (change_dir);
+         break;
+       }
+    }
 }
 
 /*-----------------------------.
@@ -442,41 +502,11 @@ name_gather (void)
 `-----------------------------*/
 
 void
-addname (const char *string)
+addname (char const *string, char const *change_dir)
 {
-  /* FIXME: This is ugly.  How is memory managed?  */
-  static char *chdir_name = NULL;
-
   struct name *name;
   size_t length;
 
-  if (strcmp (string, "-C") == 0)
-    {
-      chdir_name = xstrdup (name_next (0));
-      string = name_next (0);
-      if (!chdir_name)
-       FATAL_ERROR ((0, 0, _("Missing file name after -C")));
-
-      if (chdir_name[0] != '/')
-       {
-         char *path = xmalloc (PATH_MAX);
-
-         /* FIXME: Shouldn't we use xgetcwd?  */
-#if HAVE_GETCWD
-         if (!getcwd (path, PATH_MAX))
-           FATAL_ERROR ((0, 0, _("Could not get current directory")));
-#else
-         char *getwd ();
-
-         if (!getwd (path))
-           FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
-                         path));
-#endif
-         chdir_name = new_name (path, chdir_name);
-         free (path);
-       }
-    }
-
   length = string ? strlen (string) : 0;
   name = (struct name *) xmalloc (sizeof (struct name) + length);
   memset (name, 0, sizeof (struct name) + length);
@@ -496,7 +526,7 @@ addname (const char *string)
   name->found = 0;
   name->regexp = 0;            /* assume not a regular expression */
   name->firstch = 1;           /* assume first char is literal */
-  name->change_dir = chdir_name;
+  name->change_dir = change_dir;
   name->dir_contents = 0;
 
   if (string && is_pattern (string))
@@ -532,9 +562,7 @@ name_match (const char *path)
 
       if (cursor->fake)
        {
-         if (cursor->change_dir && chdir (cursor->change_dir))
-           FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
-                         cursor->change_dir));
+         chdir_from_initial_wd (cursor->change_dir);
          namelist = 0;
          return 1;
        }
@@ -558,9 +586,7 @@ name_match (const char *path)
                      free (namelist);
                      namelist = NULL;
                    }
-                 if (cursor->change_dir && chdir (cursor->change_dir))
-                   FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
-                                 cursor->change_dir));
+                 chdir_from_initial_wd (cursor->change_dir);
 
                  /* We got a match.  */
                  return 1;
@@ -584,9 +610,7 @@ name_match (const char *path)
                  free ((void *) namelist);
                  namelist = 0;
                }
-             if (cursor->change_dir && chdir (cursor->change_dir))
-               FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
-                             cursor->change_dir));
+             chdir_from_initial_wd (cursor->change_dir);
 
              /* We got a match.  */
              return 1;
@@ -736,10 +760,7 @@ name_from_list (void)
   if (gnu_list_name)
     {
       gnu_list_name->found = 1;
-      if (gnu_list_name->change_dir)
-       if (chdir (gnu_list_name->change_dir) < 0)
-         FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
-                       gnu_list_name->change_dir));
+      chdir_from_initial_wd (gnu_list_name->change_dir);
       return gnu_list_name->name;
     }
   return NULL;
@@ -771,137 +792,25 @@ new_name (const char *path, const char *name)
   sprintf (buffer, "%s/%s", path, name);
   return buffer;
 }
-\f
-/* Excludes names.  */
-
-static char *exclude_pool = NULL;
-static size_t exclude_pool_size = 0;
-static size_t allocated_exclude_pool_size = 0;
-
-static char **simple_exclude_array = NULL;
-static int simple_excludes = 0;
-static int allocated_simple_excludes = 0;
-
-static char **pattern_exclude_array = NULL;
-static int pattern_excludes = 0;
-static int allocated_pattern_excludes = 0;
-
-/*---.
-| ?  |
-`---*/
-
-void
-add_exclude (char *name)
-{
-  size_t name_size;
-
-  unquote_string (name);       /* FIXME: unquote in all cases?  If ever? */
-  name_size = strlen (name) + 1;
-
-  if (exclude_pool_size + name_size > allocated_exclude_pool_size)
-    {
-      char *previous_exclude_pool = exclude_pool;
-      char **cursor;
-
-      allocated_exclude_pool_size = exclude_pool_size + name_size + 1024;
-      exclude_pool = (char *)
-       xrealloc (exclude_pool, allocated_exclude_pool_size);
-
-      for (cursor = simple_exclude_array;
-          cursor < simple_exclude_array + simple_excludes;
-          cursor++)
-       *cursor = exclude_pool + (*cursor - previous_exclude_pool);
-      for (cursor = pattern_exclude_array;
-          cursor < pattern_exclude_array + pattern_excludes;
-          cursor++)
-       *cursor = exclude_pool + (*cursor - previous_exclude_pool);
-    }
-
-  if (is_pattern (name))
-    {
-      if (pattern_excludes == allocated_pattern_excludes)
-       {
-         allocated_pattern_excludes += 32;
-         pattern_exclude_array = (char **)
-           xrealloc (pattern_exclude_array,
-                     allocated_pattern_excludes * sizeof (char *));
-       }
-      pattern_exclude_array[pattern_excludes++]
-       = exclude_pool + exclude_pool_size;
-    }
-  else
-    {
-      if (simple_excludes == allocated_simple_excludes)
-       {
-         allocated_simple_excludes += 32;
-         simple_exclude_array = (char **)
-           xrealloc (simple_exclude_array,
-                     allocated_simple_excludes * sizeof (char *));
-       }
-      simple_exclude_array[simple_excludes++]
-       = exclude_pool + exclude_pool_size;
-    }
-
-  strcpy (exclude_pool + exclude_pool_size, name);
-  exclude_pool_size += name_size;
-}
-
-/*---.
-| ?  |
-`---*/
-
-void
-add_exclude_file (const char *name)
-{
-  FILE *file;
-  char buffer[1024];
-
-  if (strcmp (name, "-"))
-    file = fopen (name, "r");
-  else
-    {
-      request_stdin ("-X");
-      file = stdin;
-    }
-  if (!file)
-    FATAL_ERROR ((0, errno, _("Cannot open %s"), name));
-
-  while (fgets (buffer, 1024, file))
-    {
-      char *end_of_line = strrchr (buffer, '\n');
-
-      if (end_of_line)
-       *end_of_line = '\0';
-      add_exclude (buffer);
-    }
-  if (fclose (file) == EOF)
-    ERROR ((0, errno, "%s", name));
-}
-
-/*------------------------------------------------------------------.
-| Returns true if the file NAME should not be added nor extracted.  |
-`------------------------------------------------------------------*/
 
+/* Return nonzero if file NAME is excluded.  Exclude a name if its
+   prefix matches a pattern that contains slashes, or if one of its
+   components matches a pattern that contains no slashes.  */
 int
-check_exclude (const char *name)
+excluded_name (char const *name)
 {
-  int counter;
-
-  for (counter = 0; counter < pattern_excludes; counter++)
-    if (fnmatch (pattern_exclude_array[counter], name, FNM_LEADING_DIR) == 0)
-      return 1;
+  char const *p;
+  name += FILESYSTEM_PREFIX_LEN (name);
 
-  for (counter = 0; counter < simple_excludes; counter++)
-    {
-      /* Accept the output from strstr only if it is the last part of the
-        string.  FIXME: Find a faster way to do this.  */
+  if (excluded_filename (excluded_with_slash, name,
+                        FNM_FILE_NAME | FNM_LEADING_DIR))
+    return 1;
 
-      char *string = strstr (name, simple_exclude_array[counter]);
+  for (p = name; *p; p++)
+    if ((p == name || (ISSLASH (p[-1]) && !ISSLASH (p[0])))
+       && excluded_filename (excluded_without_slash, p,
+                             FNM_FILE_NAME | FNM_LEADING_DIR))
+      return 1;
 
-      if (string
-         && (string == name || string[-1] == '/')
-         && string[strlen (simple_exclude_array[counter])] == '\0')
-       return 1;
-    }
   return 0;
 }
This page took 0.033075 seconds and 4 git commands to generate.