view lib/opendir.c @ 15610:de2ecfd7fc4a

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.
author Bruno Haible <bruno@clisp.org>
date Tue, 13 Sep 2011 01:37:35 +0200
parents
children 9fd376c9460f
line wrap: on
line source

/* 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;
}