Commit | Line | Data |
---|---|---|
c0c3707f | 1 | /* Core of implementation of fstat and stat for native Windows. |
9c9d63b1 | 2 | Copyright (C) 2017-2021 Free Software Foundation, Inc. |
c0c3707f CB |
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 | /* Written by Bruno Haible. */ | |
18 | ||
19 | #include <config.h> | |
20 | ||
21 | #if defined _WIN32 && ! defined __CYGWIN__ | |
22 | ||
9c9d63b1 PM |
23 | /* Attempt to make <windows.h> define FILE_ID_INFO. |
24 | But ensure that the redefinition of _WIN32_WINNT does not make us assume | |
25 | Windows Vista or newer when building for an older version of Windows. */ | |
26 | #if HAVE_SDKDDKVER_H | |
27 | # include <sdkddkver.h> | |
28 | # if _WIN32_WINNT >= _WIN32_WINNT_VISTA | |
29 | # define WIN32_ASSUME_VISTA 1 | |
30 | # else | |
31 | # define WIN32_ASSUME_VISTA 0 | |
32 | # endif | |
33 | # if !defined _WIN32_WINNT || (_WIN32_WINNT < _WIN32_WINNT_WIN8) | |
34 | # undef _WIN32_WINNT | |
35 | # define _WIN32_WINNT _WIN32_WINNT_WIN8 | |
36 | # endif | |
37 | #else | |
38 | # define WIN32_ASSUME_VISTA (_WIN32_WINNT >= _WIN32_WINNT_VISTA) | |
698be2d8 | 39 | #endif |
c0c3707f CB |
40 | |
41 | #include <sys/types.h> | |
42 | #include <sys/stat.h> | |
43 | #include <errno.h> | |
44 | #include <limits.h> | |
45 | #include <string.h> | |
46 | #include <unistd.h> | |
47 | #include <windows.h> | |
48 | ||
49 | /* Specification. */ | |
50 | #include "stat-w32.h" | |
51 | ||
52 | #include "pathmax.h" | |
53 | #include "verify.h" | |
54 | ||
698be2d8 CB |
55 | /* Don't assume that UNICODE is not defined. */ |
56 | #undef LoadLibrary | |
57 | #define LoadLibrary LoadLibraryA | |
58 | #undef GetFinalPathNameByHandle | |
59 | #define GetFinalPathNameByHandle GetFinalPathNameByHandleA | |
60 | ||
9c9d63b1 PM |
61 | /* Older mingw headers do not define VOLUME_NAME_NONE. */ |
62 | #ifndef VOLUME_NAME_NONE | |
63 | # define VOLUME_NAME_NONE 4 | |
64 | #endif | |
65 | ||
66 | #if !WIN32_ASSUME_VISTA | |
698be2d8 | 67 | |
c0c3707f | 68 | /* Avoid warnings from gcc -Wcast-function-type. */ |
698be2d8 CB |
69 | # define GetProcAddress \ |
70 | (void *) GetProcAddress | |
c0c3707f | 71 | |
698be2d8 | 72 | # if _GL_WINDOWS_STAT_INODES == 2 |
c0c3707f CB |
73 | /* GetFileInformationByHandleEx was introduced only in Windows Vista. */ |
74 | typedef DWORD (WINAPI * GetFileInformationByHandleExFuncType) (HANDLE hFile, | |
75 | FILE_INFO_BY_HANDLE_CLASS fiClass, | |
76 | LPVOID lpBuffer, | |
77 | DWORD dwBufferSize); | |
78 | static GetFileInformationByHandleExFuncType GetFileInformationByHandleExFunc = NULL; | |
698be2d8 | 79 | # endif |
c0c3707f CB |
80 | /* GetFinalPathNameByHandle was introduced only in Windows Vista. */ |
81 | typedef DWORD (WINAPI * GetFinalPathNameByHandleFuncType) (HANDLE hFile, | |
698be2d8 | 82 | LPSTR lpFilePath, |
c0c3707f CB |
83 | DWORD lenFilePath, |
84 | DWORD dwFlags); | |
85 | static GetFinalPathNameByHandleFuncType GetFinalPathNameByHandleFunc = NULL; | |
86 | static BOOL initialized = FALSE; | |
87 | ||
88 | static void | |
89 | initialize (void) | |
90 | { | |
91 | HMODULE kernel32 = LoadLibrary ("kernel32.dll"); | |
92 | if (kernel32 != NULL) | |
93 | { | |
698be2d8 | 94 | # if _GL_WINDOWS_STAT_INODES == 2 |
c0c3707f CB |
95 | GetFileInformationByHandleExFunc = |
96 | (GetFileInformationByHandleExFuncType) GetProcAddress (kernel32, "GetFileInformationByHandleEx"); | |
698be2d8 | 97 | # endif |
c0c3707f CB |
98 | GetFinalPathNameByHandleFunc = |
99 | (GetFinalPathNameByHandleFuncType) GetProcAddress (kernel32, "GetFinalPathNameByHandleA"); | |
100 | } | |
101 | initialized = TRUE; | |
102 | } | |
103 | ||
698be2d8 CB |
104 | #else |
105 | ||
106 | # define GetFileInformationByHandleExFunc GetFileInformationByHandleEx | |
107 | # define GetFinalPathNameByHandleFunc GetFinalPathNameByHandle | |
108 | ||
109 | #endif | |
110 | ||
c0c3707f CB |
111 | /* Converts a FILETIME to GMT time since 1970-01-01 00:00:00. */ |
112 | #if _GL_WINDOWS_STAT_TIMESPEC | |
113 | struct timespec | |
114 | _gl_convert_FILETIME_to_timespec (const FILETIME *ft) | |
115 | { | |
116 | struct timespec result; | |
117 | /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */ | |
118 | unsigned long long since_1601 = | |
119 | ((unsigned long long) ft->dwHighDateTime << 32) | |
120 | | (unsigned long long) ft->dwLowDateTime; | |
121 | if (since_1601 == 0) | |
122 | { | |
123 | result.tv_sec = 0; | |
124 | result.tv_nsec = 0; | |
125 | } | |
126 | else | |
127 | { | |
128 | /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89 | |
129 | leap years, in total 134774 days. */ | |
130 | unsigned long long since_1970 = | |
131 | since_1601 - (unsigned long long) 134774 * (unsigned long long) 86400 * (unsigned long long) 10000000; | |
132 | result.tv_sec = since_1970 / (unsigned long long) 10000000; | |
133 | result.tv_nsec = (unsigned long) (since_1970 % (unsigned long long) 10000000) * 100; | |
134 | } | |
135 | return result; | |
136 | } | |
137 | #else | |
138 | time_t | |
139 | _gl_convert_FILETIME_to_POSIX (const FILETIME *ft) | |
140 | { | |
141 | /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */ | |
142 | unsigned long long since_1601 = | |
143 | ((unsigned long long) ft->dwHighDateTime << 32) | |
144 | | (unsigned long long) ft->dwLowDateTime; | |
145 | if (since_1601 == 0) | |
146 | return 0; | |
147 | else | |
148 | { | |
149 | /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89 | |
150 | leap years, in total 134774 days. */ | |
151 | unsigned long long since_1970 = | |
152 | since_1601 - (unsigned long long) 134774 * (unsigned long long) 86400 * (unsigned long long) 10000000; | |
153 | return since_1970 / (unsigned long long) 10000000; | |
154 | } | |
155 | } | |
156 | #endif | |
157 | ||
158 | /* Fill *BUF with information about the file designated by H. | |
159 | PATH is the file name, if known, otherwise NULL. | |
160 | Return 0 if successful, or -1 with errno set upon failure. */ | |
161 | int | |
162 | _gl_fstat_by_handle (HANDLE h, const char *path, struct stat *buf) | |
163 | { | |
164 | /* GetFileType | |
165 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype> */ | |
166 | DWORD type = GetFileType (h); | |
167 | if (type == FILE_TYPE_DISK) | |
168 | { | |
9c9d63b1 | 169 | #if !WIN32_ASSUME_VISTA |
c0c3707f CB |
170 | if (!initialized) |
171 | initialize (); | |
698be2d8 | 172 | #endif |
c0c3707f CB |
173 | |
174 | /* st_mode can be determined through | |
175 | GetFileAttributesEx | |
176 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesexa> | |
177 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_win32_file_attribute_data> | |
178 | or through | |
179 | GetFileInformationByHandle | |
180 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle> | |
181 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information> | |
182 | or through | |
183 | GetFileInformationByHandleEx with argument FileBasicInfo | |
184 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex> | |
185 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_basic_info> | |
186 | The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ | |
187 | BY_HANDLE_FILE_INFORMATION info; | |
188 | if (! GetFileInformationByHandle (h, &info)) | |
189 | goto failed; | |
190 | ||
191 | /* Test for error conditions before starting to fill *buf. */ | |
192 | if (sizeof (buf->st_size) <= 4 && info.nFileSizeHigh > 0) | |
193 | { | |
194 | errno = EOVERFLOW; | |
195 | return -1; | |
196 | } | |
197 | ||
198 | #if _GL_WINDOWS_STAT_INODES | |
199 | /* st_ino can be determined through | |
200 | GetFileInformationByHandle | |
201 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle> | |
202 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information> | |
203 | as 64 bits, or through | |
204 | GetFileInformationByHandleEx with argument FileIdInfo | |
205 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex> | |
206 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_id_info> | |
207 | as 128 bits. | |
208 | The latter requires -D_WIN32_WINNT=_WIN32_WINNT_WIN8 or higher. */ | |
209 | /* Experiments show that GetFileInformationByHandleEx does not provide | |
210 | much more information than GetFileInformationByHandle: | |
211 | * The dwVolumeSerialNumber from GetFileInformationByHandle is equal | |
212 | to the low 32 bits of the 64-bit VolumeSerialNumber from | |
213 | GetFileInformationByHandleEx, and is apparently sufficient for | |
214 | identifying the device. | |
215 | * The nFileIndex from GetFileInformationByHandle is equal to the low | |
216 | 64 bits of the 128-bit FileId from GetFileInformationByHandleEx, | |
217 | and the high 64 bits of this 128-bit FileId are zero. | |
218 | * On a FAT file system, GetFileInformationByHandleEx fails with error | |
219 | ERROR_INVALID_PARAMETER, whereas GetFileInformationByHandle | |
220 | succeeds. | |
221 | * On a CIFS/SMB file system, GetFileInformationByHandleEx fails with | |
222 | error ERROR_INVALID_LEVEL, whereas GetFileInformationByHandle | |
223 | succeeds. */ | |
224 | # if _GL_WINDOWS_STAT_INODES == 2 | |
225 | if (GetFileInformationByHandleExFunc != NULL) | |
226 | { | |
227 | FILE_ID_INFO id; | |
228 | if (GetFileInformationByHandleExFunc (h, FileIdInfo, &id, sizeof (id))) | |
229 | { | |
230 | buf->st_dev = id.VolumeSerialNumber; | |
231 | verify (sizeof (ino_t) == sizeof (id.FileId)); | |
232 | memcpy (&buf->st_ino, &id.FileId, sizeof (ino_t)); | |
233 | goto ino_done; | |
234 | } | |
235 | else | |
236 | { | |
237 | switch (GetLastError ()) | |
238 | { | |
239 | case ERROR_INVALID_PARAMETER: /* older Windows version, or FAT */ | |
240 | case ERROR_INVALID_LEVEL: /* CIFS/SMB file system */ | |
241 | goto fallback; | |
242 | default: | |
243 | goto failed; | |
244 | } | |
245 | } | |
246 | } | |
247 | fallback: ; | |
248 | /* Fallback for older Windows versions. */ | |
249 | buf->st_dev = info.dwVolumeSerialNumber; | |
250 | buf->st_ino._gl_ino[0] = ((ULONGLONG) info.nFileIndexHigh << 32) | (ULONGLONG) info.nFileIndexLow; | |
251 | buf->st_ino._gl_ino[1] = 0; | |
252 | ino_done: ; | |
253 | # else /* _GL_WINDOWS_STAT_INODES == 1 */ | |
254 | buf->st_dev = info.dwVolumeSerialNumber; | |
255 | buf->st_ino = ((ULONGLONG) info.nFileIndexHigh << 32) | (ULONGLONG) info.nFileIndexLow; | |
256 | # endif | |
257 | #else | |
258 | /* st_ino is not wide enough for identifying a file on a device. | |
259 | Without st_ino, st_dev is pointless. */ | |
260 | buf->st_dev = 0; | |
261 | buf->st_ino = 0; | |
262 | #endif | |
263 | ||
264 | /* st_mode. */ | |
265 | unsigned int mode = | |
266 | /* XXX How to handle FILE_ATTRIBUTE_REPARSE_POINT ? */ | |
267 | ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR | S_IEXEC_UGO : _S_IFREG) | |
268 | | S_IREAD_UGO | |
269 | | ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE_UGO); | |
270 | if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) | |
271 | { | |
272 | /* Determine whether the file is executable by looking at the file | |
273 | name suffix. | |
274 | If the file name is already known, use it. Otherwise, for | |
275 | non-empty files, it can be determined through | |
276 | GetFinalPathNameByHandle | |
277 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea> | |
278 | or through | |
279 | GetFileInformationByHandleEx with argument FileNameInfo | |
280 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex> | |
281 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_name_info> | |
282 | Both require -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ | |
283 | if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0) | |
284 | { | |
285 | char fpath[PATH_MAX]; | |
286 | if (path != NULL | |
287 | || (GetFinalPathNameByHandleFunc != NULL | |
288 | && GetFinalPathNameByHandleFunc (h, fpath, sizeof (fpath), VOLUME_NAME_NONE) | |
289 | < sizeof (fpath) | |
290 | && (path = fpath, 1))) | |
291 | { | |
292 | const char *last_dot = NULL; | |
293 | const char *p; | |
294 | for (p = path; *p != '\0'; p++) | |
295 | if (*p == '.') | |
296 | last_dot = p; | |
297 | if (last_dot != NULL) | |
298 | { | |
299 | const char *suffix = last_dot + 1; | |
300 | if (_stricmp (suffix, "exe") == 0 | |
301 | || _stricmp (suffix, "bat") == 0 | |
302 | || _stricmp (suffix, "cmd") == 0 | |
303 | || _stricmp (suffix, "com") == 0) | |
304 | mode |= S_IEXEC_UGO; | |
305 | } | |
306 | } | |
307 | else | |
308 | /* Cannot determine file name. Pretend that it is executable. */ | |
309 | mode |= S_IEXEC_UGO; | |
310 | } | |
311 | } | |
312 | buf->st_mode = mode; | |
313 | ||
314 | /* st_nlink can be determined through | |
315 | GetFileInformationByHandle | |
316 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle> | |
317 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information> | |
318 | or through | |
319 | GetFileInformationByHandleEx with argument FileStandardInfo | |
320 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex> | |
321 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_standard_info> | |
322 | The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ | |
323 | buf->st_nlink = (info.nNumberOfLinks > SHRT_MAX ? SHRT_MAX : info.nNumberOfLinks); | |
324 | ||
325 | /* There's no easy way to map the Windows SID concept to an integer. */ | |
326 | buf->st_uid = 0; | |
327 | buf->st_gid = 0; | |
328 | ||
329 | /* st_rdev is irrelevant for normal files and directories. */ | |
330 | buf->st_rdev = 0; | |
331 | ||
332 | /* st_size can be determined through | |
333 | GetFileSizeEx | |
334 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfilesizeex> | |
335 | or through | |
336 | GetFileAttributesEx | |
337 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesexa> | |
338 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_win32_file_attribute_data> | |
339 | or through | |
340 | GetFileInformationByHandle | |
341 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle> | |
342 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information> | |
343 | or through | |
344 | GetFileInformationByHandleEx with argument FileStandardInfo | |
345 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex> | |
346 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_standard_info> | |
347 | The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ | |
348 | if (sizeof (buf->st_size) <= 4) | |
349 | /* Range check already done above. */ | |
350 | buf->st_size = info.nFileSizeLow; | |
351 | else | |
352 | buf->st_size = ((long long) info.nFileSizeHigh << 32) | (long long) info.nFileSizeLow; | |
353 | ||
354 | /* st_atime, st_mtime, st_ctime can be determined through | |
355 | GetFileTime | |
356 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletime> | |
357 | or through | |
358 | GetFileAttributesEx | |
359 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesexa> | |
360 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_win32_file_attribute_data> | |
361 | or through | |
362 | GetFileInformationByHandle | |
363 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle> | |
364 | <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information> | |
365 | or through | |
366 | GetFileInformationByHandleEx with argument FileBasicInfo | |
367 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex> | |
368 | <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_basic_info> | |
369 | The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ | |
370 | #if _GL_WINDOWS_STAT_TIMESPEC | |
371 | buf->st_atim = _gl_convert_FILETIME_to_timespec (&info.ftLastAccessTime); | |
372 | buf->st_mtim = _gl_convert_FILETIME_to_timespec (&info.ftLastWriteTime); | |
373 | buf->st_ctim = _gl_convert_FILETIME_to_timespec (&info.ftCreationTime); | |
374 | #else | |
375 | buf->st_atime = _gl_convert_FILETIME_to_POSIX (&info.ftLastAccessTime); | |
376 | buf->st_mtime = _gl_convert_FILETIME_to_POSIX (&info.ftLastWriteTime); | |
377 | buf->st_ctime = _gl_convert_FILETIME_to_POSIX (&info.ftCreationTime); | |
378 | #endif | |
379 | ||
380 | return 0; | |
381 | } | |
382 | else if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) | |
383 | { | |
384 | buf->st_dev = 0; | |
385 | #if _GL_WINDOWS_STAT_INODES == 2 | |
386 | buf->st_ino._gl_ino[0] = buf->st_ino._gl_ino[1] = 0; | |
387 | #else | |
388 | buf->st_ino = 0; | |
389 | #endif | |
390 | buf->st_mode = (type == FILE_TYPE_PIPE ? _S_IFIFO : _S_IFCHR); | |
391 | buf->st_nlink = 1; | |
392 | buf->st_uid = 0; | |
393 | buf->st_gid = 0; | |
394 | buf->st_rdev = 0; | |
395 | if (type == FILE_TYPE_PIPE) | |
396 | { | |
397 | /* PeekNamedPipe | |
398 | <https://msdn.microsoft.com/en-us/library/aa365779.aspx> */ | |
399 | DWORD bytes_available; | |
400 | if (PeekNamedPipe (h, NULL, 0, NULL, &bytes_available, NULL)) | |
401 | buf->st_size = bytes_available; | |
402 | else | |
403 | buf->st_size = 0; | |
404 | } | |
405 | else | |
406 | buf->st_size = 0; | |
407 | #if _GL_WINDOWS_STAT_TIMESPEC | |
408 | buf->st_atim.tv_sec = 0; buf->st_atim.tv_nsec = 0; | |
409 | buf->st_mtim.tv_sec = 0; buf->st_mtim.tv_nsec = 0; | |
410 | buf->st_ctim.tv_sec = 0; buf->st_ctim.tv_nsec = 0; | |
411 | #else | |
412 | buf->st_atime = 0; | |
413 | buf->st_mtime = 0; | |
414 | buf->st_ctime = 0; | |
415 | #endif | |
416 | return 0; | |
417 | } | |
418 | else | |
419 | { | |
420 | errno = ENOENT; | |
421 | return -1; | |
422 | } | |
423 | ||
424 | failed: | |
425 | { | |
426 | DWORD error = GetLastError (); | |
427 | #if 0 | |
428 | fprintf (stderr, "_gl_fstat_by_handle error 0x%x\n", (unsigned int) error); | |
429 | #endif | |
430 | switch (error) | |
431 | { | |
432 | case ERROR_ACCESS_DENIED: | |
433 | case ERROR_SHARING_VIOLATION: | |
434 | errno = EACCES; | |
435 | break; | |
436 | ||
437 | case ERROR_OUTOFMEMORY: | |
438 | errno = ENOMEM; | |
439 | break; | |
440 | ||
441 | case ERROR_WRITE_FAULT: | |
442 | case ERROR_READ_FAULT: | |
443 | case ERROR_GEN_FAILURE: | |
444 | errno = EIO; | |
445 | break; | |
446 | ||
447 | default: | |
448 | errno = EINVAL; | |
449 | break; | |
450 | } | |
451 | return -1; | |
452 | } | |
453 | } | |
454 | ||
455 | #else | |
456 | ||
457 | /* This declaration is solely to ensure that after preprocessing | |
458 | this file is never empty. */ | |
459 | typedef int dummy; | |
460 | ||
461 | #endif |