1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
/* This file is part of GNU paxutils
Copyright (C) 2005, 2007 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
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
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
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. */
#include <system.h>
#include <hash.h>
#include <paxlib.h>
/* Hash tables of strings. */
/* Calculate the hash of a string. */
static size_t
hash_string_hasher (void const *name, size_t n_buckets)
{
return hash_string (name, n_buckets);
}
/* Compare two strings for equality. */
static bool
hash_string_compare (void const *name1, void const *name2)
{
return strcmp (name1, name2) == 0;
}
/* Return zero if TABLE contains a LEN-character long prefix of STRING,
otherwise, insert a newly allocated copy of this prefix to TABLE and
return 1. If RETURN_PREFIX is not NULL, point it to the allocated
copy. */
static bool
hash_string_insert_prefix (Hash_table **table, char const *string, size_t len,
const char **return_prefix)
{
Hash_table *t = *table;
char *s;
char *e;
if (len)
{
s = xmalloc (len + 1);
memcpy (s, string, len);
s[len] = 0;
}
else
s = xstrdup (string);
if (! ((t
|| (*table = t = hash_initialize (0, 0, hash_string_hasher,
hash_string_compare, 0)))
&& (e = hash_insert (t, s))))
xalloc_die ();
if (e == s)
{
if (return_prefix)
*return_prefix = s;
return 1;
}
else
{
free (s);
return 0;
}
}
/* Return zero if TABLE contains a copy of STRING; otherwise, insert a
copy of STRING to TABLE and return 1. */
bool
hash_string_insert (Hash_table **table, char const *string)
{
return hash_string_insert_prefix (table, string, 0, NULL);
}
/* Return 1 if TABLE contains STRING. */
bool
hash_string_lookup (Hash_table const *table, char const *string)
{
return table && hash_lookup (table, string);
}
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,
FILE_NAME is the target of a hard link, not a member name.
If ABSOLUTE_NAMES is 0, strip filesystem prefix from the file name. */
char *
safer_name_suffix (char const *file_name, bool link_target,
bool absolute_names)
{
char const *p;
if (absolute_names)
p = file_name;
else
{
/* Skip file system prefixes, leading file name components that contain
"..", and leading slashes. */
size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name);
for (p = file_name + prefix_len; *p; )
{
if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
prefix_len = p + 2 - file_name;
do
{
char c = *p++;
if (ISSLASH (c))
break;
}
while (*p);
}
for (p = file_name + prefix_len; ISSLASH (*p); p++)
continue;
prefix_len = p - file_name;
if (prefix_len)
{
const char *prefix;
if (hash_string_insert_prefix (&prefix_table[link_target], file_name,
prefix_len, &prefix))
{
static char const *const diagnostic[] =
{
N_("Removing leading `%s' from member names"),
N_("Removing leading `%s' from hard link targets")
};
WARN ((0, 0, _(diagnostic[link_target]), prefix));
}
}
}
if (! *p)
{
if (p == file_name)
{
static char const *const diagnostic[] =
{
N_("Substituting `.' for empty member name"),
N_("Substituting `.' for empty hard link target")
};
WARN ((0, 0, "%s", _(diagnostic[link_target])));
}
p = ".";
}
return (char *) p;
}
|