Blame lib/opendir.c

Packit Service a2489d
/* Start reading the entries of a directory.
Packit Service a2489d
   Copyright (C) 2006-2018 Free Software Foundation, Inc.
Packit Service a2489d
Packit Service a2489d
   This program is free software: you can redistribute it and/or modify
Packit Service a2489d
   it under the terms of the GNU General Public License as published by
Packit Service a2489d
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
   (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   This program is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
   GNU General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public License
Packit Service a2489d
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
Packit Service a2489d
/* Specification.  */
Packit Service a2489d
#include <dirent.h>
Packit Service a2489d
Packit Service a2489d
#include <errno.h>
Packit Service a2489d
#include <stddef.h>
Packit Service a2489d
Packit Service a2489d
#if HAVE_OPENDIR
Packit Service a2489d
Packit Service a2489d
/* Override opendir(), to keep track of the open file descriptors.
Packit Service a2489d
   Needed because there is a function dirfd().  */
Packit Service a2489d
Packit Service a2489d
#else
Packit Service a2489d
Packit Service a2489d
# include <stdlib.h>
Packit Service a2489d
Packit Service a2489d
# include "dirent-private.h"
Packit Service a2489d
# include "filename.h"
Packit Service a2489d
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#if REPLACE_FCHDIR
Packit Service a2489d
# include <unistd.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#ifdef __KLIBC__
Packit Service a2489d
# include <io.h>
Packit Service a2489d
# include <fcntl.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
DIR *
Packit Service a2489d
opendir (const char *dir_name)
Packit Service a2489d
{
Packit Service a2489d
#if HAVE_OPENDIR
Packit Service a2489d
# undef opendir
Packit Service a2489d
  DIR *dirp;
Packit Service a2489d
Packit Service a2489d
  dirp = opendir (dir_name);
Packit Service a2489d
  if (dirp == NULL)
Packit Service a2489d
    return NULL;
Packit Service a2489d
Packit Service a2489d
# ifdef __KLIBC__
Packit Service a2489d
  {
Packit Service a2489d
    int fd = open (dir_name, O_RDONLY);
Packit Service a2489d
    if (fd == -1 || _gl_register_dirp_fd (fd, dirp))
Packit Service a2489d
      {
Packit Service a2489d
        int saved_errno = errno;
Packit Service a2489d
Packit Service a2489d
        close (fd);
Packit Service a2489d
        closedir (dirp);
Packit Service a2489d
Packit Service a2489d
        errno = saved_errno;
Packit Service a2489d
Packit Service a2489d
        return NULL;
Packit Service a2489d
      }
Packit Service a2489d
  }
Packit Service a2489d
# endif
Packit Service a2489d
#else
Packit Service a2489d
Packit Service a2489d
  char dir_name_mask[MAX_PATH + 1 + 1 + 1];
Packit Service a2489d
  int status;
Packit Service a2489d
  HANDLE current;
Packit Service a2489d
  WIN32_FIND_DATA entry;
Packit Service a2489d
  struct gl_directory *dirp;
Packit Service a2489d
Packit Service a2489d
  if (dir_name[0] == '\0')
Packit Service a2489d
    {
Packit Service a2489d
      errno = ENOENT;
Packit Service a2489d
      return NULL;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* Make the dir_name absolute, so that we continue reading the same
Packit Service a2489d
     directory if the current directory changed between this opendir()
Packit Service a2489d
     call and a subsequent rewinddir() call.  */
Packit Service a2489d
  if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL))
Packit Service a2489d
    {
Packit Service a2489d
      errno = EINVAL;
Packit Service a2489d
      return NULL;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* Append the mask.
Packit Service a2489d
     "*" and "*.*" appear to be equivalent.  */
Packit Service a2489d
  {
Packit Service a2489d
    char *p;
Packit Service a2489d
Packit Service a2489d
    p = dir_name_mask + strlen (dir_name_mask);
Packit Service a2489d
    if (p > dir_name_mask && !ISSLASH (p[-1]))
Packit Service a2489d
      *p++ = '\\';
Packit Service a2489d
    *p++ = '*';
Packit Service a2489d
    *p = '\0';
Packit Service a2489d
  }
Packit Service a2489d
Packit Service a2489d
  /* Start searching the directory.  */
Packit Service a2489d
  status = -1;
Packit Service a2489d
  current = FindFirstFile (dir_name_mask, &entry);
Packit Service a2489d
  if (current == INVALID_HANDLE_VALUE)
Packit Service a2489d
    {
Packit Service a2489d
      switch (GetLastError ())
Packit Service a2489d
        {
Packit Service a2489d
        case ERROR_FILE_NOT_FOUND:
Packit Service a2489d
          status = -2;
Packit Service a2489d
          break;
Packit Service a2489d
        case ERROR_PATH_NOT_FOUND:
Packit Service a2489d
          errno = ENOENT;
Packit Service a2489d
          return NULL;
Packit Service a2489d
        case ERROR_DIRECTORY:
Packit Service a2489d
          errno = ENOTDIR;
Packit Service a2489d
          return NULL;
Packit Service a2489d
        case ERROR_ACCESS_DENIED:
Packit Service a2489d
          errno = EACCES;
Packit Service a2489d
          return NULL;
Packit Service a2489d
        default:
Packit Service a2489d
          errno = EIO;
Packit Service a2489d
          return NULL;
Packit Service a2489d
        }
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* Allocate the result.  */
Packit Service a2489d
  dirp =
Packit Service a2489d
    (struct gl_directory *)
Packit Service a2489d
    malloc (offsetof (struct gl_directory, dir_name_mask[0])
Packit Service a2489d
            + strlen (dir_name_mask) + 1);
Packit Service a2489d
  if (dirp == NULL)
Packit Service a2489d
    {
Packit Service a2489d
      if (current != INVALID_HANDLE_VALUE)
Packit Service a2489d
        FindClose (current);
Packit Service a2489d
      errno = ENOMEM;
Packit Service a2489d
      return NULL;
Packit Service a2489d
    }
Packit Service a2489d
  dirp->status = status;
Packit Service a2489d
  dirp->current = current;
Packit Service a2489d
  if (status == -1)
Packit Service a2489d
    memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA));
Packit Service a2489d
  strcpy (dirp->dir_name_mask, dir_name_mask);
Packit Service a2489d
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#if REPLACE_FCHDIR
Packit Service a2489d
  {
Packit Service a2489d
    int fd = dirfd (dirp);
Packit Service a2489d
    if (0 <= fd && _gl_register_fd (fd, dir_name) != fd)
Packit Service a2489d
      {
Packit Service a2489d
        int saved_errno = errno;
Packit Service a2489d
        closedir (dirp);
Packit Service a2489d
        errno = saved_errno;
Packit Service a2489d
        return NULL;
Packit Service a2489d
      }
Packit Service a2489d
  }
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
  return dirp;
Packit Service a2489d
}