diff options
Diffstat (limited to 'dbus/dbus-sysdeps-util-unix.c')
| -rw-r--r-- | dbus/dbus-sysdeps-util-unix.c | 79 | 
1 files changed, 67 insertions, 12 deletions
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; +        }      }  }  | 
