LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
osal_file_posix.c
Go to the documentation of this file.
1// src/foundation/osal/osal_file/src/posix/osal_file_posix.c
2
4#include "osal/file/osal_file_ops.h"
5#include "osal/file/osal_file_types.h"
6
8
12#include "policy/lexleo_panic.h"
13
15 FILE *fp;
17};
18
20 switch (e) {
21 case 0: return OSAL_FILE_OK;
22#ifdef ENOENT
23 case ENOENT: return OSAL_FILE_NOENT;
24#endif
25#ifdef EACCES
26 case EACCES: return OSAL_FILE_PERM;
27#endif
28#ifdef EPERM
29 case EPERM: return OSAL_FILE_PERM;
30#endif
31 default: return OSAL_FILE_IO;
32 }
33}
34
36 if (st) *st = v;
37}
38
39static const char *mode_from_flags(uint32_t flags, osal_file_status_t *st) {
40 const bool r = (flags & OSAL_FILE_READ) != 0;
41 const bool w = (flags & OSAL_FILE_WRITE) != 0;
42 const bool a = (flags & OSAL_FILE_APPEND) != 0;
43 const bool t = (flags & OSAL_FILE_TRUNC) != 0;
44 const bool c = (flags & OSAL_FILE_CREATE) != 0;
45
46 // Notes:
47 // - stdio doesn't have a pure "create if missing" mode without opening
48 // for write.
49 // - We approximate common cases for fs_stream needs.
50
51 if (a) {
52 // append implies write
53 if (r) return "a+b";
54 return "ab";
55 }
56
57 if (w) {
58 if (t) {
59 if (r) return "w+b";
60 return "wb";
61 }
62 if (c) {
63 // create if missing; stdio can't do O_CREAT|O_EXCL easily, but "a" creates
64 // without truncation. We'll open "ab" and later seek is irrelevant for stream.
65 if (r) return "a+b";
66 return "ab";
67 }
68 // "r+b" requires file exists
69 if (r) return "r+b";
70 // write only without trunc/create is ambiguous -> error
72 return NULL;
73 }
74
75 if (r) {
76 return "rb";
77 }
78
80 return NULL;
81}
82
84 const char *path_utf8,
85 uint32_t flags,
87 const osal_file_env_t *env )
88{
89 if (st) *st = OSAL_FILE_ERR;
90 if (!path_utf8 || !*path_utf8) return NULL;
91
92 osal_file_env_t default_env;
93 const osal_file_env_t *use_env = env;
94
95 if (!use_env) {
97 use_env = &default_env;
98 }
99
100 const osal_mem_ops_t *mem = use_env->mem;
101 if (!mem || !mem->calloc || !mem->free) return NULL;
102
103 const char *mode = mode_from_flags(flags, st);
104 if (!mode) return NULL;
105
106 errno = 0;
107 FILE *fp = fopen(path_utf8, mode);
108 if (!fp) {
109 set_status(st, map_errno(errno));
110 return NULL;
111 }
112
113 osal_file_t *f = (osal_file_t *)mem->calloc(1, sizeof(*f));
114 if (!f) {
115 fclose(fp);
117 return NULL;
118 }
119
120 f->fp = fp;
121 f->mem = mem;
122
124 return f;
125}
126
127static size_t posix_read(
128 osal_file_t *f,
129 void *buf,
130 size_t n,
132{
133 if (st) *st = OSAL_FILE_ERR;
134 if (!f || !f->fp || (!buf && n)) return 0;
135
136 if (n == 0) { if (st) *st = OSAL_FILE_OK; return 0; }
137
138 errno = 0;
139 size_t got = fread(buf, 1, n, f->fp);
140
141 if (got < n) {
142 if (ferror(f->fp)) {
143 clearerr(f->fp);
144 if (st) *st = map_errno(errno); // ou set_status(...)
145 return got;
146 }
147 if (feof(f->fp)) {
148 if (st) *st = OSAL_FILE_EOF;
149 return got;
150 }
151 }
152
153 if (st) *st = OSAL_FILE_OK;
154 return got;
155}
156
157static size_t posix_write(
158 osal_file_t *f,
159 const void *buf,
160 size_t n,
162{
163 if (st) *st = OSAL_FILE_ERR;
164 if (!f || !f->fp || (!buf && n)) return 0;
165
166 if (n == 0) { if (st) *st = OSAL_FILE_OK; return 0; }
167
168 errno = 0;
169 size_t put = fwrite(buf, 1, n, f->fp);
170
171 if (put < n) {
172 if (ferror(f->fp)) {
173 clearerr(f->fp);
174 if (st) *st = map_errno(errno);
175 return put;
176 }
177
178 if (st) *st = OSAL_FILE_IO;
179 return put;
180 }
181
182 if (st) *st = OSAL_FILE_OK;
183 return put;
184}
185
186
188{
189 if (!f || !f->fp) return OSAL_FILE_ERR;
190
191 errno = 0;
192 if (fflush(f->fp) != 0) {
193 if (ferror(f->fp)) {
194 clearerr(f->fp);
195 return map_errno(errno); // IO / PERM / etc.
196 }
197 return OSAL_FILE_IO; // fallback générique
198 }
199
200 return OSAL_FILE_OK;
201}
202
204{
205 if (!f) return OSAL_FILE_OK;
206
207 if (!f->mem || !f->mem->free) {
208 lexleo_panic("osal_file: invalid allocator in close");
209 return OSAL_FILE_ERR;
210 }
211
213
214 if (f->fp) {
215 errno = 0;
216 if (fclose(f->fp) != 0) {
217 st = map_errno(errno);
218 if (st == OSAL_FILE_OK) st = OSAL_FILE_IO;
219 }
220 f->fp = NULL;
221 }
222
223 f->mem->free(f);
224 return st;
225}
226
228{
229 static const osal_file_ops_t OPS = {
230 .open = posix_open,
231 .read = posix_read,
232 .write = posix_write,
233 .flush = posix_flush,
234 .close = posix_close,
235 };
236 return &OPS;
237}
@ OSAL_FILE_WRITE
@ OSAL_FILE_TRUNC
@ OSAL_FILE_APPEND
@ OSAL_FILE_CREATE
@ OSAL_FILE_READ
osal_file_status_t
@ OSAL_FILE_EOF
@ OSAL_FILE_PERM
@ OSAL_FILE_OK
@ OSAL_FILE_IO
@ OSAL_FILE_NOENT
@ OSAL_FILE_ERR
static size_t posix_write(osal_file_t *f, const void *buf, size_t n, osal_file_status_t *st)
static size_t posix_read(osal_file_t *f, void *buf, size_t n, osal_file_status_t *st)
const osal_file_ops_t * osal_file_posix_ops(void)
static void set_status(osal_file_status_t *st, osal_file_status_t v)
static osal_file_t * posix_open(const char *path_utf8, uint32_t flags, osal_file_status_t *st, const osal_file_env_t *env)
static osal_file_status_t posix_close(osal_file_t *f)
static osal_file_status_t map_errno(int e)
static const char * mode_from_flags(uint32_t flags, osal_file_status_t *st)
static osal_file_status_t posix_flush(osal_file_t *f)
void lexleo_panic(const char *msg) __attribute__((noreturn))
osal_file_env_t osal_file_default_env(const osal_mem_ops_t *mem_ops)
Definition osal_file.c:81
const osal_mem_ops_t * osal_mem_default_ops(void)
const osal_mem_ops_t * mem
osal_file_t *(* open)(const char *path_utf8, uint32_t flags, osal_file_status_t *status, const osal_file_env_t *env)
const osal_mem_ops_t * mem
void *(* calloc)(size_t nmemb, size_t size)
void(* free)(void *ptr)