LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
osal_file_win32.c
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-3.0-or-later
2 * Copyright (C) 2026 Sylvain Labopin
3 */
4
25#include "internal/osal_file_internal.h"
26
27#include "osal/file/osal_file_ops.h"
28
30#include "osal/mem/osal_mem.h"
31
39
53{
54 switch (errnum) {
55 case 0:
57
58#ifdef EINVAL
59 case EINVAL:
61#endif
62
63#ifdef ENOENT
64 case ENOENT:
66#endif
67
68#ifdef EACCES
69 case EACCES:
71#endif
72
73#ifdef EPERM
74 case EPERM:
76#endif
77
78#ifdef EEXIST
79 case EEXIST:
81#endif
82
83#ifdef ENOSPC
84 case ENOSPC:
86#endif
87
88#ifdef ENAMETOOLONG
89 case ENAMETOOLONG:
91#endif
92
93#ifdef ENOTDIR
94 case ENOTDIR:
96#endif
97
98#ifdef EISDIR
99 case EISDIR:
101#endif
102
103#ifdef EBADF
104 case EBADF:
106#endif
107
108#ifdef EFBIG
109 case EFBIG:
111#endif
112
113#ifdef EINTR
114 case EINTR:
116#endif
117
118#ifdef EMFILE
119 case EMFILE:
121#endif
122
123#ifdef ENFILE
124 case ENFILE:
126#endif
127
128#ifdef ELOOP
129 case ELOOP:
131#endif
132
133#ifdef EROFS
134 case EROFS:
136#endif
137
138#ifdef ESPIPE
139 case ESPIPE:
141#endif
142
143#ifdef EXDEV
144 case EXDEV:
146#endif
147
148#ifdef ENODEV
149 case ENODEV:
151#endif
152
153#ifdef ENXIO
154 case ENXIO:
156#endif
157
158#ifdef ESTALE
159 case ESTALE:
161#endif
162
163#ifdef ENOMEM
164 case ENOMEM:
166#endif
167
168 default:
169 return OSAL_FILE_STATUS_IO;
170 }
171}
172
186{
187 switch (err) {
188 case ERROR_SUCCESS:
189 return OSAL_FILE_STATUS_OK;
190
191 case ERROR_FILE_NOT_FOUND:
192 case ERROR_PATH_NOT_FOUND:
194
195 case ERROR_ACCESS_DENIED:
196 case ERROR_SHARING_VIOLATION:
198
199 case ERROR_ALREADY_EXISTS:
200 case ERROR_FILE_EXISTS:
202
203 case ERROR_DISK_FULL:
204 case ERROR_HANDLE_DISK_FULL:
206
207 case ERROR_FILENAME_EXCED_RANGE:
209
210 case ERROR_DIRECTORY:
212
213 case ERROR_INVALID_NAME:
214 case ERROR_BAD_PATHNAME:
215 case ERROR_INVALID_PARAMETER:
216 case ERROR_NO_UNICODE_TRANSLATION:
218
219 case ERROR_TOO_MANY_OPEN_FILES:
221
222 case ERROR_NOT_READY:
223 case ERROR_DEV_NOT_EXIST:
225
226 case ERROR_OUTOFMEMORY:
227 case ERROR_NOT_ENOUGH_MEMORY:
229
230 case ERROR_WRITE_PROTECT:
232
233 default:
234 return OSAL_FILE_STATUS_IO;
235 }
236}
237
248static const wchar_t *osal_file_mode_w(const char *mode)
249{
250 if (osal_strcmp(mode, "rb") == 0)
251 return L"rb";
252
253 if (osal_strcmp(mode, "wb") == 0)
254 return L"wb";
255
256 if (osal_strcmp(mode, "ab") == 0)
257 return L"ab";
258
259 return NULL;
260}
261
282 wchar_t **out_wstr,
283 const char *utf8,
284 const osal_mem_ops_t *mem_ops)
285{
286 LEXLEO_ASSERT(out_wstr);
287 LEXLEO_ASSERT(mem_ops && mem_ops->malloc && mem_ops->free);
288
289 *out_wstr = NULL;
290
291 if (!utf8)
293
294 int wlen = MultiByteToWideChar(
295 CP_UTF8,
296 MB_ERR_INVALID_CHARS,
297 utf8,
298 -1,
299 NULL,
300 0);
301
302 if (wlen <= 0)
303 return osal_file_win32_error(GetLastError());
304
305 size_t bytes = (size_t)wlen * sizeof(wchar_t);
306
307 wchar_t *tmp = mem_ops->malloc(bytes);
308 if (!tmp)
310
311 int converted = MultiByteToWideChar(
312 CP_UTF8,
313 MB_ERR_INVALID_CHARS,
314 utf8,
315 -1,
316 tmp,
317 wlen);
318
319 if (converted <= 0) {
320 mem_ops->free(tmp);
321 return osal_file_win32_error(GetLastError());
322 }
323
324 *out_wstr = tmp;
325 return OSAL_FILE_STATUS_OK;
326}
327
353 OSAL_FILE **out,
354 const char *pathname,
355 const char *mode,
356 const osal_mem_ops_t *mem_ops)
357{
358 if (
359 !out
360 || !pathname
361 || pathname[0] == '\0'
362 || !mode
363 || (
364 osal_strcmp(mode, "rb") != 0
365 && osal_strcmp(mode, "wb") != 0
366 && osal_strcmp(mode, "ab") != 0)
367 || !mem_ops
368 ) {
370 }
371
373 mem_ops->malloc
374 && mem_ops->free
375 );
376
377 const wchar_t *wmode = osal_file_mode_w(mode);
378 if (!wmode)
380
381 wchar_t *wpath = NULL;
382 osal_file_status_t st = osal_utf8_to_utf16_dup(&wpath, pathname, mem_ops);
383 if (st != OSAL_FILE_STATUS_OK)
384 return st;
385
386 FILE *fp = _wfopen(wpath, wmode);
387
388 mem_ops->free(wpath);
389 wpath = NULL;
390
391 if (!fp) {
392 /*
393 * _wfopen() is a CRT call; errno is the primary error channel here.
394 */
395 return osal_file_map_errno(errno);
396 }
397
398 OSAL_FILE *tmp = mem_ops->malloc(sizeof(*tmp));
399 if (!tmp) {
400 fclose(fp);
402 }
403
404 tmp->fp = fp;
405 tmp->mem_ops = mem_ops;
406
407 *out = tmp;
408
409 return OSAL_FILE_STATUS_OK;
410}
411
437static size_t osal_file_read(
438 void *ptr,
439 size_t size,
440 size_t nmemb,
441 OSAL_FILE *stream,
443{
444 if (
445 !ptr
446 || !st
447 || !stream
448 || !stream->fp
449 ) {
450 if (st)
452 return 0;
453 }
454
456
457 size_t ret = fread(ptr, size, nmemb, stream->fp);
458
459 if (ret < nmemb && ferror(stream->fp))
460 *st = osal_file_map_errno(errno);
461
462 return ret;
463}
464
490static size_t osal_file_write(
491 const void *ptr,
492 size_t size,
493 size_t nmemb,
494 OSAL_FILE *stream,
496{
497 if (
498 !ptr
499 || !st
500 || !stream
501 || !stream->fp
502 ) {
503 if (st)
505 return 0;
506 }
507
509
510 size_t ret = fwrite(ptr, size, nmemb, stream->fp);
511
512 if (ret < nmemb && ferror(stream->fp))
513 *st = osal_file_map_errno(errno);
514
515 return ret;
516}
517
532{
533 if (!stream || !stream->fp)
535
536 if (fflush(stream->fp) != 0)
537 return osal_file_map_errno(errno);
538
539 return OSAL_FILE_STATUS_OK;
540}
541
556{
557 if (!stream || !stream->fp)
559
560 if (fclose(stream->fp) != 0)
561 return osal_file_map_errno(errno);
562
563 LEXLEO_ASSERT(stream->mem_ops && stream->mem_ops->free);
564 stream->mem_ops->free(stream);
565
566 return OSAL_FILE_STATUS_OK;
567}
568
576{
577 static const osal_file_ops_t osal_file_ops = {
579 .read = osal_file_read,
580 .write = osal_file_write,
581 .close = osal_file_close,
582 .flush = osal_file_flush,
583 };
584
585 return &osal_file_ops;
586}
@ OSAL_FILE_STATUS_EXISTS
@ OSAL_FILE_STATUS_OOM
@ OSAL_FILE_STATUS_OK
@ OSAL_FILE_STATUS_BADF
@ OSAL_FILE_STATUS_STALE
@ OSAL_FILE_STATUS_IO
@ OSAL_FILE_STATUS_LOOP
@ OSAL_FILE_STATUS_INTR
@ OSAL_FILE_STATUS_NAMETOOLONG
@ OSAL_FILE_STATUS_NODEV
@ OSAL_FILE_STATUS_NOENT
@ OSAL_FILE_STATUS_INVALID
@ OSAL_FILE_STATUS_NFILE
@ OSAL_FILE_STATUS_MFILE
@ OSAL_FILE_STATUS_SPIPE
@ OSAL_FILE_STATUS_PERM
@ OSAL_FILE_STATUS_FBIG
@ OSAL_FILE_STATUS_ISDIR
@ OSAL_FILE_STATUS_ROFS
@ OSAL_FILE_STATUS_NOSPC
@ OSAL_FILE_STATUS_XDEV
@ OSAL_FILE_STATUS_NOTDIR
@ OSAL_FILE_STATUS_NXIO
osal_file_status_t
#define LEXLEO_ASSERT(expr)
int osal_strcmp(const char *s1, const char *s2)
Definition osal_mem.c:40
static size_t osal_file_read(void *ptr, size_t size, size_t nmemb, OSAL_FILE *stream, osal_file_status_t *st)
Read elements from an open OSAL_FILE.
static size_t osal_file_write(const void *ptr, size_t size, size_t nmemb, OSAL_FILE *stream, osal_file_status_t *st)
Write elements to an open OSAL_FILE.
static osal_file_status_t osal_file_map_errno(int errnum)
Map a CRT errno value to an osal_file_status_t.
static osal_file_status_t osal_file_close(OSAL_FILE *stream)
Close an open OSAL_FILE and release its associated wrapper.
static osal_file_status_t osal_utf8_to_utf16_dup(wchar_t **out_wstr, const char *utf8, const osal_mem_ops_t *mem_ops)
Duplicate a UTF-8 string as a UTF-16 wide-character string.
static const wchar_t * osal_file_mode_w(const char *mode)
Return the wide-character mode string matching a portable file mode.
const osal_file_ops_t * osal_file_default_ops(void)
Return the default Win32 / CRT OSAL file operations table.
static osal_file_status_t osal_file_open(OSAL_FILE **out, const char *pathname, const char *mode, const osal_mem_ops_t *mem_ops)
Open a file resource through the Win32 / CRT backend.
static osal_file_status_t osal_file_win32_error(DWORD err)
Map a Win32 error code to an osal_file_status_t.
static osal_file_status_t osal_file_flush(OSAL_FILE *stream)
Flush buffered output associated with an open OSAL_FILE.
Private representation of an acquired OSAL file handle.
FILE * fp
Underlying C standard I/O file handle.
const osal_mem_ops_t * mem_ops
Memory operations table used to release this wrapper.
Operations table for the low-level OSAL file abstraction.
osal_file_status_t(* open)(OSAL_FILE **out, const char *pathname, const char *mode, const osal_mem_ops_t *mem_ops)
Open a file resource.
void *(* malloc)(size_t size)
void(* free)(void *ptr)