]> git.ipfire.org Git - thirdparty/bash.git/blame - hashcmd.c
Bash-4.3 patch 7
[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
3185942a 4/* Copyright (C) 1997-2009 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"
cce855bc 34#include "findcmd.h"
d166f048
JA
35#include "hashcmd.h"
36
37extern int hashing_enabled;
38
7117c2d2 39HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;
d166f048 40
7117c2d2 41static void phash_freedata __P((PTR_T));
d166f048
JA
42
43void
7117c2d2 44phash_create ()
d166f048 45{
7117c2d2
JA
46 if (hashed_filenames == 0)
47 hashed_filenames = hash_create (FILENAME_HASH_BUCKETS);
d166f048
JA
48}
49
50static void
7117c2d2 51phash_freedata (data)
f73dda09 52 PTR_T data;
d166f048
JA
53{
54 free (((PATH_DATA *)data)->path);
55 free (data);
56}
57
58void
7117c2d2 59phash_flush ()
d166f048
JA
60{
61 if (hashed_filenames)
7117c2d2 62 hash_flush (hashed_filenames, phash_freedata);
d166f048
JA
63}
64
65/* Remove FILENAME from the table of hashed commands. */
7117c2d2
JA
66int
67phash_remove (filename)
f73dda09 68 const char *filename;
d166f048
JA
69{
70 register BUCKET_CONTENTS *item;
71
72 if (hashing_enabled == 0 || hashed_filenames == 0)
7117c2d2 73 return 0;
d166f048 74
7117c2d2 75 item = hash_remove (filename, hashed_filenames, 0);
d166f048
JA
76 if (item)
77 {
78 if (item->data)
7117c2d2 79 phash_freedata (item->data);
d166f048
JA
80 free (item->key);
81 free (item);
7117c2d2 82 return 0;
d166f048 83 }
7117c2d2 84 return 1;
d166f048
JA
85}
86
f73dda09 87/* Place FILENAME (key) and FULL_PATH (data->path) into the
d166f048 88 hash table. CHECK_DOT if non-null is for future calls to
7117c2d2 89 phash_search (); it means that this file was found
d166f048
JA
90 in a directory in $PATH that is not an absolute pathname.
91 FOUND is the initial value for times_found. */
92void
7117c2d2 93phash_insert (filename, full_path, check_dot, found)
f73dda09 94 char *filename, *full_path;
d166f048
JA
95 int check_dot, found;
96{
97 register BUCKET_CONTENTS *item;
98
99 if (hashing_enabled == 0)
100 return;
101
7117c2d2
JA
102 if (hashed_filenames == 0)
103 phash_create ();
d166f048 104
7117c2d2 105 item = hash_insert (filename, hashed_filenames, 0);
d166f048
JA
106 if (item->data)
107 free (pathdata(item)->path);
108 else
109 {
110 item->key = savestring (filename);
7117c2d2 111 item->data = xmalloc (sizeof (PATH_DATA));
d166f048 112 }
f73dda09 113 pathdata(item)->path = savestring (full_path);
d166f048
JA
114 pathdata(item)->flags = 0;
115 if (check_dot)
116 pathdata(item)->flags |= HASH_CHKDOT;
f73dda09 117 if (*full_path != '/')
d166f048
JA
118 pathdata(item)->flags |= HASH_RELPATH;
119 item->times_found = found;
120}
121
122/* Return the full pathname that FILENAME hashes to. If FILENAME
123 is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check
124 ./FILENAME and return that if it is executable. This always
125 returns a newly-allocated string; the caller is responsible
126 for freeing it. */
127char *
7117c2d2 128phash_search (filename)
f73dda09 129 const char *filename;
d166f048
JA
130{
131 register BUCKET_CONTENTS *item;
132 char *path, *dotted_filename, *tail;
133 int same;
134
135 if (hashing_enabled == 0 || hashed_filenames == 0)
136 return ((char *)NULL);
137
7117c2d2 138 item = hash_search (filename, hashed_filenames, 0);
d166f048
JA
139
140 if (item == NULL)
141 return ((char *)NULL);
142
143 /* If this filename is hashed, but `.' comes before it in the path,
144 see if ./filename is executable. If the hashed value is not an
145 absolute pathname, see if ./`hashed-value' exists. */
146 path = pathdata(item)->path;
147 if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH))
148 {
f73dda09 149 tail = (pathdata(item)->flags & HASH_RELPATH) ? path : (char *)filename; /* XXX - fix const later */
cce855bc
JA
150 /* If the pathname does not start with a `./', add a `./' to it. */
151 if (tail[0] != '.' || tail[1] != '/')
152 {
f73dda09 153 dotted_filename = (char *)xmalloc (3 + strlen (tail));
cce855bc
JA
154 dotted_filename[0] = '.'; dotted_filename[1] = '/';
155 strcpy (dotted_filename + 2, tail);
156 }
157 else
158 dotted_filename = savestring (tail);
d166f048
JA
159
160 if (executable_file (dotted_filename))
161 return (dotted_filename);
162
163 free (dotted_filename);
164
165#if 0
166 if (pathdata(item)->flags & HASH_RELPATH)
167 return ((char *)NULL);
168#endif
169
170 /* Watch out. If this file was hashed to "./filename", and
171 "./filename" is not executable, then return NULL. */
172
173 /* Since we already know "./filename" is not executable, what
174 we're really interested in is whether or not the `path'
175 portion of the hashed filename is equivalent to the current
176 directory, but only if it starts with a `.'. (This catches
177 ./. and so on.) same_file () tests general Unix file
178 equivalence -- same device and inode. */
179 if (*path == '.')
180 {
181 same = 0;
182 tail = (char *)strrchr (path, '/');
183
184 if (tail)
185 {
186 *tail = '\0';
187 same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL);
188 *tail = '/';
189 }
190
191 return same ? (char *)NULL : savestring (path);
192 }
193 }
194
195 return (savestring (path));
196}