[core] use readdir instead of readdir_r
readdir_r is deprecated in glibc due to serious memory handling issues in the API: one cannot pass the size of the allocated dirent. glibc authors claims readdir is thread-safe in modern implementations, and expect POSIX to require it in a future version. No way to check whether readdir is thread-safe though :( ("thread-safe" in this context means different directory streams, which is good enough.) Also remove li_dirent_buf_size. Change-Id: Ia5eae3327e97dc4b0751fb2604ea21c0ce09a5f9
This commit is contained in:
parent
b3dcc9662e
commit
bc6b256c34
|
@ -81,8 +81,6 @@ LI_API gboolean li_string_suffix(const GString *str, const gchar *s, gsize len);
|
|||
|
||||
LI_API void li_string_append_int(GString *dest, gint64 val);
|
||||
|
||||
LI_API gsize li_dirent_buf_size(DIR * dirp);
|
||||
|
||||
LI_API void li_apr_sha1_base64(GString *dest, const GString *passwd);
|
||||
LI_API void li_apr_md5_crypt(GString *dest, const GString *password, const GString *salt);
|
||||
|
||||
|
|
|
@ -851,36 +851,6 @@ void li_string_append_int(GString *dest, gint64 v) {
|
|||
dest->len = len;
|
||||
}
|
||||
|
||||
/* http://womble.decadentplace.org.uk/readdir_r-advisory.html */
|
||||
gsize li_dirent_buf_size(DIR * dirp) {
|
||||
glong name_max;
|
||||
gsize name_end;
|
||||
|
||||
# if !defined(HAVE_DIRFD)
|
||||
UNUSED(dirp);
|
||||
# endif
|
||||
|
||||
# if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
|
||||
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||
if (name_max == -1)
|
||||
# if defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
# else
|
||||
return (gsize)(-1);
|
||||
# endif
|
||||
# else
|
||||
# if defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
# else
|
||||
# error "buffer size for readdir_r cannot be determined"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
name_end = (gsize)offsetof(struct dirent, d_name) + name_max + 1;
|
||||
|
||||
return (name_end > sizeof(struct dirent) ? name_end : sizeof(struct dirent));
|
||||
}
|
||||
|
||||
const char *li_remove_path(const char *path) {
|
||||
char *p = strrchr(path, G_DIR_SEPARATOR);
|
||||
if (NULL != p && *(p) != '\0') {
|
||||
|
|
|
@ -108,10 +108,7 @@ static void stat_cache_run(gpointer data) {
|
|||
if (!sce->data.failed && sce->type == STAT_CACHE_ENTRY_DIR) {
|
||||
/* dirlisting */
|
||||
DIR *dirp;
|
||||
gsize size;
|
||||
struct dirent *entry;
|
||||
struct dirent *result;
|
||||
gint error;
|
||||
liStatCacheEntryData sced;
|
||||
GString *str;
|
||||
|
||||
|
@ -120,16 +117,19 @@ static void stat_cache_run(gpointer data) {
|
|||
sce->data.failed = TRUE;
|
||||
sce->data.err = errno;
|
||||
} else {
|
||||
size = li_dirent_buf_size(dirp);
|
||||
LI_FORCE_ASSERT(size != (gsize)-1);
|
||||
entry = g_slice_alloc(size);
|
||||
|
||||
sce->dirlist = g_array_sized_new(FALSE, FALSE, sizeof(liStatCacheEntryData), 32);
|
||||
|
||||
str = g_string_sized_new(sce->data.path->len + 64);
|
||||
g_string_append_len(str, GSTR_LEN(sce->data.path));
|
||||
|
||||
while ((error = readdir_r(dirp, entry, &result)) == 0 && result != NULL) {
|
||||
/* glibc claims modern readdir are thread-safe, and
|
||||
* readdir_r has issues. no way to check readdir is actually
|
||||
* safe, hope for the best.
|
||||
*/
|
||||
for (;;) {
|
||||
errno = 0; /* readdir may not reset errno */
|
||||
if (NULL == (result = readdir(dirp))) break;
|
||||
|
||||
/* hide "." and ".." */
|
||||
if (result->d_name[0] == '.' && (result->d_name[1] == '\0' ||
|
||||
(result->d_name[1] == '.' && result->d_name[2] == '\0'))) {
|
||||
|
@ -155,13 +155,12 @@ static void stat_cache_run(gpointer data) {
|
|||
g_array_append_val(sce->dirlist, sced);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
if (errno) {
|
||||
sce->data.failed = TRUE;
|
||||
sce->data.err = error;
|
||||
sce->data.err = errno;
|
||||
}
|
||||
|
||||
g_string_free(str, TRUE);
|
||||
g_slice_free1(size, entry);
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue