summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Ipsum <richardipsum@fastmail.co.uk>2017-04-14 16:58:53 +0100
committerRichard Ipsum <richardipsum@fastmail.co.uk>2017-05-14 14:28:47 +0100
commit0a536630bc0c2c3bf1db2fac108946b4d9166e81 (patch)
tree57954dfe5be135b4be2d95f74f735b132d77bd98
parente1f0802cfb62e577a78e120b8fbb55a924548601 (diff)
downloadluxio-0a536630bc0c2c3bf1db2fac108946b4d9166e81.tar.gz
Use readdir on glibc >= 2.24 by default
readdir_r is deprecated as of glibc 2.24[1][2][3] The readdir_r() function was invented as a reentrant version of readdir(3). It reads the next directory entry from the directory stream dirp, and returns it in the caller-allocated buffer pointed to by entry. For details of the dirent structure, see readdir(3). A pointer to the returned buffer is placed in *result; if the end of the directory stream was encountered, then NULL is instead returned in *result. It is recommended that applications use readdir(3) instead of readdir_r(). Furthermore, since version 2.24, glibc deprecates readdir_r(). The reasons are as follows: * On systems where NAME_MAX is undefined, calling readdir_r() may be unsafe because the interface does not allow the caller to specify the length of the buffer used for the returned directory entry. * On some systems, readdir_r() can't read directory entries with very long names. When the glibc implementation encounters such a name, readdir_r() fails with the error ENAMETOOLONG after the final directory entry has been read. On some other systems, readdir_r() may return a success status, but the returned d_name field may not be null terminated or may be truncated. * In the current POSIX.1 specification (POSIX.1-2008), readdir(3) is not required to be thread-safe. However, in modern implementations (including the glibc implementation), concurrent calls to readdir(3) that specify different directory streams are thread-safe. Therefore, the use of readdir_r() is generally unnecessary in multithreaded programs. In cases where multiple threads must read from the same directory stream, using readdir(3) with external synchronization is still preferable to the use of readdir_r(), for the reasons given in the points above. * It is expected that a future version of POSIX.1 will make readdir_r() obsolete, and require that readdir(3) be thread-safe when concurrently employed on different directory streams. This patch introduces a new constant LUXIO_USE_READDIR, luxio will use readdir instead of readdir_r iff this constant is defined. LUXIO_USE_READDIR is automatically defined for glibc 2.24 or later. [1]: http://man7.org/linux/man-pages/man3/readdir_r.3.html [2]: https://lwn.net/Articles/696475/ [3]: https://sourceware.org/ml/libc-alpha/2016-02/msg00093.html
-rw-r--r--luxio.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/luxio.c b/luxio.c
index 4ba1a9b..739a055 100644
--- a/luxio.c
+++ b/luxio.c
@@ -61,6 +61,11 @@ Not all systems will provide all the functions described here.
#include <syslog.h>
#include <iconv.h>
+#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)
+/* readdir is deprecated as of glibc 2.24, use readdir instead */
+#define LUXIO_USE_READDIR
+#endif
+
#ifdef HAVE_SENDFILE
# include <sys/sendfile.h>
#endif
@@ -1077,34 +1082,37 @@ static int
luxio_readdir(lua_State *L) /* 5.1.2 */
{
luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
- int err;
- err = readdir_r(s->dirp, s->buf, &s->ent);
-
- if (err == 0 && s->ent != NULL) {
- lua_pushinteger(L, 0);
- lua_createtable(L, 0, 3);
- lua_pushinteger(L, s->ent->d_ino);
- lua_setfield(L, -2, "d_ino");
- lua_pushstring(L, s->ent->d_name);
- lua_setfield(L, -2, "d_name");
-#ifdef HAVE_D_TYPE
- lua_pushinteger(L, s->ent->d_type);
- lua_setfield(L, -2, "d_type");
+ errno = 0;
+#ifdef LUXIO_USE_READDIR
+ struct dirent *ent = readdir(s->dirp);
+#else
+ errno = readdir_r(s->dirp, s->buf, &s->ent);
+ struct dirent *ent = errno == 0 ? s->ent : NULL;
#endif
- return 2;
- }
- if (s->ent == NULL) {
- /* end of directory */
- lua_pushnil(L);
+ if (ent == NULL) {
+ if (errno != 0) {
+ lua_pushinteger(L, errno);
+ } else {
+ /* end of directory */
+ lua_pushnil(L);
+ }
return 1;
}
- lua_pushinteger(L, err);
-
- return 1;
+ lua_pushinteger(L, 0);
+ lua_createtable(L, 0, 3);
+ lua_pushinteger(L, ent->d_ino);
+ lua_setfield(L, -2, "d_ino");
+ lua_pushstring(L, ent->d_name);
+ lua_setfield(L, -2, "d_name");
+#ifdef HAVE_D_TYPE
+ lua_pushinteger(L, ent->d_type);
+ lua_setfield(L, -2, "d_type");
+#endif
+ return 2;
}
/*** Reset directory stream