Home | History | Annotate | Line # | Download | only in import
opendir.c revision 1.1.1.2
      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 }
    180