Commit | Line | Data |
---|---|---|
6ec2e0f5 | 1 | /* Start reading the entries of a directory. |
9c9d63b1 | 2 | Copyright (C) 2006-2021 Free Software Foundation, Inc. |
6ec2e0f5 SDJ |
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 | |
c0c3707f | 15 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
6ec2e0f5 SDJ |
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 | ||
698be2d8 CB |
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 | ||
6ec2e0f5 SDJ |
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 | } |