diff options
author | Bruno Haible <bruno@clisp.org> | 2020-12-24 13:32:39 +0100 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2020-12-24 13:32:39 +0100 |
commit | d9c121346a283503350c0ac7cd6eb5092e87181b (patch) | |
tree | f1100d1ef70a766d85c09ac957b4d162ed5f73c8 /lib/findprog-in.c | |
parent | 2845b3bed86ca649d3206d9b1e0fe30a4ca33110 (diff) | |
download | gnulib-d9c121346a283503350c0ac7cd6eb5092e87181b.tar.gz |
findprog-in: Improve errno upon failure on native Windows.
* lib/findprog-in.c (find_in_given_path): If the file basename has no
dot and the search with a suffix returned no result, do also a search
without a suffix, and set errno = ENOEXEC if we find a file in this way.
* tests/test-spawn-pipe-script.c (main): Update expected errno.
Diffstat (limited to 'lib/findprog-in.c')
-rw-r--r-- | lib/findprog-in.c | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/lib/findprog-in.c b/lib/findprog-in.c index 63b8419630..d0505fb0df 100644 --- a/lib/findprog-in.c +++ b/lib/findprog-in.c @@ -118,6 +118,8 @@ find_in_given_path (const char *progname, const char *path, if (ISSLASH (*p)) progbasename = p + 1; } + + bool progbasename_has_dot = (strchr (progbasename, '.') != NULL); #endif /* Try all platform-dependent suffixes. */ @@ -129,7 +131,7 @@ find_in_given_path (const char *progname, const char *path, #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ /* File names without a '.' are not considered executable, and for file names with a '.' no additional suffix is tried. */ - if ((*suffix != '\0') != (strchr (progbasename, '.') != NULL)) + if ((*suffix != '\0') != progbasename_has_dot) #endif { /* Concatenate directory_as_prefix, progname, suffix. */ @@ -174,6 +176,36 @@ find_in_given_path (const char *progname, const char *path, free (progpathname); } } + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + if (failure_errno == ENOENT && !progbasename_has_dot) + { + /* In the loop above, we skipped suffix = "". Do this loop + round now, merely to provide a better errno than ENOENT. */ + + char *progpathname = + concatenated_filename (directory_as_prefix, progname, ""); + + if (progpathname == NULL) + return NULL; /* errno is set here */ + + if (eaccess (progpathname, X_OK) == 0) + { + struct stat statbuf; + + if (stat (progpathname, &statbuf) >= 0) + { + if (! S_ISDIR (statbuf.st_mode)) + errno = ENOEXEC; + else + errno = EACCES; + } + } + + failure_errno = errno; + + free (progpathname); + } + #endif errno = failure_errno; return NULL; @@ -196,6 +228,10 @@ find_in_given_path (const char *progname, const char *path, char *path_rest; char *cp; + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + bool progname_has_dot = (strchr (progname, '.') != NULL); + #endif + failure_errno = ENOENT; for (path_rest = path_copy; ; path_rest = cp + 1) { @@ -243,7 +279,7 @@ find_in_given_path (const char *progname, const char *path, #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ /* File names without a '.' are not considered executable, and for file names with a '.' no additional suffix is tried. */ - if ((*suffix != '\0') != (strchr (progname, '.') != NULL)) + if ((*suffix != '\0') != progname_has_dot) #endif { /* Concatenate dir_as_prefix, progname, and suffix. */ @@ -311,6 +347,41 @@ find_in_given_path (const char *progname, const char *path, free (progpathname); } } + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + if (failure_errno == ENOENT && !progname_has_dot) + { + /* In the loop above, we skipped suffix = "". Do this loop + round now, merely to provide a better errno than ENOENT. */ + + char *progpathname = + concatenated_filename (dir_as_prefix, progname, ""); + + if (progpathname == NULL) + { + /* errno is set here. */ + failure_errno = errno; + free (dir_as_prefix_to_free); + goto failed; + } + + if (eaccess (progpathname, X_OK) == 0) + { + struct stat statbuf; + + if (stat (progpathname, &statbuf) >= 0) + { + if (! S_ISDIR (statbuf.st_mode)) + errno = ENOEXEC; + else + errno = EACCES; + } + } + + failure_errno = errno; + + free (progpathname); + } + #endif free (dir_as_prefix_to_free); |