guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

readdir_r again


From: Kevin Ryde
Subject: readdir_r again
Date: Fri, 24 Feb 2006 11:43:28 +1100
User-agent: Gnus/5.110004 (No Gnus v0.4) Emacs/21.4 (gnu/linux)

I had another go at the readdir_r pathconf biz, below, this time
actually tested a bit.  I'm inclined to use NAME_MAX rather than
fpathconf when there's a choice, because NAME_MAX is probably a
constant, but I'm open to arguments the other way.

When using pathconf it'd be possible to make the syscall to get the
size just once in opendir and store that in the smob (becoming a
double cell).  Not sure if that's worth doing.

The plain readdir() case is protected by a mutex, but I'm wondering if
that's really necessary.  It could be easier to assume that if you've
got posix threads then you've got readdir_r.  Likewise with a lot of
these choices between plain and "_r" funcs.



SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0,
            (SCM port),
            "Return (as a string) the next directory entry from the directory 
stream\n"
            "@var{stream}.  If there is no remaining entry to be read then 
the\n"
            "end of file object is returned.")
#define FUNC_NAME s_scm_readdir
{
  struct dirent *rdent;

  SCM_VALIDATE_DIR (1, port);
  if (!SCM_DIR_OPEN_P (port))
    SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));

#if HAVE_READDIR_R
  {
    DIR           *ds = (DIR *) SCM_CELL_WORD_1 (port);
    struct dirent de; /* just for sizeof */
    size_t        name_max, dirent_size, namlen;
    char          *buf;
    int           old_errno;

    /* On solaris 10 there's no NAME_MAX constant, it's obligatory to use
       pathconf().  */
#ifdef NAME_MAX
    name_max = NAME_MAX;
#else
    name_max = fpathconf (dirfd (ds), _PC_NAME_MAX);
    if (name_max == -1)
      SCM_SYSERROR;
#endif

    /* As noted in the glibc manual, on various systems (such as Solaris) the
       d_name[] field is only 1 char and you're expected to size the buffer
       for readdir_r based on NAME_MAX.  So the following effectively uses the
       bigger of sizeof(d_name) or NAME_MAX.  */
    dirent_size = SCM_MAX (sizeof (de),
                           sizeof (de) - sizeof (de.d_name) + name_max + 1);

    /* NAME_MAX is typically 255, so alloca on the stack is good */
    buf = alloca (dirent_size);
    errno = 0;
    SCM_SYSCALL (readdir_r (ds, (struct dirent *) buf, &rdent));
    if (errno != 0)
      SCM_SYSERROR;
    if (! rdent)
      return SCM_EOF_VAL;

    namlen = NAMLEN (rdent);

    return (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
            : SCM_EOF_VAL);
  }
#else
  {
    SCM ret;
    scm_dynwind_begin (0);
    scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex);

    errno = 0;
    SCM_SYSCALL (rdent = readdir ((DIR *) SCM_CELL_WORD_1 (port)));
    if (errno != 0)
      SCM_SYSERROR;

    ret = (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
           : SCM_EOF_VAL);

    scm_dynwind_end ();
    return ret;
  }
#endif
}
#undef FUNC_NAME




reply via email to

[Prev in Thread] Current Thread [Next in Thread]