summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn (J5) Palmieri <johnp@redhat.com>2006-09-13 19:13:17 +0000
committerJohn (J5) Palmieri <johnp@redhat.com>2006-09-13 19:13:17 +0000
commitf82bdd3ab39cc5741189a4ab16dc3533a79c6617 (patch)
tree86cb3648bc8adb776e00284f58957f5a9c6aa4a5
parent642335f681c26b78a1a0e2f2167d2f0e7beb6807 (diff)
* dbus/dbus-sysdeps-util-unix.c (_dbus_directory_get_next_file):
use threadsafe readdir_r instead of readdir
-rw-r--r--ChangeLog5
-rw-r--r--configure.in2
-rw-r--r--dbus/dbus-sysdeps-util-unix.c79
3 files changed, 73 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index cc89708f..ae2e5c4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2006-09-13 John (J5) Palmieri <johnp@redhat.com>
+ * dbus/dbus-sysdeps-util-unix.c (_dbus_directory_get_next_file):
+ use threadsafe readdir_r instead of readdir
+
+2006-09-13 John (J5) Palmieri <johnp@redhat.com>
+
* dbus-threads.c (dbus_threads_init_default): New method for
initializing the internal thread implementation (Patch from
Alexander Larsson <alexl at redhat dot com>)
diff --git a/configure.in b/configure.in
index 48708c82..399225ef 100644
--- a/configure.in
+++ b/configure.in
@@ -489,7 +489,7 @@ fi
AC_CHECK_LIB(socket,socket)
AC_CHECK_LIB(nsl,gethostbyname)
-AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep poll setenv unsetenv socketpair getgrouplist)
+AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep poll setenv unsetenv socketpair getgrouplist fpathconf dirfd)
AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c
index 981d4e3e..9fc7645b 100644
--- a/dbus/dbus-sysdeps-util-unix.c
+++ b/dbus/dbus-sysdeps-util-unix.c
@@ -490,14 +490,47 @@ _dbus_directory_open (const DBusString *filename,
return iter;
}
+/* Calculate the required buffer size (in bytes) for directory
+ * entries read from the given directory handle. Return -1 if this
+ * this cannot be done.
+ *
+ * If you use autoconf, include fpathconf and dirfd in your
+ * AC_CHECK_FUNCS list. Otherwise use some other method to detect
+ * and use them where available.
+ */
+static dbus_bool_t
+dirent_buf_size(DIR * dirp, size_t *size)
+{
+ long name_max;
+# 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;
+# else
+ return FALSE;
+# endif
+# else
+# if defined(NAME_MAX)
+ name_max = NAME_MAX;
+# else
+# error "buffer size for readdir_r cannot be determined"
+# endif
+# endif
+ if (size)
+ *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
/**
* Get next file in the directory. Will not return "." or ".." on
* UNIX. If an error occurs, the contents of "filename" are
* undefined. The error is never set if the function succeeds.
*
- * @todo 1.0 for thread safety, I think we have to use
- * readdir_r(). (GLib has the same issue, should file a bug.)
- *
* @param iter the iterator
* @param filename string to be set to the next file in the dir
* @param error return location for error
@@ -508,19 +541,37 @@ _dbus_directory_get_next_file (DBusDirIter *iter,
DBusString *filename,
DBusError *error)
{
- struct dirent *ent;
+ struct dirent *d, *ent;
+ size_t buf_size;
+ int err;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
+
+ if (!dirent_buf_size (iter->d, &buf_size))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Can't calculate buffer size when reading directory");
+ return FALSE;
+ }
+
+ d = (struct dirent *)dbus_malloc (buf_size);
+ if (!d)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+ "No memory to read directory entry");
+ return FALSE;
+ }
+
again:
- errno = 0;
- ent = readdir (iter->d);
- if (ent == NULL)
+ err = readdir_r (iter->d, d, &ent);
+ if (err || !ent)
{
- if (errno != 0)
+ if (err != 0)
dbus_set_error (error,
- _dbus_error_from_errno (errno),
- "%s", _dbus_strerror (errno));
+ _dbus_error_from_errno (err),
+ "%s", _dbus_strerror (err));
+
+ dbus_free (d);
return FALSE;
}
else if (ent->d_name[0] == '.' &&
@@ -534,10 +585,14 @@ _dbus_directory_get_next_file (DBusDirIter *iter,
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
"No memory to read directory entry");
+ dbus_free (d);
return FALSE;
}
else
- return TRUE;
+ {
+ dbus_free (d);
+ return TRUE;
+ }
}
}