]> git.proxmox.com Git - ceph.git/blob - ceph/src/pmdk/src/core/util_windows.c
import ceph 16.2.7
[ceph.git] / ceph / src / pmdk / src / core / util_windows.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2015-2020, Intel Corporation */
3
4 /*
5 * util_windows.c -- misc utilities with OS-specific implementation
6 */
7
8 #include <errno.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <tchar.h>
12
13 #include "alloc.h"
14 #include "util.h"
15 #include "out.h"
16 #include "os.h"
17
18 /* Windows CRT doesn't support all errors, add unmapped here */
19 #define ENOTSUP_STR "Operation not supported"
20 #define ECANCELED_STR "Operation canceled"
21 #define ENOERROR 0
22 #define ENOERROR_STR "Success"
23 #define UNMAPPED_STR "Unmapped error"
24
25 /*
26 * util_strerror -- return string describing error number
27 *
28 * XXX: There are many other POSIX error codes that are not recognized by
29 * strerror_s(), so eventually we may want to implement this in a similar
30 * fashion as strsignal().
31 */
32 void
33 util_strerror(int errnum, char *buff, size_t bufflen)
34 {
35 switch (errnum) {
36 case ENOERROR:
37 strcpy_s(buff, bufflen, ENOERROR_STR);
38 break;
39 case ENOTSUP:
40 strcpy_s(buff, bufflen, ENOTSUP_STR);
41 break;
42 case ECANCELED:
43 strcpy_s(buff, bufflen, ECANCELED_STR);
44 break;
45 default:
46 if (strerror_s(buff, bufflen, errnum))
47 strcpy_s(buff, bufflen, UNMAPPED_STR);
48 }
49 }
50
51 /*
52 * util_strwinerror -- return string describing windows error codes
53 */
54 void
55 util_strwinerror(unsigned long err, char *buff, size_t bufflen)
56 {
57 wchar_t *error_str;
58
59 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
60 FORMAT_MESSAGE_FROM_SYSTEM |
61 FORMAT_MESSAGE_IGNORE_INSERTS,
62 NULL,
63 err,
64 0,
65 (LPWSTR)&error_str,
66 0, NULL) == 0) {
67 sprintf_s(buff, bufflen, "GetLastError() == %lu", err);
68 return;
69 }
70
71 if (util_toUTF8_buff(error_str, buff, bufflen)) {
72 LocalFree(error_str);
73 sprintf_s(buff, bufflen, "GetLastError() == %lu", err);
74 return;
75 }
76
77 /* let's do the error message without '\r' and '\n' at the end */
78 size_t len = strlen(buff);
79 for (size_t i = len - 1; i > 0; i--) {
80 if (buff[i] != '\r' && buff[i] != '\n') {
81 buff[i + 1] = '\0';
82 break;
83 }
84 }
85
86 LocalFree(error_str);
87 }
88
89 /*
90 * util_part_realpath -- get canonicalized absolute pathname for a part file
91 *
92 * On Windows, paths cannot be symlinks and paths used in a poolset have to
93 * be absolute (checked when parsing a poolset file), so we just return
94 * the path.
95 */
96 char *
97 util_part_realpath(const char *path)
98 {
99 return strdup(path);
100 }
101
102 /*
103 * util_compare_file_inodes -- compare device and inodes of two files
104 */
105 int
106 util_compare_file_inodes(const char *path1, const char *path2)
107 {
108 return strcmp(path1, path2) != 0;
109 }
110
111 /*
112 * util_aligned_malloc -- allocate aligned memory
113 */
114 void *
115 util_aligned_malloc(size_t alignment, size_t size)
116 {
117 return _aligned_malloc(size, alignment);
118 }
119
120 /*
121 * util_aligned_free -- free allocated memory in util_aligned_malloc
122 */
123 void
124 util_aligned_free(void *ptr)
125 {
126 _aligned_free(ptr);
127 }
128
129 /*
130 * util_toUTF8 -- allocating conversion from wide char string to UTF8
131 */
132 char *
133 util_toUTF8(const wchar_t *wstr)
134 {
135 int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr, -1,
136 NULL, 0, NULL, NULL);
137 if (size == 0)
138 goto err;
139
140 char *str = Malloc(size * sizeof(char));
141 if (str == NULL)
142 goto out;
143
144 if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr, -1, str,
145 size, NULL, NULL) == 0) {
146 Free(str);
147 goto err;
148 }
149
150 out:
151 return str;
152
153 err:
154 errno = EINVAL;
155 return NULL;
156 }
157
158 /*
159 * util_free_UTF8 -- free UTF8 string
160 */
161 void util_free_UTF8(char *str) {
162 Free(str);
163 }
164
165 /*
166 * util_toUTF16 -- allocating conversion from UTF8 to wide char string
167 */
168 wchar_t *
169 util_toUTF16(const char *str)
170 {
171 int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1,
172 NULL, 0);
173 if (size == 0)
174 goto err;
175
176 wchar_t *wstr = Malloc(size * sizeof(wchar_t));
177 if (wstr == NULL)
178 goto out;
179
180 if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, wstr,
181 size) == 0) {
182 Free(wstr);
183 goto err;
184 }
185
186 out:
187 return wstr;
188
189 err:
190 errno = EINVAL;
191 return NULL;
192 }
193
194 /*
195 * util_free_UTF16 -- free wide char string
196 */
197 void
198 util_free_UTF16(wchar_t *wstr)
199 {
200 Free(wstr);
201 }
202
203 /*
204 * util_toUTF16_buff -- non-allocating conversion from UTF8 to wide char string
205 *
206 * The user responsible for supplying a large enough out buffer.
207 */
208 int
209 util_toUTF16_buff(const char *in, wchar_t *out, size_t out_size)
210 {
211 ASSERT(out != NULL);
212
213 int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, in,
214 -1, NULL, 0);
215 if (size == 0 || out_size < size)
216 goto err;
217
218 if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, in, -1,
219 out, size) == 0)
220 goto err;
221
222 return 0;
223 err:
224 errno = EINVAL;
225 return -1;
226 }
227
228 /*
229 * util_toUTF8_buff -- non-allocating conversion from wide char string to UTF8
230 *
231 * The user responsible for supplying a large enough out buffer.
232 */
233 int
234 util_toUTF8_buff(const wchar_t *in, char *out, size_t out_size)
235 {
236 ASSERT(out != NULL);
237
238 int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, -1,
239 NULL, 0, NULL, NULL);
240 if (size == 0 || out_size < size)
241 goto err;
242
243 if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, -1,
244 out, size, NULL, NULL) == 0)
245 goto err;
246
247 return 0;
248 err:
249 errno = EINVAL;
250 return -1;
251 }
252
253 /*
254 * util_getexecname -- return name of current executable
255 */
256 char *
257 util_getexecname(char *path, size_t pathlen)
258 {
259 ssize_t cc;
260 if ((cc = GetModuleFileNameA(NULL, path, (DWORD)pathlen)) == 0)
261 strcpy(path, "unknown");
262 else
263 path[cc] = '\0';
264
265 return path;
266 }
267
268 /*
269 * util_suppress_errmsg -- suppresses "abort" window on Windows if env variable
270 * is set, useful for automatic tests
271 */
272 void
273 util_suppress_errmsg(void)
274 {
275 if (os_getenv("PMDK_NO_ABORT_MSG") != NULL) {
276 DWORD err = GetErrorMode();
277 SetErrorMode(err | SEM_NOGPFAULTERRORBOX |
278 SEM_FAILCRITICALERRORS);
279 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
280 }
281 }
282
283 static int Lasterror_to_errno[16000] = {
284 [ERROR_ACCESS_DENIED] = EACCES,
285 [ERROR_FILE_NOT_FOUND] = ENOENT,
286 [ERROR_INVALID_ACCESS] = EACCES,
287 [ERROR_INVALID_ADDRESS] = EINVAL,
288 [ERROR_INVALID_FUNCTION] = EINVAL,
289 [ERROR_INVALID_HANDLE] = EINVAL,
290 [ERROR_INVALID_PARAMETER] = EINVAL,
291 [ERROR_LOCK_FAILED] = EACCES,
292 [ERROR_MAPPED_ALIGNMENT] = EINVAL,
293 [ERROR_NOT_ENOUGH_MEMORY] = ENOMEM,
294 [ERROR_NOT_SUPPORTED] = ENOTSUP,
295 [ERROR_OUTOFMEMORY] = ENOMEM,
296 [ERROR_PATH_NOT_FOUND] = ENOENT,
297 [ERROR_TOO_MANY_OPEN_FILES] = EMFILE,
298 };
299
300 /*
301 * util_lasterror_to_errno - converts windows error codes to errno
302 */
303 int
304 util_lasterror_to_errno(unsigned long err)
305 {
306 if (err >= ARRAY_SIZE(Lasterror_to_errno))
307 return -1;
308
309 /* no error */
310 if (err == 0)
311 return 0;
312
313 int ret = Lasterror_to_errno[err];
314
315 /* 0 is used to signalize missing entry in Lasterror_to_errno array */
316 if (ret == 0)
317 return -1;
318
319 return ret;
320 }