From 994c21f30d225cd35a8fa57851df8bc6bd66d97f Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 13 Sep 2011 01:37:35 +0200 Subject: [PATCH] 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. --- ChangeLog | 39 ++++++++++ NEWS | 6 ++ doc/posix-functions/closedir.texi | 8 +-- doc/posix-functions/opendir.texi | 8 +-- doc/posix-functions/readdir.texi | 8 +-- doc/posix-functions/rewinddir.texi | 8 +-- lib/closedir.c | 63 ++++++++++++++++ lib/dirent-private.h | 40 +++++++++++ lib/dirent.in.h | 111 +++++++++++++++++++++++----- lib/fchdir.c | 36 ---------- lib/opendir.c | 143 +++++++++++++++++++++++++++++++++++++ lib/readdir.c | 98 +++++++++++++++++++++++++ lib/rewinddir.c | 49 +++++++++++++ m4/closedir.m4 | 23 ++++++ m4/dirent_h.m4 | 14 +++- m4/fchdir.m4 | 4 +- m4/opendir.m4 | 23 ++++++ m4/readdir.m4 | 15 ++++ m4/rewinddir.m4 | 15 ++++ modules/closedir | 28 ++++++++ modules/dirent | 10 ++- modules/opendir | 30 ++++++++ modules/readdir | 29 ++++++++ modules/rewinddir | 30 ++++++++ 24 files changed, 761 insertions(+), 77 deletions(-) create mode 100644 lib/closedir.c create mode 100644 lib/dirent-private.h create mode 100644 lib/opendir.c create mode 100644 lib/readdir.c create mode 100644 lib/rewinddir.c create mode 100644 m4/closedir.m4 create mode 100644 m4/opendir.m4 create mode 100644 m4/readdir.m4 create mode 100644 m4/rewinddir.m4 create mode 100644 modules/closedir create mode 100644 modules/opendir create mode 100644 modules/readdir create mode 100644 modules/rewinddir diff --git a/ChangeLog b/ChangeLog index 30af537ca..3c177306c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2011-09-12 Bruno Haible + + 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 asm-underscore.m4: Support for MSVC. diff --git a/NEWS b/NEWS index 390538358..16c5a3528 100644 --- 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 diff --git a/doc/posix-functions/closedir.texi b/doc/posix-functions/closedir.texi index 487a179b4..c8a1d386d 100644 --- a/doc/posix-functions/closedir.texi +++ b/doc/posix-functions/closedir.texi @@ -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 diff --git a/doc/posix-functions/opendir.texi b/doc/posix-functions/opendir.texi index feb1af546..661790cc4 100644 --- a/doc/posix-functions/opendir.texi +++ b/doc/posix-functions/opendir.texi @@ -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 diff --git a/doc/posix-functions/readdir.texi b/doc/posix-functions/readdir.texi index 5325fd9a4..a69b06843 100644 --- a/doc/posix-functions/readdir.texi +++ b/doc/posix-functions/readdir.texi @@ -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 diff --git a/doc/posix-functions/rewinddir.texi b/doc/posix-functions/rewinddir.texi index 6f789ce9b..47f8d4c02 100644 --- a/doc/posix-functions/rewinddir.texi +++ b/doc/posix-functions/rewinddir.texi @@ -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 index 000000000..700d60eeb --- /dev/null +++ b/lib/closedir.c @@ -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 . */ + +#include + +/* Specification. */ +#include + +#if HAVE_CLOSEDIR + +/* Override closedir(), to keep track of the open file descriptors. + Needed because there is a function dirfd(). */ + +#else + +# include + +# 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 index 000000000..74632ff39 --- /dev/null +++ b/lib/dirent-private.h @@ -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 . */ + +#ifndef _DIRENT_PRIVATE_H +#define _DIRENT_PRIVATE_H 1 + +#define WIN32_LEAN_AND_MEAN +#include + +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 */ diff --git a/lib/dirent.in.h b/lib/dirent.in.h index a8b3f490a..cbcf841df 100644 --- a/lib/dirent.in.h +++ b/lib/dirent.in.h @@ -32,6 +32,29 @@ /* Get ino_t. Needed on some systems, including glibc 2.8. */ #include +#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. */ @@ -41,16 +64,79 @@ /* 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, diff --git a/lib/fchdir.c b/lib/fchdir.c index 6dd704f62..e13ba2249 100644 --- a/lib/fchdir.c +++ b/lib/fchdir.c @@ -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 index 000000000..cb7f67c10 --- /dev/null +++ b/lib/opendir.c @@ -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 . */ + +#include + +/* Specification. */ +#include + +#if HAVE_OPENDIR + +/* Override opendir(), to keep track of the open file descriptors. + Needed because there is a function dirfd(). */ + +#else + +# include +# include +# include + +# 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 index 000000000..04858b008 --- /dev/null +++ b/lib/readdir.c @@ -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 . */ + +#include + +/* Specification. */ +#include + +#include +#include + +#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" + + "." 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 index 000000000..bfb91084b --- /dev/null +++ b/lib/rewinddir.c @@ -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 . */ + +#include + +/* Specification. */ +#include + +#include + +#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 index 000000000..1b7912a30 --- /dev/null +++ b/m4/closedir.m4 @@ -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 + ]) +]) diff --git a/m4/dirent_h.m4 b/m4/dirent_h.m4 index 5ecfd8305..ab45170b9 100644 --- a/m4/dirent_h.m4 +++ b/m4/dirent_h.m4 @@ -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 - ]], [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]) ]) diff --git a/m4/fchdir.m4 b/m4/fchdir.m4 index a387dbb4f..e742a0732 100644 --- a/m4/fchdir.m4 +++ b/m4/fchdir.m4 @@ -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 index 000000000..fa315b983 --- /dev/null +++ b/m4/opendir.m4 @@ -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 index 000000000..cfeed0890 --- /dev/null +++ b/m4/readdir.m4 @@ -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 index 000000000..b9b6b3d0b --- /dev/null +++ b/m4/rewinddir.m4 @@ -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 index 000000000..1ebff9cca --- /dev/null +++ b/modules/closedir @@ -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: + + +License: +LGPL + +Maintainer: +Bruno Haible diff --git a/modules/dirent b/modules/dirent index 0fdf94b37..6f615b496 100644 --- a/modules/dirent +++ b/modules/dirent @@ -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 index 000000000..ede6d48a3 --- /dev/null +++ b/modules/opendir @@ -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: + + +License: +LGPL + +Maintainer: +Bruno Haible diff --git a/modules/readdir b/modules/readdir new file mode 100644 index 000000000..487a888a1 --- /dev/null +++ b/modules/readdir @@ -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: + + +License: +LGPL + +Maintainer: +Bruno Haible diff --git a/modules/rewinddir b/modules/rewinddir new file mode 100644 index 000000000..050cfe8cc --- /dev/null +++ b/modules/rewinddir @@ -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: + + +License: +LGPL + +Maintainer: +Bruno Haible -- 2.11.0