Cthulhu  0.2.10
Cthulhu compiler collection
os.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "os/os.h"
4 #include "os_common.h"
5 
6 #include "base/util.h"
7 
8 #include "arena/arena.h"
9 #include "base/panic.h"
10 
14 
15 void os_init(void)
16 {
17  impl_init();
18 }
19 
21 {
22  impl_exit(code);
24 }
25 
27 {
28  impl_thread_exit(status);
30 }
31 
33 {
34  impl_abort();
36 }
37 
41 
43 size_t os_error_get_string(os_error_t error, char *buffer, size_t size)
44 {
45  if (size == 0)
46  {
47  CTASSERT(buffer == NULL);
48  return impl_error_length(error);
49  }
50 
51  CTASSERT(buffer != NULL);
52  return impl_error_string(error, buffer, size);
53 }
54 
56 char *os_error_string(os_error_t error, arena_t *arena)
57 {
58  CTASSERT(arena != NULL);
59 
60  size_t size = os_error_get_string(error, NULL, 0);
61  CTASSERT(size > 0);
62 
63  char *buffer = ARENA_MALLOC(size + 1, "os_error_string", NULL, arena);
64 
65  size_t written = os_error_get_string(error, buffer, size + 1);
66  buffer[written] = '\0';
67 
68  return buffer;
69 }
70 
72 char *os_cwd_string(arena_t *arena)
73 {
74  CTASSERT(arena != NULL);
75 
76  size_t size = os_cwd_get_string(NULL, 0);
77  CTASSERT(size > 0);
78 
79  char *buffer = ARENA_MALLOC(size + 1, "os_getcwd", NULL, arena);
80 
81  size_t written = os_cwd_get_string(buffer, size + 1);
82  buffer[written] = '\0';
83 
84  return buffer;
85 }
86 
88 os_error_t os_getcwd(text_t *text, arena_t *arena)
89 {
90  CTASSERT(text != NULL);
91  CTASSERT(arena != NULL);
92 
93  size_t size = os_cwd_get_string(NULL, 0);
94  CTASSERT(size > 0);
95 
96  text->text = ARENA_MALLOC(size + 1, "os_getcwd", NULL, arena);
97  text->length = size;
98 
99  size_t written = os_cwd_get_string(text->text, size + 1);
100  if (written != size)
101  {
102  return impl_last_error();
103  }
104 
105  return eOsSuccess;
106 }
107 
111 
112 STA_DECL
113 os_error_t os_file_map(os_file_t *file, os_protect_t protect, size_t size, os_mapping_t *mapping)
114 {
115  CTASSERT(file != NULL);
116  CTASSERT(mapping != NULL);
117 
118  os_error_t err = eOsSuccess;
119 
120  if (size == 0)
121  {
122  err = os_file_size(file, &size);
123  if (err != eOsSuccess)
124  {
125  return err;
126  }
127  }
128 
129  if (size == 0)
130  {
131  return eOsTooSmall;
132  }
133 
134  mapping->size = size;
135  void *ptr = impl_file_map(file, protect, size, mapping);
136  if (ptr == CT_OS_INVALID_MAPPING)
137  {
138  err = impl_last_error();
139  }
140  else
141  {
142  mapping->view = ptr;
143  }
144 
145  return err;
146 }
147 
148 STA_DECL
149 os_error_t os_unmap(os_mapping_t *mapping)
150 {
151  CTASSERT(mapping != NULL);
152 
153  return impl_unmap(mapping);
154 }
155 
156 STA_DECL
157 size_t os_mapping_size(const os_mapping_t *mapping)
158 {
159  CTASSERT(mapping != NULL);
160  CTASSERT(os_mapping_active(mapping));
161 
162  return mapping->size;
163 }
164 
165 STA_DECL
167 {
168  CTASSERT(mapping != NULL);
169  CTASSERT(os_mapping_active(mapping));
170 
171  return mapping->view;
172 }
173 
174 STA_DECL
175 bool os_mapping_active(const os_mapping_t *mapping)
176 {
177  CTASSERT(mapping != NULL);
178 
179  return mapping->view != CT_OS_INVALID_MAPPING;
180 }
181 
185 
186 STA_DECL
187 os_error_t os_library_open(const char *path, os_library_t *library)
188 {
189  CTASSERT(path != NULL);
190  CTASSERTF(library != NULL, "invalid library handle used for %s", path);
191 
193  if (lib == CT_OS_INVALID_LIBRARY)
194  {
195  return impl_last_error();
196  }
197 
198  library->impl = lib;
199  library->name = path;
200 
201  return eOsSuccess;
202 }
203 
204 STA_DECL
205 os_error_t os_library_close(os_library_t *library)
206 {
207  CTASSERT(library != NULL);
208 
209  if (!impl_library_close(library->impl))
210  {
211  return impl_last_error();
212  }
213 
214  return eOsSuccess;
215 }
216 
217 STA_DECL
218 os_error_t os_library_symbol(os_library_t *library, void **symbol, const char *name)
219 {
220  CTASSERT(library != NULL);
221  CTASSERT(name != NULL);
222 
223  void *addr = impl_library_symbol(library->impl, name);
224  if (addr == NULL)
225  {
226  return impl_last_error();
227  }
228 
229  *symbol = addr;
230 
231  return eOsSuccess;
232 }
233 
234 STA_DECL
235 const char *os_library_name(const os_library_t *library)
236 {
237  CTASSERT(library != NULL);
238 
239  return library->name;
240 }
241 
245 
246 STA_DECL
247 os_error_t os_file_open(const char *path, os_access_t access, os_file_t *file)
248 {
249  CTASSERT(path != NULL);
250  CTASSERT(file != NULL);
251  CTASSERTF(access & (eOsAccessRead | eOsAccessWrite), "%s: invalid access flags 0x%x", path, access);
252  CTASSERTF(access != (eOsAccessRead | eOsAccessTruncate), "%s: cannot truncate read only file", path);
253 
254  os_file_impl_t fd = impl_file_open(path, access);
255  if (fd == CT_OS_INVALID_FILE)
256  {
257  return impl_last_error();
258  }
259 
260  file->path = path;
261  file->impl = fd;
262 
263  return eOsSuccess;
264 }
265 
266 STA_DECL
267 os_error_t os_file_close(os_file_t *file)
268 {
269  CTASSERT(file != NULL);
270  CTASSERTF(file->impl != CT_OS_INVALID_FILE, "invalid file handle (%s)", file->path);
271 
272  if (!impl_file_close(file->impl))
273  {
274  return impl_last_error();
275  }
276 
277  return eOsSuccess;
278 }
279 
280 STA_DECL
281 const char *os_file_name(const os_file_t *file)
282 {
283  CTASSERT(file != NULL);
284 
285  return file->path;
286 }
287 
288 STA_DECL
289 os_error_t os_file_create(const char *path)
290 {
291  CTASSERT(path != NULL);
292 
293  os_file_t fd = { 0 };
294  os_error_t err = os_file_open(path, eOsAccessWrite | eOsAccessTruncate, &fd);
295  if (err != eOsSuccess)
296  {
297  return err;
298  }
299 
300  return os_file_close(&fd);
301 }
302 
303 STA_DECL
304 os_error_t os_file_copy(const char *dst, const char *src)
305 {
306 #if CTU_OS_HAS_COPYFILE
307  return impl_copyfile(dst, src);
308 #else
309  os_file_t dstf = { 0 };
310  os_file_t srcf = { 0 };
311  os_error_t err = eOsSuccess;
312 
313  err = os_file_open(src, eOsAccessRead, &srcf);
314  if (err != eOsSuccess)
315  {
316  goto cleanup;
317  }
318 
319  err = os_file_open(dst, eOsAccessWrite | eOsAccessTruncate, &dstf);
320  if (err != eOsSuccess)
321  {
322  goto cleanup;
323  }
324 
325  char buffer[0x1000];
326  size_t read = 0;
327  size_t written = 0;
328 
329  while ((err = os_file_read(&srcf, buffer, sizeof(buffer), &read)) == eOsSuccess)
330  {
331  if (read == 0)
332  break;
333 
334  err = os_file_write(&dstf, buffer, read, &written);
335  if (err != eOsSuccess)
336  {
337  break;
338  }
339  }
340 
341 cleanup:
342  os_file_close(&srcf);
343  os_file_close(&dstf);
344  return err;
345 #endif
346 }
347 
351 
352 STA_DECL
353 bool os_dir_exists(const char *path)
354 {
355  os_dirent_t type = os_dirent_type(path);
356  return type == eOsNodeDir;
357 }
358 
362 
363 static void inode_init(os_inode_t *dst, const os_inode_impl_t *src)
364 {
365  dst->type = impl_inode_type(src);
367 }
368 
369 static bool iter_next(os_iter_t *iter, os_inode_impl_t *result)
370 {
371  bool ok = impl_iter_next(iter->impl, result);
372  if (!ok)
373  {
374  iter->error = impl_last_error();
375  }
376 
377  return ok;
378 }
379 
380 STA_DECL
381 os_error_t os_iter_begin(const char *path, os_iter_t *iter)
382 {
383  CTASSERT(path != NULL);
384  CTASSERT(iter != NULL);
385 
386  iter->error = eOsSuccess;
387  iter->impl = impl_iter_open(path, &iter->current);
388  if (iter->impl == CT_OS_INVALID_ITER)
389  {
390  iter->error = impl_last_error();
391  }
392 
393  return iter->error;
394 }
395 
396 STA_DECL
397 os_error_t os_iter_end(os_iter_t *iter)
398 {
399  CTASSERT(iter != NULL);
400 
401  if (!impl_iter_close(iter->impl))
402  {
403  return impl_last_error();
404  }
405 
406  return eOsSuccess;
407 }
408 
409 STA_DECL
411 {
412  CTASSERT(iter != NULL);
413  CTASSERT(dir != NULL);
414 
415  if (iter->error != eOsSuccess)
416  return false;
417 
418  os_inode_impl_t data;
419  while (iter_next(iter, &data))
420  {
421  if (is_path_special(impl_inode_name(&data)))
422  {
423  continue;
424  }
425 
426  break;
427  }
428 
429  if (iter->error != eOsSuccess)
430  return false;
431 
432  inode_init(dir, &data);
433  return true;
434 }
435 
436 STA_DECL
437 os_error_t os_iter_error(const os_iter_t *iter)
438 {
439  CTASSERT(iter != NULL);
440 
441  return iter->error;
442 }
443 
447 
448 STA_DECL
450 {
451  CTASSERT(node != NULL);
452 
453  return node->type;
454 }
455 
456 STA_DECL
457 const char *os_inode_name(const os_inode_t *node)
458 {
459  CTASSERT(node != NULL);
460 
461  return node->name;
462 }
463 
467 
468 STA_DECL
469 const char *os_thread_name(const os_thread_t *thread)
470 {
471  CTASSERT(thread != NULL);
472 
473  return thread->name;
474 }
475 
476 STA_DECL
478 {
479  CTASSERT(thread != NULL);
480 
481  return thread->id == id;
482 }
CT_NODISCARD size_t size
Definition: scan.h:128
int os_exitcode_t
program exit code
Definition: core.h:67
CT_NODISCARD CT_OS_API size_t os_cwd_get_string(STA_WRITES(size) char *buffer, size_t size)
get the current working directory
os_dirent_t
directory entry type
Definition: core.h:56
os_protect_t
file mapping memory protection
Definition: core.h:47
os_access_t
file access mode
Definition: core.h:38
#define CT_NORETURN
Definition: analyze.h:150
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
CT_BASE_API char * ctu_strcpy(STA_WRITES(size) char *dst, const char *src, size_t size)
copy a string equivalent to strcpy but with safety checks
CT_BEGIN_API CT_NODISCARD CT_PUREFN CT_BASE_API bool is_path_special(const char *path)
check if a path is special special paths are paths such as "." and ".." that are not valid for most o...
Definition: util.c:10
#define CT_UNREACHABLE()
mark a point in code as unreachable
Definition: compiler.h:102
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
Definition: arena.h:392
STA_DECL os_error_t os_file_copy(const char *dst, const char *src)
copy a file from one location to another
Definition: os.c:304
CT_NORETURN os_thread_exit(os_status_t status)
exit the current thread of execution
Definition: os.c:26
unsigned os_status_t
thread return code
Definition: core.h:71
size_t os_thread_id_t
thread id
Definition: core.h:75
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
STA_DECL const char * os_thread_name(const os_thread_t *thread)
Definition: os.c:469
STA_DECL os_error_t os_file_create(const char *path)
create a file
Definition: os.c:289
STA_DECL os_error_t os_unmap(os_mapping_t *mapping)
Definition: os.c:149
CT_NORETURN os_exit(os_exitcode_t code)
exit the program
Definition: os.c:20
STA_DECL void * os_mapping_data(os_mapping_t *mapping)
get the data of a file mapping
Definition: os.c:166
STA_DECL os_dirent_t os_inode_type(const os_inode_t *node)
get the type of an inode
Definition: os.c:449
STA_DECL os_error_t os_iter_end(os_iter_t *iter)
Definition: os.c:397
STA_DECL os_error_t os_library_symbol(os_library_t *library, void **symbol, const char *name)
Definition: os.c:218
STA_DECL os_error_t os_file_map(os_file_t *file, os_protect_t protect, size_t size, os_mapping_t *mapping)
Definition: os.c:113
STA_DECL size_t os_error_get_string(os_error_t error, char *buffer, size_t size)
Definition: os.c:43
void os_init(void)
initialize the os api
Definition: os.c:15
STA_DECL os_error_t os_library_open(const char *path, os_library_t *library)
Definition: os.c:187
STA_DECL bool os_thread_cmpid(const os_thread_t *thread, os_thread_id_t id)
Definition: os.c:477
STA_DECL bool os_dir_exists(const char *path)
check if a directory exists
Definition: os.c:353
STA_DECL const char * os_inode_name(const os_inode_t *node)
get the name of an inode
Definition: os.c:457
STA_DECL os_error_t os_file_open(const char *path, os_access_t access, os_file_t *file)
Definition: os.c:247
STA_DECL bool os_mapping_active(const os_mapping_t *mapping)
does the mapping object contain a valid mapping checks if the mapping data exists,...
Definition: os.c:175
CT_NORETURN os_abort(void)
abort the program
Definition: os.c:32
STA_DECL char * os_error_string(os_error_t error, arena_t *arena)
convert an os error code to a string
Definition: os.c:56
STA_DECL bool os_iter_next(os_iter_t *iter, os_inode_t *dir)
Definition: os.c:410
STA_DECL size_t os_mapping_size(const os_mapping_t *mapping)
get the size of a file mapping
Definition: os.c:157
STA_DECL os_error_t os_getcwd(text_t *text, arena_t *arena)
Definition: os.c:88
STA_DECL os_error_t os_file_close(os_file_t *file)
Definition: os.c:267
STA_DECL os_error_t os_library_close(os_library_t *library)
Definition: os.c:205
STA_DECL os_error_t os_iter_error(const os_iter_t *iter)
get the error state of a directory iterator
Definition: os.c:437
STA_DECL const char * os_file_name(const os_file_t *file)
get the name of a file
Definition: os.c:281
STA_DECL const char * os_library_name(const os_library_t *library)
get the name of a shared library
Definition: os.c:235
STA_DECL os_error_t os_iter_begin(const char *path, os_iter_t *iter)
Definition: os.c:381
STA_DECL char * os_cwd_string(arena_t *arena)
get the current working directory
Definition: os.c:72
CT_NODISCARD CT_OS_API os_dirent_t os_dirent_type(const char *path)
get the type of a paths inode entry
Definition: fs.c:65
CT_OS_API os_error_t os_file_size(os_file_t *file, OUT_NOTNULL size_t *actual)
get the size of a file
CT_OS_API os_error_t os_file_read(os_file_t *file, STA_WRITES(size) void *buffer, size_t size, OUT_NOTNULL size_t *actual)
read from a file
CT_OS_API os_error_t os_file_write(os_file_t *file, STA_READS(size) const void *buffer, size_t size, OUT_NOTNULL size_t *actual)
write to a file
CT_NODISCARD OUT_NOTNULL os_inode_t * dir
Definition: os.h:245
CT_LOCAL os_library_impl_t impl_library_open(const char *path)
Definition: library.c:10
STA_LAST_ERROR CT_LOCAL os_error_t impl_last_error(void)
Definition: error.c:16
CT_LOCAL os_dirent_t impl_inode_type(const os_inode_impl_t *inode)
Definition: dir.c:32
CT_LOCAL bool impl_iter_close(os_iter_impl_t impl)
Definition: dir.c:21
CT_LOCAL os_error_t impl_unmap(os_mapping_t *map)
Definition: file.c:230
CT_LOCAL size_t impl_error_length(os_error_t error)
Definition: error.c:21
CT_BEGIN_API CT_LOCAL void impl_init(void)
Definition: init.c:23
CT_LOCAL bool impl_library_close(os_library_impl_t lib)
Definition: library.c:15
CT_LOCAL bool impl_iter_next(os_iter_impl_t impl, os_inode_impl_t *inode)
Definition: dir.c:14
CT_LOCAL bool impl_file_close(os_file_impl_t impl)
Definition: file.c:76
CT_LOCAL void impl_thread_exit(os_status_t status)
Definition: init.c:54
CT_LOCAL void * impl_file_map(os_file_t *file, os_protect_t protect, size_t size, os_mapping_t *map)
Definition: file.c:220
CT_LOCAL void impl_abort(void)
Definition: init.c:59
CT_LOCAL void * impl_library_symbol(os_library_impl_t lib, const char *name)
Definition: library.c:27
CT_LOCAL void impl_exit(os_exitcode_t code)
Definition: init.c:49
CT_LOCAL os_iter_impl_t impl_iter_open(const char *path, os_inode_impl_t *inode)
Definition: dir.c:7
CT_LOCAL os_error_t impl_copyfile(const char *dst, const char *src)
Definition: file.c:16
CT_LOCAL const char * impl_inode_name(const os_inode_impl_t *inode)
Definition: dir.c:26
CT_LOCAL os_file_impl_t impl_file_open(const char *path, os_access_t access)
Definition: file.c:50
CT_LOCAL size_t impl_error_string(os_error_t error, char *buffer, size_t size)
Definition: error.c:27
#define CT_OS_NAME_MAX
Definition: posix.h:42
#define CT_OS_INVALID_LIBRARY
Definition: posix.h:31
#define CT_OS_INVALID_MAPPING
Definition: posix.h:34
#define CT_OS_INVALID_ITER
Definition: posix.h:35
@ eOsTooSmall
Definition: posix.h:27
@ eOsSuccess
Definition: posix.h:24
struct dirent * os_inode_impl_t
Definition: posix.h:12
#define CT_OS_INVALID_FILE
Definition: posix.h:30
void * os_library_impl_t
Definition: posix.h:10
FILE * os_file_impl_t
Definition: posix.h:11
an allocator object
Definition: arena.h:86
a file handle
Definition: os.h:40
os_file_impl_t impl
Definition: os.h:45
const char * path
Definition: os.h:42
an inode entry
Definition: os.h:52
os_dirent_t type
Definition: os.h:54
char name[CT_OS_NAME_MAX]
Definition: os.h:55
a directory iterator
Definition: os.h:62
os_inode_impl_t current
Definition: os.h:69
os_iter_impl_t impl
Definition: os.h:68
os_error_t error
Definition: os.h:64
a shared library handle
Definition: os.h:28
const char * name
Definition: os.h:30
os_library_impl_t impl
Definition: os.h:33
memory mapping handle
Definition: posix.h:18
size_t size
Definition: posix.h:20
void * view
Definition: posix.h:19
a thread handle
Definition: os.h:79
os_thread_id_t id
Definition: os.h:88
const char * name
Definition: os.h:81
a range of text
Definition: text.h:14
size_t length
the number of characters in the text
Definition: text.h:19