From 905ae44c77a4b899100de99360823a586e095622 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Sat, 11 Apr 2020 17:07:11 -0300 Subject: linux: Move posix dir implementations to Linux This generic implementation already expects a getdents API which is Linux specific. It also allows simplify it by assuming _DIRENT_HAVE_D_RECLEN and _DIRENT_HAVE_D_OFF support. The readdir are also expanded on each required implementation, futher fixes and improvements will make parametrize the implementation more complex. Checked on x86_64-linux-gnu, i686-linux-gnu, and with a build for all affected ABIs. --- sysdeps/unix/sysv/linux/readdir.c | 65 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'sysdeps/unix/sysv/linux/readdir.c') diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index df7a92aa78..2e03e66e69 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -19,5 +19,68 @@ #include #if !_DIRENT_MATCHES_DIRENT64 -# include +#include + +/* Read a directory entry from DIRP. */ +struct dirent * +__readdir (DIR *dirp) +{ + struct dirent *dp; + int saved_errno = errno; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + + do + { + size_t reclen; + + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __getdents (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + bytes = 0; + + /* Don't modifiy errno when reaching EOF. */ + if (bytes == 0) + __set_errno (saved_errno); + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct dirent *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + /* Skip deleted files. */ + } while (dp->d_ino == 0); + +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + + return dp; +} +weak_alias (__readdir, readdir) + #endif -- cgit 1.4.1