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