Commit | Line | Data |
---|---|---|
1db20bfd JG |
1 | /* |
2 | * msvcrt.dll errno functions | |
3 | * | |
4 | * Copyright 2000 Jon Griffiths | |
0799c1a7 AJ |
5 | * |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, write to the Free Software | |
360a3f91 | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
1db20bfd JG |
19 | */ |
20 | ||
e7f75c5d FG |
21 | #include <stdio.h> |
22 | #include <string.h> | |
4f3b7f84 | 23 | #include <stdarg.h> |
33929be4 | 24 | |
4f3b7f84 AJ |
25 | #include "ntstatus.h" |
26 | #define WIN32_NO_STATUS | |
27 | #include "windef.h" | |
28 | #include "winternl.h" | |
03774624 | 29 | #include "msvcrt.h" |
4f3b7f84 | 30 | #include "excpt.h" |
bd1689ec AJ |
31 | #include "wine/debug.h" |
32 | ||
33 | WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); | |
1db20bfd | 34 | |
401ead5c | 35 | /* error strings generated with glibc strerror */ |
28486da9 AJ |
36 | static char str_success[] = "Success"; |
37 | static char str_EPERM[] = "Operation not permitted"; | |
38 | static char str_ENOENT[] = "No such file or directory"; | |
39 | static char str_ESRCH[] = "No such process"; | |
40 | static char str_EINTR[] = "Interrupted system call"; | |
41 | static char str_EIO[] = "Input/output error"; | |
42 | static char str_ENXIO[] = "No such device or address"; | |
43 | static char str_E2BIG[] = "Argument list too long"; | |
44 | static char str_ENOEXEC[] = "Exec format error"; | |
45 | static char str_EBADF[] = "Bad file descriptor"; | |
46 | static char str_ECHILD[] = "No child processes"; | |
47 | static char str_EAGAIN[] = "Resource temporarily unavailable"; | |
48 | static char str_ENOMEM[] = "Cannot allocate memory"; | |
49 | static char str_EACCES[] = "Permission denied"; | |
50 | static char str_EFAULT[] = "Bad address"; | |
51 | static char str_EBUSY[] = "Device or resource busy"; | |
52 | static char str_EEXIST[] = "File exists"; | |
53 | static char str_EXDEV[] = "Invalid cross-device link"; | |
54 | static char str_ENODEV[] = "No such device"; | |
55 | static char str_ENOTDIR[] = "Not a directory"; | |
56 | static char str_EISDIR[] = "Is a directory"; | |
57 | static char str_EINVAL[] = "Invalid argument"; | |
58 | static char str_ENFILE[] = "Too many open files in system"; | |
59 | static char str_EMFILE[] = "Too many open files"; | |
60 | static char str_ENOTTY[] = "Inappropriate ioctl for device"; | |
61 | static char str_EFBIG[] = "File too large"; | |
62 | static char str_ENOSPC[] = "No space left on device"; | |
63 | static char str_ESPIPE[] = "Illegal seek"; | |
64 | static char str_EROFS[] = "Read-only file system"; | |
65 | static char str_EMLINK[] = "Too many links"; | |
66 | static char str_EPIPE[] = "Broken pipe"; | |
67 | static char str_EDOM[] = "Numerical argument out of domain"; | |
68 | static char str_ERANGE[] = "Numerical result out of range"; | |
69 | static char str_EDEADLK[] = "Resource deadlock avoided"; | |
70 | static char str_ENAMETOOLONG[] = "File name too long"; | |
71 | static char str_ENOLCK[] = "No locks available"; | |
72 | static char str_ENOSYS[] = "Function not implemented"; | |
73 | static char str_ENOTEMPTY[] = "Directory not empty"; | |
74 | static char str_EILSEQ[] = "Invalid or incomplete multibyte or wide character"; | |
75 | static char str_generic_error[] = "Unknown error"; | |
401ead5c AJ |
76 | |
77 | char *MSVCRT__sys_errlist[] = | |
78 | { | |
79 | str_success, | |
80 | str_EPERM, | |
81 | str_ENOENT, | |
82 | str_ESRCH, | |
83 | str_EINTR, | |
84 | str_EIO, | |
85 | str_ENXIO, | |
86 | str_E2BIG, | |
87 | str_ENOEXEC, | |
88 | str_EBADF, | |
89 | str_ECHILD, | |
90 | str_EAGAIN, | |
91 | str_ENOMEM, | |
92 | str_EACCES, | |
93 | str_EFAULT, | |
94 | str_generic_error, | |
95 | str_EBUSY, | |
96 | str_EEXIST, | |
97 | str_EXDEV, | |
98 | str_ENODEV, | |
99 | str_ENOTDIR, | |
100 | str_EISDIR, | |
101 | str_EINVAL, | |
102 | str_ENFILE, | |
103 | str_EMFILE, | |
104 | str_ENOTTY, | |
105 | str_generic_error, | |
106 | str_EFBIG, | |
107 | str_ENOSPC, | |
108 | str_ESPIPE, | |
109 | str_EROFS, | |
110 | str_EMLINK, | |
111 | str_EPIPE, | |
112 | str_EDOM, | |
113 | str_ERANGE, | |
114 | str_generic_error, | |
115 | str_EDEADLK, | |
116 | str_generic_error, | |
117 | str_ENAMETOOLONG, | |
118 | str_ENOLCK, | |
119 | str_ENOSYS, | |
120 | str_ENOTEMPTY, | |
121 | str_EILSEQ, | |
122 | str_generic_error | |
123 | }; | |
124 | ||
125 | unsigned int MSVCRT__sys_nerr = sizeof(MSVCRT__sys_errlist)/sizeof(MSVCRT__sys_errlist[0]) - 1; | |
4f3b7f84 AJ |
126 | |
127 | static MSVCRT_invalid_parameter_handler invalid_parameter_handler = NULL; | |
1db20bfd JG |
128 | |
129 | /* INTERNAL: Set the crt and dos errno's from the OS error given. */ | |
03774624 | 130 | void msvcrt_set_errno(int err) |
1db20bfd | 131 | { |
44b4235a | 132 | int *errno = MSVCRT__errno(); |
82f175e9 | 133 | MSVCRT_ulong *doserrno = MSVCRT___doserrno(); |
1db20bfd JG |
134 | |
135 | *doserrno = err; | |
136 | ||
137 | switch(err) | |
138 | { | |
139 | #define ERR_CASE(oserr) case oserr: | |
cb08534a | 140 | #define ERR_MAPS(oserr, crterr) case oserr: *errno = crterr; break |
1db20bfd JG |
141 | ERR_CASE(ERROR_ACCESS_DENIED) |
142 | ERR_CASE(ERROR_NETWORK_ACCESS_DENIED) | |
143 | ERR_CASE(ERROR_CANNOT_MAKE) | |
144 | ERR_CASE(ERROR_SEEK_ON_DEVICE) | |
145 | ERR_CASE(ERROR_LOCK_FAILED) | |
146 | ERR_CASE(ERROR_FAIL_I24) | |
147 | ERR_CASE(ERROR_CURRENT_DIRECTORY) | |
148 | ERR_CASE(ERROR_DRIVE_LOCKED) | |
149 | ERR_CASE(ERROR_NOT_LOCKED) | |
150 | ERR_CASE(ERROR_INVALID_ACCESS) | |
b5d86403 | 151 | ERR_CASE(ERROR_SHARING_VIOLATION) |
1db20bfd JG |
152 | ERR_MAPS(ERROR_LOCK_VIOLATION, MSVCRT_EACCES); |
153 | ERR_CASE(ERROR_FILE_NOT_FOUND) | |
154 | ERR_CASE(ERROR_NO_MORE_FILES) | |
155 | ERR_CASE(ERROR_BAD_PATHNAME) | |
156 | ERR_CASE(ERROR_BAD_NETPATH) | |
157 | ERR_CASE(ERROR_INVALID_DRIVE) | |
158 | ERR_CASE(ERROR_BAD_NET_NAME) | |
159 | ERR_CASE(ERROR_FILENAME_EXCED_RANGE) | |
160 | ERR_MAPS(ERROR_PATH_NOT_FOUND, MSVCRT_ENOENT); | |
161 | ERR_MAPS(ERROR_IO_DEVICE, MSVCRT_EIO); | |
162 | ERR_MAPS(ERROR_BAD_FORMAT, MSVCRT_ENOEXEC); | |
163 | ERR_MAPS(ERROR_INVALID_HANDLE, MSVCRT_EBADF); | |
164 | ERR_CASE(ERROR_OUTOFMEMORY) | |
165 | ERR_CASE(ERROR_INVALID_BLOCK) | |
166 | ERR_CASE(ERROR_NOT_ENOUGH_QUOTA); | |
167 | ERR_MAPS(ERROR_ARENA_TRASHED, MSVCRT_ENOMEM); | |
168 | ERR_MAPS(ERROR_BUSY, MSVCRT_EBUSY); | |
169 | ERR_CASE(ERROR_ALREADY_EXISTS) | |
170 | ERR_MAPS(ERROR_FILE_EXISTS, MSVCRT_EEXIST); | |
171 | ERR_MAPS(ERROR_BAD_DEVICE, MSVCRT_ENODEV); | |
172 | ERR_MAPS(ERROR_TOO_MANY_OPEN_FILES, MSVCRT_EMFILE); | |
173 | ERR_MAPS(ERROR_DISK_FULL, MSVCRT_ENOSPC); | |
174 | ERR_MAPS(ERROR_BROKEN_PIPE, MSVCRT_EPIPE); | |
175 | ERR_MAPS(ERROR_POSSIBLE_DEADLOCK, MSVCRT_EDEADLK); | |
176 | ERR_MAPS(ERROR_DIR_NOT_EMPTY, MSVCRT_ENOTEMPTY); | |
177 | ERR_MAPS(ERROR_BAD_ENVIRONMENT, MSVCRT_E2BIG); | |
178 | ERR_CASE(ERROR_WAIT_NO_CHILDREN) | |
179 | ERR_MAPS(ERROR_CHILD_NOT_COMPLETE, MSVCRT_ECHILD); | |
180 | ERR_CASE(ERROR_NO_PROC_SLOTS) | |
181 | ERR_CASE(ERROR_MAX_THRDS_REACHED) | |
182 | ERR_MAPS(ERROR_NESTING_NOT_ALLOWED, MSVCRT_EAGAIN); | |
183 | default: | |
184 | /* Remaining cases map to EINVAL */ | |
185 | /* FIXME: may be missing some errors above */ | |
186 | *errno = MSVCRT_EINVAL; | |
187 | } | |
188 | } | |
189 | ||
190 | /********************************************************************* | |
191 | * _errno (MSVCRT.@) | |
192 | */ | |
24beabfd | 193 | int* CDECL MSVCRT__errno(void) |
1db20bfd | 194 | { |
821f4775 | 195 | return &msvcrt_get_thread_data()->thread_errno; |
1db20bfd JG |
196 | } |
197 | ||
198 | /********************************************************************* | |
199 | * __doserrno (MSVCRT.@) | |
200 | */ | |
82f175e9 | 201 | MSVCRT_ulong* CDECL MSVCRT___doserrno(void) |
1db20bfd | 202 | { |
821f4775 | 203 | return &msvcrt_get_thread_data()->thread_doserrno; |
1db20bfd JG |
204 | } |
205 | ||
1db20bfd JG |
206 | /********************************************************************* |
207 | * strerror (MSVCRT.@) | |
208 | */ | |
24beabfd | 209 | char* CDECL MSVCRT_strerror(int err) |
1db20bfd | 210 | { |
2dacd3c5 AJ |
211 | thread_data_t *data = msvcrt_get_thread_data(); |
212 | ||
213 | if (!data->strerror_buffer) | |
214 | if (!(data->strerror_buffer = MSVCRT_malloc(256))) return NULL; | |
215 | ||
216 | if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr; | |
217 | strcpy( data->strerror_buffer, MSVCRT__sys_errlist[err] ); | |
218 | return data->strerror_buffer; | |
1db20bfd JG |
219 | } |
220 | ||
221 | /********************************************************************** | |
222 | * _strerror (MSVCRT.@) | |
223 | */ | |
24beabfd | 224 | char* CDECL _strerror(const char* str) |
1db20bfd | 225 | { |
2dacd3c5 AJ |
226 | thread_data_t *data = msvcrt_get_thread_data(); |
227 | int err; | |
228 | ||
229 | if (!data->strerror_buffer) | |
230 | if (!(data->strerror_buffer = MSVCRT_malloc(256))) return NULL; | |
231 | ||
232 | err = data->thread_errno; | |
233 | if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr; | |
234 | ||
235 | if (str && *str) | |
236 | sprintf( data->strerror_buffer, "%s: %s\n", str, MSVCRT__sys_errlist[err] ); | |
237 | else | |
238 | sprintf( data->strerror_buffer, "%s\n", MSVCRT__sys_errlist[err] ); | |
239 | ||
240 | return data->strerror_buffer; | |
1db20bfd JG |
241 | } |
242 | ||
1db20bfd JG |
243 | /********************************************************************* |
244 | * perror (MSVCRT.@) | |
245 | */ | |
24beabfd | 246 | void CDECL MSVCRT_perror(const char* str) |
1db20bfd | 247 | { |
2dacd3c5 AJ |
248 | int err = *MSVCRT__errno(); |
249 | if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr; | |
250 | ||
251 | if (str && *str) | |
252 | { | |
6bbd3cac TC |
253 | MSVCRT__write( 2, str, strlen(str) ); |
254 | MSVCRT__write( 2, ": ", 2 ); | |
2dacd3c5 | 255 | } |
6bbd3cac TC |
256 | MSVCRT__write( 2, MSVCRT__sys_errlist[err], strlen(MSVCRT__sys_errlist[err]) ); |
257 | MSVCRT__write( 2, "\n", 1 ); | |
1db20bfd | 258 | } |
70d1136c AJ |
259 | |
260 | /****************************************************************************** | |
261 | * _set_error_mode (MSVCRT.@) | |
262 | * | |
263 | * Set the error mode, which describes where the C run-time writes error | |
264 | * messages. | |
265 | * | |
266 | * PARAMS | |
267 | * mode - the new error mode | |
268 | * | |
269 | * RETURNS | |
270 | * The old error mode. | |
271 | * | |
272 | * TODO | |
273 | * This function does not have a proper implementation; the error mode is | |
274 | * never used. | |
275 | */ | |
24beabfd | 276 | int CDECL _set_error_mode(int mode) |
70d1136c | 277 | { |
03774624 | 278 | static int current_mode = MSVCRT__OUT_TO_DEFAULT; |
70d1136c AJ |
279 | |
280 | const int old = current_mode; | |
03774624 | 281 | if ( MSVCRT__REPORT_ERRMODE != mode ) { |
70d1136c AJ |
282 | current_mode = mode; |
283 | FIXME("dummy implementation (old mode: %d, new mode: %d)\n", | |
284 | old, mode); | |
285 | } | |
286 | return old; | |
287 | } | |
dec198af AJ |
288 | |
289 | /****************************************************************************** | |
290 | * _seterrormode (MSVCRT.@) | |
291 | */ | |
24beabfd | 292 | void CDECL _seterrormode(int mode) |
dec198af AJ |
293 | { |
294 | SetErrorMode( mode ); | |
295 | } | |
abb74600 | 296 | |
4f3b7f84 AJ |
297 | /****************************************************************************** |
298 | * _invalid_parameter (MSVCRT.@) | |
299 | */ | |
300 | void __cdecl MSVCRT__invalid_parameter(const MSVCRT_wchar_t *expr, const MSVCRT_wchar_t *func, | |
301 | const MSVCRT_wchar_t *file, unsigned int line, MSVCRT_uintptr_t arg) | |
302 | { | |
303 | if (invalid_parameter_handler) invalid_parameter_handler( expr, func, file, line, arg ); | |
304 | else | |
305 | { | |
306 | ERR( "%s:%u %s: %s %lx\n", debugstr_w(file), line, debugstr_w(func), debugstr_w(expr), arg ); | |
307 | RaiseException( STATUS_INVALID_CRUNTIME_PARAMETER, EXCEPTION_NONCONTINUABLE, 0, NULL ); | |
308 | } | |
309 | } | |
310 | ||
abb74600 PC |
311 | /* _get_invalid_parameter_handler - not exported in native msvcrt, added in msvcr80 */ |
312 | MSVCRT_invalid_parameter_handler CDECL _get_invalid_parameter_handler(void) | |
313 | { | |
314 | TRACE("\n"); | |
4f3b7f84 | 315 | return invalid_parameter_handler; |
abb74600 PC |
316 | } |
317 | ||
318 | /* _set_invalid_parameter_handler - not exproted in native msvcrt, added in msvcr80 */ | |
319 | MSVCRT_invalid_parameter_handler CDECL _set_invalid_parameter_handler( | |
320 | MSVCRT_invalid_parameter_handler handler) | |
321 | { | |
4f3b7f84 | 322 | MSVCRT_invalid_parameter_handler old = invalid_parameter_handler; |
abb74600 PC |
323 | |
324 | TRACE("(%p)\n", handler); | |
325 | ||
4f3b7f84 | 326 | invalid_parameter_handler = handler; |
abb74600 PC |
327 | return old; |
328 | } |