Commit | Line | Data |
---|---|---|
6ec2e0f5 | 1 | /* Start reading the entries of a directory. |
5df4cba6 | 2 | Copyright (C) 2006-2020 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 | ||
48 | DIR * | |
49 | opendir (const char *dir_name) | |
50 | { | |
51 | #if HAVE_OPENDIR | |
52 | # undef opendir | |
53 | DIR *dirp; | |
54 | ||
55 | dirp = opendir (dir_name); | |
56 | if (dirp == NULL) | |
57 | return NULL; | |
58 | ||
59 | # ifdef __KLIBC__ | |
60 | { | |
61 | int fd = open (dir_name, O_RDONLY); | |
62 | if (fd == -1 || _gl_register_dirp_fd (fd, dirp)) | |
63 | { | |
64 | int saved_errno = errno; | |
65 | ||
66 | close (fd); | |
67 | closedir (dirp); | |
68 | ||
69 | errno = saved_errno; | |
70 | ||
71 | return NULL; | |
72 | } | |
73 | } | |
74 | # endif | |
75 | #else | |
76 | ||
77 | char dir_name_mask[MAX_PATH + 1 + 1 + 1]; | |
78 | int status; | |
79 | HANDLE current; | |
80 | WIN32_FIND_DATA entry; | |
81 | struct gl_directory *dirp; | |
82 | ||
83 | if (dir_name[0] == '\0') | |
84 | { | |
85 | errno = ENOENT; | |
86 | return NULL; | |
87 | } | |
88 | ||
89 | /* Make the dir_name absolute, so that we continue reading the same | |
90 | directory if the current directory changed between this opendir() | |
91 | call and a subsequent rewinddir() call. */ | |
92 | if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL)) | |
93 | { | |
94 | errno = EINVAL; | |
95 | return NULL; | |
96 | } | |
97 | ||
98 | /* Append the mask. | |
99 | "*" and "*.*" appear to be equivalent. */ | |
100 | { | |
101 | char *p; | |
102 | ||
103 | p = dir_name_mask + strlen (dir_name_mask); | |
104 | if (p > dir_name_mask && !ISSLASH (p[-1])) | |
105 | *p++ = '\\'; | |
106 | *p++ = '*'; | |
107 | *p = '\0'; | |
108 | } | |
109 | ||
110 | /* Start searching the directory. */ | |
111 | status = -1; | |
112 | current = FindFirstFile (dir_name_mask, &entry); | |
113 | if (current == INVALID_HANDLE_VALUE) | |
114 | { | |
115 | switch (GetLastError ()) | |
116 | { | |
117 | case ERROR_FILE_NOT_FOUND: | |
118 | status = -2; | |
119 | break; | |
120 | case ERROR_PATH_NOT_FOUND: | |
121 | errno = ENOENT; | |
122 | return NULL; | |
123 | case ERROR_DIRECTORY: | |
124 | errno = ENOTDIR; | |
125 | return NULL; | |
126 | case ERROR_ACCESS_DENIED: | |
127 | errno = EACCES; | |
128 | return NULL; | |
129 | default: | |
130 | errno = EIO; | |
131 | return NULL; | |
132 | } | |
133 | } | |
134 | ||
135 | /* Allocate the result. */ | |
136 | dirp = | |
137 | (struct gl_directory *) | |
138 | malloc (offsetof (struct gl_directory, dir_name_mask[0]) | |
139 | + strlen (dir_name_mask) + 1); | |
140 | if (dirp == NULL) | |
141 | { | |
142 | if (current != INVALID_HANDLE_VALUE) | |
143 | FindClose (current); | |
144 | errno = ENOMEM; | |
145 | return NULL; | |
146 | } | |
147 | dirp->status = status; | |
148 | dirp->current = current; | |
149 | if (status == -1) | |
150 | memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA)); | |
151 | strcpy (dirp->dir_name_mask, dir_name_mask); | |
152 | ||
153 | #endif | |
154 | ||
155 | #if REPLACE_FCHDIR | |
156 | { | |
157 | int fd = dirfd (dirp); | |
158 | if (0 <= fd && _gl_register_fd (fd, dir_name) != fd) | |
159 | { | |
160 | int saved_errno = errno; | |
161 | closedir (dirp); | |
162 | errno = saved_errno; | |
163 | return NULL; | |
164 | } | |
165 | } | |
166 | #endif | |
167 | ||
168 | return dirp; | |
169 | } |