expected/1.8.4 behavior
download ruby-1.8.4, extract, cd into the source root. (alternatively,
use Ubuntu 6.10’s ruby package.)
./configure && make && ./ruby -w -e ‘puts(Dir.glob(“v*/config.h”))’
produces (after the build output) this output:
vms/config.h
actual 1.8.6 behavior
download ruby-1.8.6, extract, cd into the source root. (alternatively,
use Debian testing/unstable’s ruby package.)
./configure && make && ./ruby -w -e ‘puts(Dir.glob(“v*/config.h”))’
produces (after the build output) this output:
-e:1: warning: variable.o/config.h: Not a directory
-e:1: warning: variable.c/config.h: Not a directory
-e:1: warning: version.c/config.h: Not a directory
-e:1: warning: version.o/config.h: Not a directory
-e:1: warning: version.h/config.h: Not a directory
vms/config.h
responsible code
in “dir.c”:
static int
do_stat(const char *path, struct stat *pst, int flags)
{
int ret = stat(path, pst);
if (ret < 0 && errno != ENOENT)
sys_warning(path);
return ret;
}
static int
do_lstat(const char *path, struct stat *pst, int flags)
{
int ret = lstat(path, pst);
if (ret < 0 && errno != ENOENT)
sys_warning(path);
return ret;
}
static DIR *
do_opendir(const char *path, int flags)
{
DIR *dirp = opendir(path);
if (dirp == NULL && errno != ENOENT && errno != ENOTDIR)
sys_warning(path);
return dirp;
}
evaluation
stat(2)/lstat(2) can return ENOTDIR if a non-leaf element of the path
they’re given is not a directory.
this is a fairly common case when people are using globbing as a cheap
way of finding files at a fixed depth below a given directory.
suggested fix
make do_stat and do_lstat more like do_opendir:
-
if (ret < 0 && errno != ENOENT)
-
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
it might also be worth a code comment, since it’s not likely to be
immediately obvious to most readers that stat(2)/lstat(2) can return
ENOTDIR.
thanks!
–
Elliott Hughes, BlueArc Engineering