diff options
author | Richard Ipsum <richardipsum@fastmail.co.uk> | 2017-04-14 16:58:53 +0100 |
---|---|---|
committer | Richard Ipsum <richardipsum@fastmail.co.uk> | 2017-05-14 14:28:47 +0100 |
commit | 0a536630bc0c2c3bf1db2fac108946b4d9166e81 (patch) | |
tree | 57954dfe5be135b4be2d95f74f735b132d77bd98 | |
parent | e1f0802cfb62e577a78e120b8fbb55a924548601 (diff) | |
download | luxio-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.c | 50 |
1 files changed, 29 insertions, 21 deletions
@@ -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 |