#include <stdio.h>
#include "chartypes.h"
#include "bashtypes.h"
-#ifndef _MINIX
+#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "filecntl.h"
containing the file of interest. */
int dot_found_in_search = 0;
-#define u_mode_bits(x) (((x) & 0000700) >> 6)
-#define g_mode_bits(x) (((x) & 0000070) >> 3)
-#define o_mode_bits(x) (((x) & 0000007) >> 0)
-#define X_BIT(x) ((x) & 1)
-
/* Return some flags based on information about this file.
The EXISTS bit is non-zero if the file is found.
The EXECABLE bit is non-zero the file is executble.
const char *name;
{
struct stat finfo;
+ int r;
/* Determine whether this file exists or not. */
if (stat (name, &finfo) < 0)
if (S_ISDIR (finfo.st_mode))
return (FS_EXISTS|FS_DIRECTORY);
+ r = FS_EXISTS;
+
#if defined (AFS)
/* We have to use access(2) to determine access because AFS does not
support Unix file system semantics. This may produce wrong
answers for non-AFS files when ruid != euid. I hate AFS. */
if (access (name, X_OK) == 0)
- return (FS_EXISTS | FS_EXECABLE);
- else
- return (FS_EXISTS);
+ r |= FS_EXECABLE;
+ if (access (name, R_OK) == 0)
+ r |= FS_READABLE;
+
+ return r;
#else /* !AFS */
/* Find out if the file is actually executable. By definition, the
only other criteria is that the file has an execute bit set that
- we can use. */
+ we can use. The same with whether or not a file is readable. */
/* Root only requires execute permission for any of owner, group or
- others to be able to exec a file. */
+ others to be able to exec a file, and can read any file. */
if (current_user.euid == (uid_t)0)
{
- int bits;
-
- bits = (u_mode_bits (finfo.st_mode) |
- g_mode_bits (finfo.st_mode) |
- o_mode_bits (finfo.st_mode));
-
- if (X_BIT (bits))
- return (FS_EXISTS | FS_EXECABLE);
+ r |= FS_READABLE;
+ if (finfo.st_mode & S_IXUGO)
+ r |= FS_EXECABLE;
+ return r;
}
- /* If we are the owner of the file, the owner execute bit applies. */
- if (current_user.euid == finfo.st_uid && X_BIT (u_mode_bits (finfo.st_mode)))
- return (FS_EXISTS | FS_EXECABLE);
+ /* If we are the owner of the file, the owner bits apply. */
+ if (current_user.euid == finfo.st_uid)
+ {
+ if (finfo.st_mode & S_IXUSR)
+ r |= FS_EXECABLE;
+ if (finfo.st_mode & S_IRUSR)
+ r |= FS_READABLE;
+ }
/* If we are in the owning group, the group permissions apply. */
- if (group_member (finfo.st_gid) && X_BIT (g_mode_bits (finfo.st_mode)))
- return (FS_EXISTS | FS_EXECABLE);
+ else if (group_member (finfo.st_gid))
+ {
+ if (finfo.st_mode & S_IXGRP)
+ r |= FS_EXECABLE;
+ if (finfo.st_mode & S_IRGRP)
+ r |= FS_READABLE;
+ }
- /* If `others' have execute permission to the file, then so do we,
- since we are also `others'. */
- if (X_BIT (o_mode_bits (finfo.st_mode)))
- return (FS_EXISTS | FS_EXECABLE);
+ /* Else we check whether `others' have permission to execute the file */
+ else
+ {
+ if (finfo.st_mode & S_IXOTH)
+ r |= FS_EXECABLE;
+ if (finfo.st_mode & S_IROTH)
+ r |= FS_READABLE;
+ }
- return (FS_EXISTS);
+ return r;
#endif /* !AFS */
}
/* Locate the file referenced by NAME, searching along the contents
of the shell PATH variable. Return a new string which is the full
pathname to the file, or NULL if the file couldn't be found. This
- returns the first file found. */
+ returns the first readable file found; designed to be used to look
+ for shell scripts or files to source. */
char *
find_path_file (name)
const char *name;
{
- return (find_user_command_internal (name, FS_EXISTS));
+ return (find_user_command_internal (name, FS_READABLE));
}
static char *
char *path_list, *cmd;
SHELL_VAR *var;
- /* Search for the value of PATH in both the temporary environment, and
+ /* Search for the value of PATH in both the temporary environments and
in the regular list of variables. */
if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */
path_list = value_cell (var);
cmd = find_user_command_in_path (name, path_list, flags);
- if (var && tempvar_p (var))
- dispose_variable (var);
-
return (cmd);
}
/* If PATH is in the temporary environment for this command, don't use the
hash table to search for the full pathname. */
- path = find_tempenv_variable ("PATH");
- temp_path = path != 0;
+ path = find_variable_internal ("PATH", 1);
+ temp_path = path && tempvar_p (path);
+ if (temp_path == 0 && path)
+ path = (SHELL_VAR *)NULL;
/* Don't waste time trying to find hashed data for a pathname
that is already completely specified or if we're using a command-
specific value for PATH. */
if (path == 0 && absolute_program (pathname) == 0)
- hashed_file = find_hashed_filename (pathname);
+ hashed_file = phash_search (pathname);
/* If a command found in the hash table no longer exists, we need to
look for it in $PATH. Thank you Posix.2. This forces us to stat
if (hashed_file && (posixly_correct || check_hashed_filenames))
{
st = file_status (hashed_file);
- if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0)
+ if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE))
{
- remove_hashed_filename (pathname);
+ phash_remove (pathname);
free (hashed_file);
hashed_file = (char *)NULL;
}
{
command = find_user_command_in_path (pathname, value_cell (path),
FS_EXEC_PREFERRED|FS_NODIRS);
- if (tempvar_p (path))
- dispose_variable (path);
}
else
command = find_user_command (pathname);
if (command && hashing_enabled && temp_path == 0)
- remember_filename ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
+ phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
}
return (command);
}
if (match_list == 0)
{
match_list_size = 5;
- match_list = alloc_array (match_list_size);
+ match_list = strvec_create (match_list_size);
}
/* Clear out the old match list. */
if (match_index + 1 == match_list_size)
{
match_list_size += 10;
- match_list = (char **)xrealloc (match_list, (match_list_size + 1) * sizeof (char *));
+ match_list = strvec_resize (match_list, (match_list_size + 1));
}
match_list[match_index++] = match;
int status;
char *full_path, *xpath;
- xpath = (*path == '~') ? bash_tilde_expand (path) : path;
+ xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path;
/* Remember the location of "." in the path, in all its forms
(as long as they begin with a `.', e.g. `./.') */
if (flags & FS_EXISTS)
return (full_path);
+ /* If we have a readable file, and the caller wants a readable file, this
+ is it. */
+ if ((flags & FS_READABLE) && (status & FS_READABLE))
+ return (full_path);
+
/* If the file is executable, then it satisfies the cases of
EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
- if ((status & FS_EXECABLE) &&
+ if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) &&
(((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0)))
{
FREE (file_to_lose_on);
file_to_lose_on = savestring (full_path);
/* If we want only executable files, or we don't want directories and
- this file is a directory, fail. */
- if ((flags & FS_EXEC_ONLY) || (flags & FS_EXEC_PREFERRED) ||
- ((flags & FS_NODIRS) && (status & FS_DIRECTORY)))
+ this file is a directory, or we want a readable file and this file
+ isn't readable, fail. */
+ if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) ||
+ ((flags & FS_NODIRS) && (status & FS_DIRECTORY)) ||
+ ((flags & FS_READABLE) && (status & FS_READABLE) == 0))
{
free (full_path);
return ((char *)NULL);