(root)/
sed-4.9/
gnulib-tests/
opendir.c
       1  /* Start reading the entries of a directory.
       2     Copyright (C) 2006-2022 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <dirent.h>
      21  
      22  #include <errno.h>
      23  #include <stddef.h>
      24  
      25  #if HAVE_OPENDIR
      26  
      27  /* Override opendir(), to keep track of the open file descriptors.
      28     Needed because there is a function dirfd().  */
      29  
      30  #else
      31  
      32  # include <stdlib.h>
      33  
      34  # include "dirent-private.h"
      35  # include "filename.h"
      36  
      37  #endif
      38  
      39  #if REPLACE_FCHDIR
      40  # include <unistd.h>
      41  #endif
      42  
      43  #ifdef __KLIBC__
      44  # include <io.h>
      45  # include <fcntl.h>
      46  #endif
      47  
      48  #if defined _WIN32 && ! defined __CYGWIN__
      49  /* Don't assume that UNICODE is not defined.  */
      50  # undef WIN32_FIND_DATA
      51  # define WIN32_FIND_DATA WIN32_FIND_DATAA
      52  # undef GetFullPathName
      53  # define GetFullPathName GetFullPathNameA
      54  # undef FindFirstFile
      55  # define FindFirstFile FindFirstFileA
      56  #endif
      57  
      58  DIR *
      59  opendir (const char *dir_name)
      60  {
      61  #if HAVE_OPENDIR
      62  # undef opendir
      63    DIR *dirp;
      64  
      65    dirp = opendir (dir_name);
      66    if (dirp == NULL)
      67      return NULL;
      68  
      69  # ifdef __KLIBC__
      70    {
      71      int fd = open (dir_name, O_RDONLY);
      72      if (fd == -1 || _gl_register_dirp_fd (fd, dirp))
      73        {
      74          int saved_errno = errno;
      75  
      76          close (fd);
      77          closedir (dirp);
      78  
      79          errno = saved_errno;
      80  
      81          return NULL;
      82        }
      83    }
      84  # endif
      85  #else
      86  
      87    char dir_name_mask[MAX_PATH + 1 + 1 + 1];
      88    int status;
      89    HANDLE current;
      90    WIN32_FIND_DATA entry;
      91    struct gl_directory *dirp;
      92  
      93    if (dir_name[0] == '\0')
      94      {
      95        errno = ENOENT;
      96        return NULL;
      97      }
      98  
      99    /* Make the dir_name absolute, so that we continue reading the same
     100       directory if the current directory changed between this opendir()
     101       call and a subsequent rewinddir() call.  */
     102    if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL))
     103      {
     104        errno = EINVAL;
     105        return NULL;
     106      }
     107  
     108    /* Append the mask.
     109       "*" and "*.*" appear to be equivalent.  */
     110    {
     111      char *p;
     112  
     113      p = dir_name_mask + strlen (dir_name_mask);
     114      if (p > dir_name_mask && !ISSLASH (p[-1]))
     115        *p++ = '\\';
     116      *p++ = '*';
     117      *p = '\0';
     118    }
     119  
     120    /* Start searching the directory.  */
     121    status = -1;
     122    current = FindFirstFile (dir_name_mask, &entry);
     123    if (current == INVALID_HANDLE_VALUE)
     124      {
     125        switch (GetLastError ())
     126          {
     127          case ERROR_FILE_NOT_FOUND:
     128            status = -2;
     129            break;
     130          case ERROR_PATH_NOT_FOUND:
     131            errno = ENOENT;
     132            return NULL;
     133          case ERROR_DIRECTORY:
     134            errno = ENOTDIR;
     135            return NULL;
     136          case ERROR_ACCESS_DENIED:
     137            errno = EACCES;
     138            return NULL;
     139          default:
     140            errno = EIO;
     141            return NULL;
     142          }
     143      }
     144  
     145    /* Allocate the result.  */
     146    dirp =
     147      (struct gl_directory *)
     148      malloc (offsetof (struct gl_directory, dir_name_mask[0])
     149              + strlen (dir_name_mask) + 1);
     150    if (dirp == NULL)
     151      {
     152        if (current != INVALID_HANDLE_VALUE)
     153          FindClose (current);
     154        errno = ENOMEM;
     155        return NULL;
     156      }
     157    dirp->status = status;
     158    dirp->current = current;
     159    if (status == -1)
     160      memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA));
     161    strcpy (dirp->dir_name_mask, dir_name_mask);
     162  
     163  #endif
     164  
     165  #if REPLACE_FCHDIR
     166    {
     167      int fd = dirfd (dirp);
     168      if (0 <= fd && _gl_register_fd (fd, dir_name) != fd)
     169        {
     170          int saved_errno = errno;
     171          closedir (dirp);
     172          errno = saved_errno;
     173          return NULL;
     174        }
     175    }
     176  #endif
     177  
     178    return dirp;
     179  }