]> git.ipfire.org Git - thirdparty/bash.git/blame - hashcmd.c
Bash-5.1 patch 4: fix key-value pair associative array assignment word expansions
[thirdparty/bash.git] / hashcmd.c
CommitLineData
d166f048
JA
1/* hashcmd.c - functions for managing a hash table mapping command names to
2 full pathnames. */
3
8868edaf 4/* Copyright (C) 1997-2020 Free Software Foundation, Inc.
d166f048
JA
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
d166f048 12
3185942a
JA
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
d166f048 17
3185942a
JA
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
20*/
d166f048
JA
21
22#include <config.h>
23
24#include "bashtypes.h"
25#include "posixstat.h"
26
27#if defined (HAVE_UNISTD_H)
28# include <unistd.h>
29#endif
30
31#include "bashansi.h"
32
33#include "shell.h"
d233b485 34#include "flags.h"
cce855bc 35#include "findcmd.h"
d166f048
JA
36#include "hashcmd.h"
37
7117c2d2 38HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;
d166f048 39
8868edaf 40static void phash_freedata PARAMS((PTR_T));
d166f048
JA
41
42void
7117c2d2 43phash_create ()
d166f048 44{
7117c2d2
JA
45 if (hashed_filenames == 0)
46 hashed_filenames = hash_create (FILENAME_HASH_BUCKETS);
d166f048
JA
47}
48
49static void
7117c2d2 50phash_freedata (data)
f73dda09 51 PTR_T data;
d166f048
JA
52{
53 free (((PATH_DATA *)data)->path);
54 free (data);
55}
56
57void
7117c2d2 58phash_flush ()
d166f048
JA
59{
60 if (hashed_filenames)
7117c2d2 61 hash_flush (hashed_filenames, phash_freedata);
d166f048
JA
62}
63
64/* Remove FILENAME from the table of hashed commands. */
7117c2d2
JA
65int
66phash_remove (filename)
f73dda09 67 const char *filename;
d166f048
JA
68{
69 register BUCKET_CONTENTS *item;
70
71 if (hashing_enabled == 0 || hashed_filenames == 0)
7117c2d2 72 return 0;
d166f048 73
7117c2d2 74 item = hash_remove (filename, hashed_filenames, 0);
d166f048
JA
75 if (item)
76 {
77 if (item->data)
7117c2d2 78 phash_freedata (item->data);
d166f048
JA
79 free (item->key);
80 free (item);
7117c2d2 81 return 0;
d166f048 82 }
7117c2d2 83 return 1;
d166f048
JA
84}
85
f73dda09 86/* Place FILENAME (key) and FULL_PATH (data->path) into the
d166f048 87 hash table. CHECK_DOT if non-null is for future calls to
7117c2d2 88 phash_search (); it means that this file was found
d166f048
JA
89 in a directory in $PATH that is not an absolute pathname.
90 FOUND is the initial value for times_found. */
91void
7117c2d2 92phash_insert (filename, full_path, check_dot, found)
f73dda09 93 char *filename, *full_path;
d166f048
JA
94 int check_dot, found;
95{
96 register BUCKET_CONTENTS *item;
97
98 if (hashing_enabled == 0)
99 return;
100
7117c2d2
JA
101 if (hashed_filenames == 0)
102 phash_create ();
d166f048 103
7117c2d2 104 item = hash_insert (filename, hashed_filenames, 0);
d166f048
JA
105 if (item->data)
106 free (pathdata(item)->path);
107 else
108 {
109 item->key = savestring (filename);
7117c2d2 110 item->data = xmalloc (sizeof (PATH_DATA));
d166f048 111 }
f73dda09 112 pathdata(item)->path = savestring (full_path);
d166f048
JA
113 pathdata(item)->flags = 0;
114 if (check_dot)
115 pathdata(item)->flags |= HASH_CHKDOT;
f73dda09 116 if (*full_path != '/')
d166f048
JA
117 pathdata(item)->flags |= HASH_RELPATH;
118 item->times_found = found;
119}
120
121/* Return the full pathname that FILENAME hashes to. If FILENAME
122 is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check
123 ./FILENAME and return that if it is executable. This always
124 returns a newly-allocated string; the caller is responsible
125 for freeing it. */
126char *
7117c2d2 127phash_search (filename)
f73dda09 128 const char *filename;
d166f048
JA
129{
130 register BUCKET_CONTENTS *item;
131 char *path, *dotted_filename, *tail;
132 int same;
133
134 if (hashing_enabled == 0 || hashed_filenames == 0)
135 return ((char *)NULL);
136
7117c2d2 137 item = hash_search (filename, hashed_filenames, 0);
d166f048
JA
138
139 if (item == NULL)
140 return ((char *)NULL);
141
142 /* If this filename is hashed, but `.' comes before it in the path,
143 see if ./filename is executable. If the hashed value is not an
144 absolute pathname, see if ./`hashed-value' exists. */
145 path = pathdata(item)->path;
146 if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH))
147 {
f73dda09 148 tail = (pathdata(item)->flags & HASH_RELPATH) ? path : (char *)filename; /* XXX - fix const later */
cce855bc
JA
149 /* If the pathname does not start with a `./', add a `./' to it. */
150 if (tail[0] != '.' || tail[1] != '/')
151 {
f73dda09 152 dotted_filename = (char *)xmalloc (3 + strlen (tail));
cce855bc
JA
153 dotted_filename[0] = '.'; dotted_filename[1] = '/';
154 strcpy (dotted_filename + 2, tail);
155 }
156 else
157 dotted_filename = savestring (tail);
d166f048
JA
158
159 if (executable_file (dotted_filename))
160 return (dotted_filename);
161
162 free (dotted_filename);
163
164#if 0
165 if (pathdata(item)->flags & HASH_RELPATH)
166 return ((char *)NULL);
167#endif
168
169 /* Watch out. If this file was hashed to "./filename", and
170 "./filename" is not executable, then return NULL. */
171
172 /* Since we already know "./filename" is not executable, what
173 we're really interested in is whether or not the `path'
174 portion of the hashed filename is equivalent to the current
175 directory, but only if it starts with a `.'. (This catches
176 ./. and so on.) same_file () tests general Unix file
177 equivalence -- same device and inode. */
178 if (*path == '.')
179 {
180 same = 0;
181 tail = (char *)strrchr (path, '/');
182
183 if (tail)
184 {
185 *tail = '\0';
186 same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL);
187 *tail = '/';
188 }
189
190 return same ? (char *)NULL : savestring (path);
191 }
192 }
193
194 return (savestring (path));
195}