New modules 'opendir', 'readdir', 'rewinddir', 'closedir'.
authorBruno Haible <bruno@clisp.org>
Mon, 12 Sep 2011 23:37:35 +0000 (01:37 +0200)
committerBruno Haible <bruno@clisp.org>
Mon, 12 Sep 2011 23:39:18 +0000 (01:39 +0200)
* lib/dirent.in.h (struct dirent): New type.
(DT_UNKNOWN, DT_FIFO, DT_CHR, DT_DIR, DT_BLK, DT_REG, DT_LNK, DT_SOCK,
DT_WHT): New macros.
(DIR): New type.
(opendir, closedir): Declare only if the module 'opendir' is enabled.
(readdir, rewinddir): New declarations.
* lib/dirent-private.h: New file.
* lib/opendir.c: New file.
* lib/readdir.c: New file.
* lib/rewinddir.c: New file.
* lib/closedir.c: New file.
* lib/fchdir.c (rpl_closedir, rpl_opendir): Remove functions.
* m4/opendir.m4: New file.
* m4/readdir.m4: New file.
* m4/rewinddir.m4: New file.
* m4/closedir.m4: New file.
* m4/fchdir.m4 (gl_FUNC_FCHDIR): Don't set REPLACE_OPENDIR,
REPLACE_CLOSEDIR here.
* m4/dirent_h.m4 (gl_DIRENT_H): Also check whether closedir, opendir,
readdir, rewinddir are declared.
(gl_DIRENT_H_DEFAULTS): Initialize GNULIB_OPENDIR, GNULIB_READDIR,
GNULIB_REWINDDIR, GNULIB_CLOSEDIR, HAVE_OPENDIR, HAVE_READDIR,
HAVE_REWINDDIR, HAVE_CLOSEDIR.
* modules/dirent (Makefile.am): Substitute GNULIB_OPENDIR,
GNULIB_READDIR, GNULIB_REWINDDIR, GNULIB_CLOSEDIR, HAVE_OPENDIR,
HAVE_READDIR, HAVE_REWINDDIR, HAVE_CLOSEDIR.
* modules/opendir: New file.
* modules/readdir: New file.
* modules/rewinddir: New file.
* modules/closedir: New file.
* doc/posix-functions/opendir.texi: Mention the 'opendir' module.
* doc/posix-functions/readdir.texi: Mention the 'readdir' module.
* doc/posix-functions/rewinddir.texi: Mention the 'rewinddir' module.
* doc/posix-functions/closedir.texi: Mention the 'closedir' module.
* NEWS: Mention the 'fchdir' change.

24 files changed:
ChangeLog
NEWS
doc/posix-functions/closedir.texi
doc/posix-functions/opendir.texi
doc/posix-functions/readdir.texi
doc/posix-functions/rewinddir.texi
lib/closedir.c [new file with mode: 0644]
lib/dirent-private.h [new file with mode: 0644]
lib/dirent.in.h
lib/fchdir.c
lib/opendir.c [new file with mode: 0644]
lib/readdir.c [new file with mode: 0644]
lib/rewinddir.c [new file with mode: 0644]
m4/closedir.m4 [new file with mode: 0644]
m4/dirent_h.m4
m4/fchdir.m4
m4/opendir.m4 [new file with mode: 0644]
m4/readdir.m4 [new file with mode: 0644]
m4/rewinddir.m4 [new file with mode: 0644]
modules/closedir [new file with mode: 0644]
modules/dirent
modules/opendir [new file with mode: 0644]
modules/readdir [new file with mode: 0644]
modules/rewinddir [new file with mode: 0644]

index 30af537..3c17730 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2011-09-12  Bruno Haible  <bruno@clisp.org>
+
+       New modules 'opendir', 'readdir', 'rewinddir', 'closedir'.
+       * lib/dirent.in.h (struct dirent): New type.
+       (DT_UNKNOWN, DT_FIFO, DT_CHR, DT_DIR, DT_BLK, DT_REG, DT_LNK, DT_SOCK,
+       DT_WHT): New macros.
+       (DIR): New type.
+       (opendir, closedir): Declare only if the module 'opendir' is enabled.
+       (readdir, rewinddir): New declarations.
+       * lib/dirent-private.h: New file.
+       * lib/opendir.c: New file.
+       * lib/readdir.c: New file.
+       * lib/rewinddir.c: New file.
+       * lib/closedir.c: New file.
+       * lib/fchdir.c (rpl_closedir, rpl_opendir): Remove functions.
+       * m4/opendir.m4: New file.
+       * m4/readdir.m4: New file.
+       * m4/rewinddir.m4: New file.
+       * m4/closedir.m4: New file.
+       * m4/fchdir.m4 (gl_FUNC_FCHDIR): Don't set REPLACE_OPENDIR,
+       REPLACE_CLOSEDIR here.
+       * m4/dirent_h.m4 (gl_DIRENT_H): Also check whether closedir, opendir,
+       readdir, rewinddir are declared.
+       (gl_DIRENT_H_DEFAULTS): Initialize GNULIB_OPENDIR, GNULIB_READDIR,
+       GNULIB_REWINDDIR, GNULIB_CLOSEDIR, HAVE_OPENDIR, HAVE_READDIR,
+       HAVE_REWINDDIR, HAVE_CLOSEDIR.
+       * modules/dirent (Makefile.am): Substitute GNULIB_OPENDIR,
+       GNULIB_READDIR, GNULIB_REWINDDIR, GNULIB_CLOSEDIR, HAVE_OPENDIR,
+       HAVE_READDIR, HAVE_REWINDDIR, HAVE_CLOSEDIR.
+       * modules/opendir: New file.
+       * modules/readdir: New file.
+       * modules/rewinddir: New file.
+       * modules/closedir: New file.
+       * doc/posix-functions/opendir.texi: Mention the 'opendir' module.
+       * doc/posix-functions/readdir.texi: Mention the 'readdir' module.
+       * doc/posix-functions/rewinddir.texi: Mention the 'rewinddir' module.
+       * doc/posix-functions/closedir.texi: Mention the 'closedir' module.
+       * NEWS: Mention the 'fchdir' change.
+
 2011-09-11  Bruno Haible  <bruno@clisp.org>
 
        asm-underscore.m4: Support for MSVC.
diff --git a/NEWS b/NEWS
index 3905383..16c5a35 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,12 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2011-09-12  fchdir          This module no longer overrides the functions
+                            opendir() and closedir(), unless the modules
+                            'opendir' and 'closedir' are in use, respectively.
+                            If you use opendir(), please use module 'opendir'.
+                            If you use closedir(), please use module 'closedir'.
+
 2011-08-04  pathmax         The header file "pathmax.h" no longer defines
                             PATH_MAX on GNU/Hurd. Please use one of the methods
                             listed in pathmax.h to ensure your package is
index 487a179..c8a1d38 100644 (file)
@@ -4,15 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/closedir.html}
 
-Gnulib module: ---
+Gnulib module: closedir
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+MSVC 9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function is missing on some platforms:
-MSVC 9.
 @end itemize
index feb1af5..661790c 100644 (file)
@@ -4,18 +4,18 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/opendir.html}
 
-Gnulib module: ---
+Gnulib module: opendir
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+MSVC 9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-MSVC 9.
-@item
 On platforms where @code{off_t} is a 32-bit type, this function may not
 work correctly on huge directories larger than 2 GB.  Also, on platforms
 where @code{ino_t} is a 32-bit type, this function may report inode numbers
index 5325fd9..a69b068 100644 (file)
@@ -4,18 +4,18 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/readdir.html}
 
-Gnulib module: ---
+Gnulib module: readdir
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+MSVC 9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-MSVC 9.
-@item
 On platforms where @code{off_t} is a 32-bit type, this function may not
 work correctly on huge directories larger than 2 GB.  Also, on platforms
 where @code{ino_t} is a 32-bit type, this function may report inode numbers
index 6f789ce..47f8d4c 100644 (file)
@@ -4,18 +4,18 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/rewinddir.html}
 
-Gnulib module: ---
+Gnulib module: rewinddir
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+MSVC 9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-MSVC 9.
-@item
 On platforms where @code{long int} is a 32-bit type, this function may not
 work correctly on huge directories larger than 2 GB.  The fix is to use
 the @code{AC_SYS_LARGEFILE} macro (only on MacOS X systems).
diff --git a/lib/closedir.c b/lib/closedir.c
new file mode 100644 (file)
index 0000000..700d60e
--- /dev/null
@@ -0,0 +1,63 @@
+/* Stop reading the entries of a directory.
+   Copyright (C) 2006-2011 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <dirent.h>
+
+#if HAVE_CLOSEDIR
+
+/* Override closedir(), to keep track of the open file descriptors.
+   Needed because there is a function dirfd().  */
+
+#else
+
+# include <stdlib.h>
+
+# include "dirent-private.h"
+
+#endif
+
+int
+closedir (DIR *dirp)
+{
+# if REPLACE_FCHDIR
+  int fd = dirfd (dirp);
+# endif
+  int retval;
+
+#if HAVE_CLOSEDIR
+# undef closedir
+
+  retval = closedir (dirp);
+
+#else
+
+  if (dirp->current != INVALID_HANDLE_VALUE)
+    FindClose (dirp->current);
+  free (dirp);
+
+  retval = 0;
+
+#endif
+
+#if REPLACE_FCHDIR
+  if (retval >= 0)
+    _gl_unregister_fd (fd);
+#endif
+  return retval;
+}
diff --git a/lib/dirent-private.h b/lib/dirent-private.h
new file mode 100644 (file)
index 0000000..74632ff
--- /dev/null
@@ -0,0 +1,40 @@
+/* Private details of the DIR type.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DIRENT_PRIVATE_H
+#define _DIRENT_PRIVATE_H 1
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+struct gl_directory
+{
+  /* Status, or error code to produce in next readdir() call.
+     -2 means the end of the directory is already reached,
+     -1 means the entry was already filled by FindFirstFile,
+     0 means the entry needs to be filled using FindNextFile.
+     A positive value is an error code.  */
+  int status;
+  /* Handle, reading the directory, at current position.  */
+  HANDLE current;
+  /* Found directory entry.  */
+  WIN32_FIND_DATA entry;
+  /* Argument to pass to FindFirstFile.  It consists of the absolutized
+     directory name, followed by a directory separator and the wildcards.  */
+  char dir_name_mask[1];
+};
+
+#endif /* _DIRENT_PRIVATE_H */
index a8b3f49..cbcf841 100644 (file)
 /* Get ino_t.  Needed on some systems, including glibc 2.8.  */
 #include <sys/types.h>
 
+#if !@HAVE_DIRENT_H@
+/* Define types DIR and 'struct dirent'.  */
+# if !GNULIB_defined_struct_dirent
+struct dirent
+{
+  char d_type;
+  char d_name[1];
+};
+/* Possible values for 'd_type'.  */
+#  define DT_UNKNOWN 0
+#  define DT_FIFO    1          /* FIFO */
+#  define DT_CHR     2          /* character device */
+#  define DT_DIR     4          /* directory */
+#  define DT_BLK     6          /* block device */
+#  define DT_REG     8          /* regular file */
+#  define DT_LNK    10          /* symbolic link */
+#  define DT_SOCK   12          /* socket */
+#  define DT_WHT    14          /* whiteout */
+typedef struct gl_directory DIR;
+#  define GNULIB_defined_struct_dirent 1
+# endif
+#endif
+
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
 
 /* The definition of _GL_ARG_NONNULL is copied here.  */
 
 /* Declare overridden functions.  */
 
-#if @REPLACE_CLOSEDIR@
-# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#  define closedir rpl_closedir
+#if @GNULIB_OPENDIR@
+# if @REPLACE_OPENDIR@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef opendir
+#   define opendir rpl_opendir
+#  endif
+_GL_FUNCDECL_RPL (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (opendir, DIR *, (const char *dir_name));
+# else
+#  if !@HAVE_OPENDIR@
+_GL_FUNCDECL_SYS (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL ((1)));
+#  endif
+_GL_CXXALIAS_SYS (opendir, DIR *, (const char *dir_name));
+# endif
+_GL_CXXALIASWARN (opendir);
+#elif defined GNULIB_POSIXCHECK
+# undef opendir
+# if HAVE_RAW_DECL_OPENDIR
+_GL_WARN_ON_USE (opendir, "opendir is not portable - "
+                 "use gnulib module opendir for portability");
+# endif
+#endif
+
+#if @GNULIB_READDIR@
+# if !@HAVE_READDIR@
+_GL_FUNCDECL_SYS (readdir, struct dirent *, (DIR *dirp) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (readdir, struct dirent *, (DIR *dirp));
+_GL_CXXALIASWARN (readdir);
+#elif defined GNULIB_POSIXCHECK
+# undef readdir
+# if HAVE_RAW_DECL_READDIR
+_GL_WARN_ON_USE (readdir, "readdir is not portable - "
+                 "use gnulib module readdir for portability");
 # endif
-_GL_FUNCDECL_RPL (closedir, int, (DIR *) _GL_ARG_NONNULL ((1)));
-_GL_CXXALIAS_RPL (closedir, int, (DIR *));
-#else
-_GL_CXXALIAS_SYS (closedir, int, (DIR *));
 #endif
+
+#if @GNULIB_REWINDDIR@
+# if !@HAVE_REWINDDIR@
+_GL_FUNCDECL_SYS (rewinddir, void, (DIR *dirp) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (rewinddir, void, (DIR *dirp));
+_GL_CXXALIASWARN (rewinddir);
+#elif defined GNULIB_POSIXCHECK
+# undef rewinddir
+# if HAVE_RAW_DECL_REWINDDIR
+_GL_WARN_ON_USE (rewinddir, "rewinddir is not portable - "
+                 "use gnulib module rewinddir for portability");
+# endif
+#endif
+
+#if @GNULIB_CLOSEDIR@
+# if @REPLACE_CLOSEDIR@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef closedir
+#   define closedir rpl_closedir
+#  endif
+_GL_FUNCDECL_RPL (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (closedir, int, (DIR *dirp));
+# else
+#  if !@HAVE_CLOSEDIR@
+_GL_FUNCDECL_SYS (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
+#  endif
+_GL_CXXALIAS_SYS (closedir, int, (DIR *dirp));
+# endif
 _GL_CXXALIASWARN (closedir);
+#elif defined GNULIB_POSIXCHECK
+# undef closedir
+# if HAVE_RAW_DECL_CLOSEDIR
+_GL_WARN_ON_USE (closedir, "closedir is not portable - "
+                 "use gnulib module closedir for portability");
+# endif
+#endif
 
 #if @GNULIB_DIRFD@
 /* Return the file descriptor associated with the given directory stream,
@@ -111,17 +197,6 @@ _GL_WARN_ON_USE (fdopendir, "fdopendir is unportable - "
 # endif
 #endif
 
-#if @REPLACE_OPENDIR@
-# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#  define opendir rpl_opendir
-# endif
-_GL_FUNCDECL_RPL (opendir, DIR *, (const char *) _GL_ARG_NONNULL ((1)));
-_GL_CXXALIAS_RPL (opendir, DIR *, (const char *));
-#else
-_GL_CXXALIAS_SYS (opendir, DIR *, (const char *));
-#endif
-_GL_CXXALIASWARN (opendir);
-
 #if @GNULIB_SCANDIR@
 /* Scan the directory DIR, calling FILTER on each directory entry.
    Entries for which FILTER returns nonzero are individually malloc'd,
index 6dd704f..e13ba22 100644 (file)
@@ -211,42 +211,6 @@ rpl_fstat (int fd, struct stat *statbuf)
 }
 #endif
 
-/* Override opendir() and closedir(), to keep track of the open file
-   descriptors.  Needed because there is a function dirfd().  */
-
-int
-rpl_closedir (DIR *dp)
-#undef closedir
-{
-  int fd = dirfd (dp);
-  int retval = closedir (dp);
-
-  if (retval >= 0)
-    _gl_unregister_fd (fd);
-  return retval;
-}
-
-DIR *
-rpl_opendir (const char *filename)
-#undef opendir
-{
-  DIR *dp;
-
-  dp = opendir (filename);
-  if (dp != NULL)
-    {
-      int fd = dirfd (dp);
-      if (0 <= fd && _gl_register_fd (fd, filename) != fd)
-        {
-          int saved_errno = errno;
-          closedir (dp);
-          errno = saved_errno;
-          return NULL;
-        }
-    }
-  return dp;
-}
-
 /* Override dup(), to keep track of open file descriptors.  */
 
 int
diff --git a/lib/opendir.c b/lib/opendir.c
new file mode 100644 (file)
index 0000000..cb7f67c
--- /dev/null
@@ -0,0 +1,143 @@
+/* Start reading the entries of a directory.
+   Copyright (C) 2006-2011 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <dirent.h>
+
+#if HAVE_OPENDIR
+
+/* Override opendir(), to keep track of the open file descriptors.
+   Needed because there is a function dirfd().  */
+
+#else
+
+# include <errno.h>
+# include <stddef.h>
+# include <stdlib.h>
+
+# include "dirent-private.h"
+# include "filename.h"
+
+#endif
+
+DIR *
+opendir (const char *dir_name)
+{
+#if HAVE_OPENDIR
+# undef opendir
+  DIR *dirp;
+
+  dirp = opendir (dir_name);
+  if (dirp == NULL)
+    return NULL;
+
+#else
+
+  char dir_name_mask[MAX_PATH + 1 + 1 + 1];
+  int status;
+  HANDLE current;
+  WIN32_FIND_DATA entry;
+  struct gl_directory *dirp;
+
+  if (dir_name[0] == '\0')
+    {
+      errno = ENOENT;
+      return NULL;
+    }
+
+  /* Make the dir_name absolute, so that we continue reading the same
+     directory if the current directory changed between this opendir()
+     call and a subsequent rewinddir() call.  */
+  if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL))
+    {
+      errno = EINVAL;
+      return NULL;
+    }
+
+  /* Append the mask.
+     "*" and "*.*" appear to be equivalent.  */
+  {
+    char *p;
+
+    p = dir_name_mask + strlen (dir_name_mask);
+    if (p > dir_name_mask && !ISSLASH (p[-1]))
+      *p++ = '\\';
+    *p++ = '*';
+    *p = '\0';
+  }
+
+  /* Start searching the directory.  */
+  status = -1;
+  current = FindFirstFile (dir_name_mask, &entry);
+  if (current == INVALID_HANDLE_VALUE)
+    {
+      switch (GetLastError ())
+        {
+        case ERROR_FILE_NOT_FOUND:
+          status = -2;
+          break;
+        case ERROR_PATH_NOT_FOUND:
+          errno = ENOENT;
+          return NULL;
+        case ERROR_DIRECTORY:
+          errno = ENOTDIR;
+          return NULL;
+        case ERROR_ACCESS_DENIED:
+          errno = EACCES;
+          return NULL;
+        default:
+          errno = EIO;
+          return NULL;
+        }
+    }
+
+  /* Allocate the result.  */
+  dirp =
+    (struct gl_directory *)
+    malloc (offsetof (struct gl_directory, dir_name_mask[0])
+            + strlen (dir_name_mask) + 1);
+  if (dirp == NULL)
+    {
+      if (current != INVALID_HANDLE_VALUE)
+        FindClose (current);
+      errno = ENOMEM;
+      return NULL;
+    }
+  dirp->status = status;
+  dirp->current = current;
+  if (status == -1)
+    memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA));
+  strcpy (dirp->dir_name_mask, dir_name_mask);
+
+#endif
+
+#if REPLACE_FCHDIR
+  {
+    int fd = dirfd (dirp);
+    if (0 <= fd && _gl_register_fd (fd, dir_name) != fd)
+      {
+        int saved_errno = errno;
+        closedir (dirp);
+        errno = saved_errno;
+        return NULL;
+      }
+  }
+#endif
+
+  return dirp;
+}
diff --git a/lib/readdir.c b/lib/readdir.c
new file mode 100644 (file)
index 0000000..04858b0
--- /dev/null
@@ -0,0 +1,98 @@
+/* Read the next entry of a directory.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <dirent.h>
+
+#include <errno.h>
+#include <stddef.h>
+
+#include "dirent-private.h"
+
+struct dirent *
+readdir (DIR *dirp)
+{
+  char type;
+  struct dirent *result;
+
+  /* There is no need to add code to produce entries for "." and "..".
+     According to the POSIX:2008 section "4.12 Pathname Resolution"
+     <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html>
+     "." and ".." are syntactic entities.
+     POSIX also says:
+       "If entries for dot or dot-dot exist, one entry shall be returned
+        for dot and one entry shall be returned for dot-dot; otherwise,
+        they shall not be returned."  */
+
+  switch (dirp->status)
+    {
+    case -2:
+      /* End of directory already reached.  */
+      return NULL;
+    case -1:
+      break;
+    case 0:
+      if (!FindNextFile (dirp->current, &dirp->entry))
+        {
+          switch (GetLastError ())
+            {
+            case ERROR_NO_MORE_FILES:
+              dirp->status = -2;
+              return NULL;
+            default:
+              errno = EIO;
+              return NULL;
+            }
+        }
+      break;
+    default:
+      errno = dirp->status;
+      return NULL;
+    }
+
+  dirp->status = 0;
+
+  if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+    type = DT_DIR;
+  else if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+    type = DT_LNK;
+  else if ((dirp->entry.dwFileAttributes
+            & ~(FILE_ATTRIBUTE_READONLY
+                | FILE_ATTRIBUTE_HIDDEN
+                | FILE_ATTRIBUTE_SYSTEM
+                | FILE_ATTRIBUTE_ARCHIVE
+                | FILE_ATTRIBUTE_NORMAL
+                | FILE_ATTRIBUTE_TEMPORARY
+                | FILE_ATTRIBUTE_SPARSE_FILE
+                | FILE_ATTRIBUTE_COMPRESSED
+                | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
+                | FILE_ATTRIBUTE_ENCRYPTED)) == 0)
+    /* Devices like COM1, LPT1, NUL would also have the attributes 0x20 but
+       they cannot occur here.  */
+    type = DT_REG;
+  else
+    type = DT_UNKNOWN;
+
+  /* Reuse the memory of dirp->entry for the result.  */
+  result =
+    (struct dirent *)
+    ((char *) dirp->entry.cFileName - offsetof (struct dirent, d_name[0]));
+  result->d_type = type;
+
+  return result;
+}
diff --git a/lib/rewinddir.c b/lib/rewinddir.c
new file mode 100644 (file)
index 0000000..bfb9108
--- /dev/null
@@ -0,0 +1,49 @@
+/* Restart reading the entries of a directory from the beginning.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <dirent.h>
+
+#include <errno.h>
+
+#include "dirent-private.h"
+
+void
+rewinddir (DIR *dirp)
+{
+  /* Like in closedir().  */
+  if (dirp->current != INVALID_HANDLE_VALUE)
+    FindClose (dirp->current);
+
+  /* Like in opendir().  */
+  dirp->status = -1;
+  dirp->current = FindFirstFile (dirp->dir_name_mask, &dirp->entry);
+  if (dirp->current == INVALID_HANDLE_VALUE)
+    {
+      switch (GetLastError ())
+        {
+        case ERROR_FILE_NOT_FOUND:
+          dirp->status = -2;
+          break;
+        default:
+          /* Save the error code for the next readdir() call.  */
+          dirp->status = ENOENT;
+          break;
+        }
+    }
+}
diff --git a/m4/closedir.m4 b/m4/closedir.m4
new file mode 100644 (file)
index 0000000..1b7912a
--- /dev/null
@@ -0,0 +1,23 @@
+# closedir.m4 serial 1
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_CLOSEDIR],
+[
+  AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+  AC_CHECK_FUNCS([closedir])
+  if test $ac_cv_func_closedir = no; then
+    HAVE_CLOSEDIR=0
+  fi
+  dnl Replace closedir() for supporting the gnulib-defined fchdir() function,
+  dnl to keep fchdir's bookkeeping up-to-date.
+  m4_ifdef([gl_FUNC_FCHDIR], [
+    gl_TEST_FCHDIR
+    if test $HAVE_FCHDIR = 0; then
+      REPLACE_CLOSEDIR=1
+    fi
+  ])
+])
index 5ecfd83..ab45170 100644 (file)
@@ -1,4 +1,4 @@
-# dirent_h.m4 serial 15
+# dirent_h.m4 serial 16
 dnl Copyright (C) 2008-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -24,7 +24,7 @@ AC_DEFUN([gl_DIRENT_H],
   dnl Check for declarations of anything we want to poison if the
   dnl corresponding gnulib module is not in use.
   gl_WARN_ON_USE_PREPARE([[#include <dirent.h>
-    ]], [alphasort dirfd fdopendir scandir])
+    ]], [alphasort closedir dirfd fdopendir opendir readdir rewinddir scandir])
 ])
 
 AC_DEFUN([gl_DIRENT_MODULE_INDICATOR],
@@ -39,18 +39,26 @@ AC_DEFUN([gl_DIRENT_MODULE_INDICATOR],
 AC_DEFUN([gl_DIRENT_H_DEFAULTS],
 [
   AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR
+  GNULIB_OPENDIR=0;     AC_SUBST([GNULIB_OPENDIR])
+  GNULIB_READDIR=0;     AC_SUBST([GNULIB_READDIR])
+  GNULIB_REWINDDIR=0;   AC_SUBST([GNULIB_REWINDDIR])
+  GNULIB_CLOSEDIR=0;    AC_SUBST([GNULIB_CLOSEDIR])
   GNULIB_DIRFD=0;       AC_SUBST([GNULIB_DIRFD])
   GNULIB_FDOPENDIR=0;   AC_SUBST([GNULIB_FDOPENDIR])
   GNULIB_SCANDIR=0;     AC_SUBST([GNULIB_SCANDIR])
   GNULIB_ALPHASORT=0;   AC_SUBST([GNULIB_ALPHASORT])
   dnl Assume proper GNU behavior unless another module says otherwise.
+  HAVE_OPENDIR=1;       AC_SUBST([HAVE_OPENDIR])
+  HAVE_READDIR=1;       AC_SUBST([HAVE_READDIR])
+  HAVE_REWINDDIR=1;     AC_SUBST([HAVE_REWINDDIR])
+  HAVE_CLOSEDIR=1;      AC_SUBST([HAVE_CLOSEDIR])
   HAVE_DECL_DIRFD=1;    AC_SUBST([HAVE_DECL_DIRFD])
   HAVE_DECL_FDOPENDIR=1;AC_SUBST([HAVE_DECL_FDOPENDIR])
   HAVE_FDOPENDIR=1;     AC_SUBST([HAVE_FDOPENDIR])
   HAVE_SCANDIR=1;       AC_SUBST([HAVE_SCANDIR])
   HAVE_ALPHASORT=1;     AC_SUBST([HAVE_ALPHASORT])
+  REPLACE_OPENDIR=0;    AC_SUBST([REPLACE_OPENDIR])
   REPLACE_CLOSEDIR=0;   AC_SUBST([REPLACE_CLOSEDIR])
   REPLACE_DIRFD=0;      AC_SUBST([REPLACE_DIRFD])
   REPLACE_FDOPENDIR=0;  AC_SUBST([REPLACE_FDOPENDIR])
-  REPLACE_OPENDIR=0;    AC_SUBST([REPLACE_OPENDIR])
 ])
index a387dbb..e742a07 100644 (file)
@@ -1,4 +1,4 @@
-# fchdir.m4 serial 17
+# fchdir.m4 serial 18
 dnl Copyright (C) 2006-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -24,8 +24,6 @@ AC_DEFUN([gl_FUNC_FCHDIR],
     dnl We must also replace anything that can manipulate a directory fd,
     dnl to keep our bookkeeping up-to-date.  We don't have to replace
     dnl fstatat, since no platform has fstatat but lacks fchdir.
-    REPLACE_OPENDIR=1
-    REPLACE_CLOSEDIR=1
     REPLACE_DUP=1
     AC_CACHE_CHECK([whether open can visit directories],
       [gl_cv_func_open_directory_works],
diff --git a/m4/opendir.m4 b/m4/opendir.m4
new file mode 100644 (file)
index 0000000..fa315b9
--- /dev/null
@@ -0,0 +1,23 @@
+# opendir.m4 serial 1
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_OPENDIR],
+[
+  AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+  AC_CHECK_FUNCS([opendir])
+  if test $ac_cv_func_opendir = no; then
+    HAVE_OPENDIR=0
+  fi
+  dnl Replace opendir() for supporting the gnulib-defined fchdir() function,
+  dnl to keep fchdir's bookkeeping up-to-date.
+  m4_ifdef([gl_FUNC_FCHDIR], [
+    gl_TEST_FCHDIR
+    if test $HAVE_FCHDIR = 0; then
+      REPLACE_OPENDIR=1
+    fi
+  ])
+])
diff --git a/m4/readdir.m4 b/m4/readdir.m4
new file mode 100644 (file)
index 0000000..cfeed08
--- /dev/null
@@ -0,0 +1,15 @@
+# readdir.m4 serial 1
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_READDIR],
+[
+  AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+  AC_CHECK_FUNCS([readdir])
+  if test $ac_cv_func_readdir = no; then
+    HAVE_READDIR=0
+  fi
+])
diff --git a/m4/rewinddir.m4 b/m4/rewinddir.m4
new file mode 100644 (file)
index 0000000..b9b6b3d
--- /dev/null
@@ -0,0 +1,15 @@
+# rewinddir.m4 serial 1
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_REWINDDIR],
+[
+  AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+  AC_CHECK_FUNCS([rewinddir])
+  if test $ac_cv_func_rewinddir = no; then
+    HAVE_REWINDDIR=0
+  fi
+])
diff --git a/modules/closedir b/modules/closedir
new file mode 100644 (file)
index 0000000..1ebff9c
--- /dev/null
@@ -0,0 +1,28 @@
+Description:
+closedir() function: stop reading the entries of a directory
+
+Files:
+lib/closedir.c
+lib/dirent-private.h
+m4/closedir.m4
+
+Depends-on:
+dirent
+
+configure.ac:
+gl_FUNC_CLOSEDIR
+if test $HAVE_CLOSEDIR = 0 || test $REPLACE_CLOSEDIR = 1; then
+  AC_LIBOBJ([closedir])
+fi
+gl_DIRENT_MODULE_INDICATOR([closedir])
+
+Makefile.am:
+
+Include:
+<dirent.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
index 0fdf94b..6f615b4 100644 (file)
@@ -29,19 +29,27 @@ dirent.h: dirent.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_DIRENT_H''@|$(NEXT_DIRENT_H)|g' \
+             -e 's/@''GNULIB_OPENDIR''@/$(GNULIB_OPENDIR)/g' \
+             -e 's/@''GNULIB_READDIR''@/$(GNULIB_READDIR)/g' \
+             -e 's/@''GNULIB_REWINDDIR''@/$(GNULIB_REWINDDIR)/g' \
+             -e 's/@''GNULIB_CLOSEDIR''@/$(GNULIB_CLOSEDIR)/g' \
              -e 's/@''GNULIB_DIRFD''@/$(GNULIB_DIRFD)/g' \
              -e 's/@''GNULIB_FDOPENDIR''@/$(GNULIB_FDOPENDIR)/g' \
              -e 's/@''GNULIB_SCANDIR''@/$(GNULIB_SCANDIR)/g' \
              -e 's/@''GNULIB_ALPHASORT''@/$(GNULIB_ALPHASORT)/g' \
+             -e 's/@''HAVE_OPENDIR''@/$(HAVE_OPENDIR)/g' \
+             -e 's/@''HAVE_READDIR''@/$(HAVE_READDIR)/g' \
+             -e 's/@''HAVE_REWINDDIR''@/$(HAVE_REWINDDIR)/g' \
+             -e 's/@''HAVE_CLOSEDIR''@/$(HAVE_CLOSEDIR)/g' \
              -e 's|@''HAVE_DECL_DIRFD''@|$(HAVE_DECL_DIRFD)|g' \
              -e 's|@''HAVE_DECL_FDOPENDIR''@|$(HAVE_DECL_FDOPENDIR)|g' \
              -e 's|@''HAVE_FDOPENDIR''@|$(HAVE_FDOPENDIR)|g' \
              -e 's|@''HAVE_SCANDIR''@|$(HAVE_SCANDIR)|g' \
              -e 's|@''HAVE_ALPHASORT''@|$(HAVE_ALPHASORT)|g' \
+             -e 's|@''REPLACE_OPENDIR''@|$(REPLACE_OPENDIR)|g' \
              -e 's|@''REPLACE_CLOSEDIR''@|$(REPLACE_CLOSEDIR)|g' \
              -e 's|@''REPLACE_DIRFD''@|$(REPLACE_DIRFD)|g' \
              -e 's|@''REPLACE_FDOPENDIR''@|$(REPLACE_FDOPENDIR)|g' \
-             -e 's|@''REPLACE_OPENDIR''@|$(REPLACE_OPENDIR)|g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
              -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
diff --git a/modules/opendir b/modules/opendir
new file mode 100644 (file)
index 0000000..ede6d48
--- /dev/null
@@ -0,0 +1,30 @@
+Description:
+opendir() function: start reading the entries of a directory
+
+Files:
+lib/opendir.c
+lib/dirent-private.h
+m4/opendir.m4
+
+Depends-on:
+dirent
+largefile
+filename        [test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1]
+
+configure.ac:
+gl_FUNC_OPENDIR
+if test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1; then
+  AC_LIBOBJ([opendir])
+fi
+gl_DIRENT_MODULE_INDICATOR([opendir])
+
+Makefile.am:
+
+Include:
+<dirent.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
diff --git a/modules/readdir b/modules/readdir
new file mode 100644 (file)
index 0000000..487a888
--- /dev/null
@@ -0,0 +1,29 @@
+Description:
+readdir() function: read the next entry of a directory
+
+Files:
+lib/readdir.c
+lib/dirent-private.h
+m4/readdir.m4
+
+Depends-on:
+dirent
+largefile
+
+configure.ac:
+gl_FUNC_READDIR
+if test $HAVE_READDIR = 0; then
+  AC_LIBOBJ([readdir])
+fi
+gl_DIRENT_MODULE_INDICATOR([readdir])
+
+Makefile.am:
+
+Include:
+<dirent.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
diff --git a/modules/rewinddir b/modules/rewinddir
new file mode 100644 (file)
index 0000000..050cfe8
--- /dev/null
@@ -0,0 +1,30 @@
+Description:
+rewinddir() function: restart reading the entries of a directory from the
+beginning
+
+Files:
+lib/rewinddir.c
+lib/dirent-private.h
+m4/rewinddir.m4
+
+Depends-on:
+dirent
+largefile
+
+configure.ac:
+gl_FUNC_REWINDDIR
+if test $HAVE_REWINDDIR = 0; then
+  AC_LIBOBJ([rewinddir])
+fi
+gl_DIRENT_MODULE_INDICATOR([rewinddir])
+
+Makefile.am:
+
+Include:
+<dirent.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible