diff options
author | Rich Felker <dalias@aerifal.cx> | 2014-02-25 13:05:38 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2014-02-25 13:05:38 -0500 |
commit | b9f7f2e8762922a1a24d41358164ebe9ae437e31 (patch) | |
tree | e33c0f60a24d7d78e014f51af99ffbf753997fca /src/dirent | |
parent | d82db8550a2fc7ec573b28073317532ec7ca873e (diff) | |
download | musl-b9f7f2e8762922a1a24d41358164ebe9ae437e31.tar.gz musl-b9f7f2e8762922a1a24d41358164ebe9ae437e31.tar.xz musl-b9f7f2e8762922a1a24d41358164ebe9ae437e31.zip |
fix readdir not to set ENOENT when directory is removed while reading
per POSIX, ENOENT is reserved for invalid stream position; it is an optional error and would only happen if the application performs invalid seeks on the underlying file descriptor. however, linux's getdents syscall also returns ENOENT if the directory was removed between the time it was opened and the time of the read. we need to catch this case and remap it to simple end-of-file condition (null pointer return value like an error, but no change to errno). this issue reportedly affects GNU make in certain corner cases. rather than backing up and restoring errno, I've just changed the syscall to be made in a way that doesn't affect errno (via an inline syscall rather than a call to the __getdents function). the latter still exists for the purpose of providing the public getdents alias which sets errno.
Diffstat (limited to 'src/dirent')
-rw-r--r-- | src/dirent/readdir.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/src/dirent/readdir.c b/src/dirent/readdir.c index 98ec029e..2cf0632c 100644 --- a/src/dirent/readdir.c +++ b/src/dirent/readdir.c @@ -1,5 +1,7 @@ #include <dirent.h> +#include <errno.h> #include "__dirent.h" +#include "syscall.h" #include "libc.h" int __getdents(int, struct dirent *, size_t); @@ -9,8 +11,11 @@ struct dirent *readdir(DIR *dir) struct dirent *de; if (dir->buf_pos >= dir->buf_end) { - int len = __getdents(dir->fd, (void *)dir->buf, sizeof dir->buf); - if (len <= 0) return 0; + int len = __syscall(SYS_getdents, dir->fd, dir->buf, sizeof dir->buf); + if (len <= 0) { + if (len < 0 && len != -ENOENT) errno = -len; + return 0; + } dir->buf_end = len; dir->buf_pos = 0; } |