Imported Upstream version 4.4
[platform/upstream/make.git] / src / w32 / compat / dirent.c
1 /* Directory entry code for Window platforms.
2 Copyright (C) 1996-2022 Free Software Foundation, Inc.
3 This file is part of GNU Make.
4
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
8 version.
9
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program.  If not, see <https://www.gnu.org/licenses/>.  */
16
17
18 #include <config.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include "dirent.h"
25
26 #ifndef __MINGW32__
27 DIR*
28 opendir(const char* pDirName)
29 {
30         struct stat sb;
31         DIR*    pDir;
32         char*   pEndDirName;
33         size_t  nBufferLen;
34
35         /* sanity checks */
36         if (!pDirName) {
37                 errno = EINVAL;
38                 return NULL;
39         }
40         if (stat(pDirName, &sb) != 0) {
41                 errno = ENOENT;
42                 return NULL;
43         }
44         if ((sb.st_mode & S_IFMT) != S_IFDIR) {
45                 errno = ENOTDIR;
46                 return NULL;
47         }
48
49         /* allocate a DIR structure to return */
50         pDir = (DIR *) malloc(sizeof (DIR));
51
52         if (!pDir)
53                 return NULL;
54
55         /* input directory name length */
56         nBufferLen = strlen(pDirName);
57
58         /* copy input directory name to DIR buffer */
59         strcpy(pDir->dir_pDirectoryName, pDirName);
60
61         /* point to end of the copied directory name */
62         pEndDirName = &pDir->dir_pDirectoryName[nBufferLen - 1];
63
64         /* if directory name did not end in '/' or '\', add '/' */
65         if ((*pEndDirName != '/') && (*pEndDirName != '\\')) {
66                 pEndDirName++;
67                 *pEndDirName = '/';
68         }
69
70         /* now append the wildcard character to the buffer */
71         pEndDirName++;
72         *pEndDirName = '*';
73         pEndDirName++;
74         *pEndDirName = '\0';
75
76         /* other values defaulted */
77         pDir->dir_nNumFiles = 0;
78         pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
79         pDir->dir_ulCookie = __DIRENT_COOKIE;
80
81         return pDir;
82 }
83
84 void
85 closedir(DIR *pDir)
86 {
87         /* got a valid pointer? */
88         if (!pDir) {
89                 errno = EINVAL;
90                 return;
91         }
92
93         /* sanity check that this is a DIR pointer */
94         if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
95                 errno = EINVAL;
96                 return;
97         }
98
99         /* close the WINDOWS32 directory handle */
100         if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
101                 FindClose(pDir->dir_hDirHandle);
102
103         free(pDir);
104
105         return;
106 }
107
108 struct dirent *
109 readdir(DIR* pDir)
110 {
111         WIN32_FIND_DATA wfdFindData;
112
113         if (!pDir) {
114                 errno = EINVAL;
115                 return NULL;
116         }
117
118         /* sanity check that this is a DIR pointer */
119         if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
120                 errno = EINVAL;
121                 return NULL;
122         }
123
124         if (pDir->dir_nNumFiles == 0) {
125                 pDir->dir_hDirHandle = FindFirstFile(pDir->dir_pDirectoryName, &wfdFindData);
126                 if (pDir->dir_hDirHandle == INVALID_HANDLE_VALUE)
127                         return NULL;
128         } else if (!FindNextFile(pDir->dir_hDirHandle, &wfdFindData))
129                         return NULL;
130
131         /* bump count for next call to readdir() */
132         pDir->dir_nNumFiles++;
133
134         /* fill in struct dirent values */
135         pDir->dir_sdReturn.d_ino = (ino_t)-1;
136         strcpy(pDir->dir_sdReturn.d_name, wfdFindData.cFileName);
137
138         if (wfdFindData.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
139           pDir->dir_sdReturn.d_type = DT_CHR;
140         else if (wfdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
141           pDir->dir_sdReturn.d_type = DT_DIR;
142         else
143           pDir->dir_sdReturn.d_type = DT_REG;
144
145         return &pDir->dir_sdReturn;
146 }
147
148 void
149 rewinddir(DIR* pDir)
150 {
151         if (!pDir) {
152                 errno = EINVAL;
153                 return;
154         }
155
156         /* sanity check that this is a DIR pointer */
157         if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
158                 errno = EINVAL;
159                 return;
160         }
161
162         /* close the WINDOWS32 directory handle */
163         if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
164                 if (!FindClose(pDir->dir_hDirHandle))
165                         errno = EBADF;
166
167         /* reset members which control readdir() */
168         pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
169         pDir->dir_nNumFiles = 0;
170
171         return;
172 }
173
174 void
175 seekdir(DIR* pDir, long nPosition)
176 {
177         if (!pDir)
178                 return;
179
180         /* sanity check that this is a DIR pointer */
181         if (pDir->dir_ulCookie != __DIRENT_COOKIE)
182                 return;
183
184         /* go back to beginning of directory */
185         rewinddir(pDir);
186
187         /* loop until we have found position we care about */
188         for (--nPosition; nPosition && readdir(pDir); nPosition--);
189
190         /* flag invalid nPosition value */
191         if (nPosition)
192                 errno = EINVAL;
193
194         return;
195 }
196 #endif  /* !__MINGW32__ */