opendir.c revision 1.1.1.1
1/* Start reading the entries of a directory. 2 Copyright (C) 2006-2020 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program 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 General Public License for more details. 13 14 You should have received a copy of the GNU 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 58DIR * 59opendir (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