(root)/
tar-1.35/
lib/
paxnames.c
       1  /* This file is part of GNU paxutils
       2     Copyright (C) 2005, 2007, 2010, 2023 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify it
       5     under the terms of the GNU General Public License as published by the
       6     Free Software Foundation; either version 3, or (at your option) any later
       7     version.
       8  
       9     This program is distributed in the hope that it will be useful, but
      10     WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
      12     Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License along
      15     with this program; if not, write to the Free Software Foundation, Inc.,
      16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
      17  
      18  #include <system.h>
      19  #include <hash.h>
      20  #include <paxlib.h>
      21  
      22  
      23  /* Hash tables of strings.  */
      24  
      25  /* Calculate the hash of a string.  */
      26  static size_t
      27  hash_string_hasher (void const *name, size_t n_buckets)
      28  {
      29    return hash_string (name, n_buckets);
      30  }
      31  
      32  /* Compare two strings for equality.  */
      33  static bool
      34  hash_string_compare (void const *name1, void const *name2)
      35  {
      36    return strcmp (name1, name2) == 0;
      37  }
      38  
      39  /* Return zero if TABLE contains a LEN-character long prefix of STRING,
      40     otherwise, insert a newly allocated copy of this prefix to TABLE and
      41     return 1.  If RETURN_PREFIX is not NULL, point it to the allocated
      42     copy. */
      43  static bool
      44  hash_string_insert_prefix (Hash_table **table, char const *string, size_t len,
      45  			   const char **return_prefix)
      46  {
      47    Hash_table *t = *table;
      48    char *s;
      49    char *e;
      50  
      51    if (len)
      52      {
      53        s = xmalloc (len + 1);
      54        memcpy (s, string, len);
      55        s[len] = 0;
      56      }
      57    else
      58      s = xstrdup (string);
      59  
      60    if (! ((t
      61  	  || (*table = t = hash_initialize (0, 0, hash_string_hasher,
      62  					    hash_string_compare, 0)))
      63  	 && (e = hash_insert (t, s))))
      64      xalloc_die ();
      65  
      66    if (e == s)
      67      {
      68        if (return_prefix)
      69  	*return_prefix = s;
      70        return 1;
      71      }
      72    else
      73      {
      74        free (s);
      75        return 0;
      76      }
      77  }
      78  
      79  
      80  static Hash_table *prefix_table[2];
      81  
      82  /* Return true if file names of some members in the archive were stripped off
      83     their leading components. We could have used
      84          return prefix_table[0] || prefix_table[1]
      85     but the following seems to be safer: */
      86  bool
      87  removed_prefixes_p (void)
      88  {
      89    return (prefix_table[0] && hash_get_n_entries (prefix_table[0]) != 0)
      90           || (prefix_table[1] && hash_get_n_entries (prefix_table[1]) != 0);
      91  }
      92  
      93  /* Return a safer suffix of FILE_NAME, or "." if it has no safer
      94     suffix.  Check for fully specified file names and other atrocities.
      95     Warn the user if we do not return NAME.  If LINK_TARGET is 1,
      96     FILE_NAME is the target of a hard link, not a member name.
      97     If ABSOLUTE_NAMES is 0, strip filesystem prefix from the file name. */
      98  
      99  char *
     100  safer_name_suffix (char const *file_name, bool link_target,
     101  		   bool absolute_names)
     102  {
     103    char const *p;
     104  
     105    if (absolute_names)
     106      p = file_name;
     107    else
     108      {
     109        /* Skip file system prefixes, leading file name components that contain
     110  	 "..", and leading slashes.  */
     111  
     112        size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name);
     113  
     114        for (p = file_name + prefix_len; *p; )
     115  	{
     116            if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
     117  	    prefix_len = p + 2 - file_name;
     118  
     119  	  do
     120  	    {
     121  	      char c = *p++;
     122  	      if (ISSLASH (c))
     123  		break;
     124  	    }
     125  	  while (*p);
     126  	}
     127  
     128        for (p = file_name + prefix_len; ISSLASH (*p); p++)
     129  	continue;
     130        prefix_len = p - file_name;
     131  
     132        if (prefix_len)
     133  	{
     134  	  const char *prefix;
     135  	  if (hash_string_insert_prefix (&prefix_table[link_target], file_name,
     136  					 prefix_len, &prefix))
     137  	    {
     138  	      static char const *const diagnostic[] =
     139  	      {
     140  		N_("Removing leading `%s' from member names"),
     141  		N_("Removing leading `%s' from hard link targets")
     142  	      };
     143  	      WARN ((0, 0, _(diagnostic[link_target]), prefix));
     144  	    }
     145  	}
     146      }
     147  
     148    if (! *p)
     149      {
     150        if (p == file_name)
     151  	{
     152  	  static char const *const diagnostic[] =
     153  	  {
     154  	    N_("Substituting `.' for empty member name"),
     155  	    N_("Substituting `.' for empty hard link target")
     156  	  };
     157  	  WARN ((0, 0, "%s", _(diagnostic[link_target])));
     158  	}
     159  
     160        p = ".";
     161      }
     162  
     163    return (char *) p;
     164  }