ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
fw_if_fs_posix_common.c
Go to the documentation of this file.
1
19
20#ifndef RA8_OFF_TARGET
21#error "port/posix is host-only and must never be compiled or linked into target firmware."
22#endif
23
24#ifndef _GNU_SOURCE
26#define _GNU_SOURCE
27#endif
28
29#include <errno.h>
30#include <fcntl.h>
31#include <stdint.h> // ra8-keep-include: `uint8_t` used directly
32#include <string.h>
33#include <sys/stat.h>
34#include <time.h> // ra8-keep-include: `time_t` and `gmtime_r` used directly
35#include <unistd.h>
36
37#include "ra8_attributes.h" // ra8-keep-include: `RA8_INTERNAL` and `RA8_PRIV` used directly
38
39#if defined(__linux__) || defined(__APPLE__)
40#include <sys/syscall.h>
41#endif
42
44#include "ra8_err.h" // ra8-keep-include: `ra8_err_t` used directly
45
46#ifndef O_CLOEXEC
48#define O_CLOEXEC (0)
49#endif
50
51#ifndef O_NOFOLLOW
53#define O_NOFOLLOW (0)
54#endif
55
57{
58 switch (value) {
59 case 0:
60 return k_ra8_ok;
61 case ENOENT:
62 case ENOTDIR:
64 case EEXIST:
65 return k_ra8_err_exists;
66 case ENOSPC:
67 case EDQUOT:
68 case EMFILE:
69 case ENFILE:
70 return k_ra8_err_no_mem;
71 case ENOTEMPTY:
73 case EACCES:
74 case EPERM:
75 case ELOOP:
77 case EINVAL:
78 case EXDEV:
79 case ENAMETOOLONG:
80 case EISDIR:
82 case EFBIG:
83 case EOVERFLOW:
85 case EBADF:
87 case EBUSY:
88 return k_ra8_err_busy;
89#ifdef ENOTSUP
90 case ENOTSUP:
92#endif
93 default:
94 return k_ra8_fail;
95 }
96}
97
99{
100 const int value = *fd;
101 *fd = -1;
102 if (value < 0) {
104 }
105 if (close(value) != 0) {
106 return priv_fs_posix_errno(errno);
107 }
108 return k_ra8_ok;
109}
110
112{
113 const ra8_err_t cleanup = priv_fs_posix_close_fd(fd);
114 return (primary != k_ra8_ok) ? primary : cleanup;
115}
116
135RA8_INTERNAL static bool
136internal_bytes_equal(const char* actual, const char* expected, size_t bytes)
137{
138 bool equal = true;
140 for (size_t index = 0U; index < bytes; ++index) {
141 if (actual[index] != expected[index]) {
142 equal = false;
143 break;
144 }
145 }
146 return equal;
147}
148
150 const char* target,
151 size_t target_bytes,
152 posix_root_alias_t* out_alias)
153{
154 const char* expected = nullptr;
155 size_t expected_bytes = 0U;
158 *out_alias = k_posix_root_alias_none;
159 if (strcmp(component, "tmp") == 0) {
160 expected = "private/tmp";
161 expected_bytes = sizeof("private/tmp") - 1U;
162 classified = k_posix_root_alias_tmp;
163 }
164 if (strcmp(component, "var") == 0) {
165 expected = "private/var";
166 expected_bytes = sizeof("private/var") - 1U;
167 classified = k_posix_root_alias_var;
168 }
169 if (expected != nullptr) {
170 if (target_bytes == expected_bytes) {
171 if (internal_bytes_equal(target, expected, expected_bytes)) {
172 *out_alias = classified;
173 status = k_ra8_ok;
174 }
175 }
176 }
177 return status;
178}
179
180#ifdef __APPLE__
181RA8_PRIV ra8_err_t priv_fs_posix_root_alias_verify(int parent_fd,
182 const char* component,
183 posix_root_alias_t* out_alias)
184{
185 struct stat parent_meta;
186 struct stat root_meta;
187 ra8_err_t status = k_ra8_ok;
188 *out_alias = k_posix_root_alias_none;
189 if (fstat(parent_fd, &parent_meta) != 0) {
190 status = priv_fs_posix_errno(errno);
191 } else if (stat("/", &root_meta) != 0) {
192 status = priv_fs_posix_errno(errno);
193 } else if (parent_meta.st_dev != root_meta.st_dev) {
195 } else if (parent_meta.st_ino != root_meta.st_ino) {
197 } else {
198 char target[k_posix_component_cap];
199 const ssize_t target_bytes = readlinkat(parent_fd, component, target, sizeof(target));
200 if (target_bytes < 0) {
201 status = priv_fs_posix_errno(errno);
202 } else {
203 status =
204 priv_fs_posix_root_alias_classify(component, target, (size_t)target_bytes, out_alias);
205 }
206 }
207 return status;
208}
209#endif
210
212{
213 const char* leaf = nullptr;
214 int private_fd = -1;
215 int opened = -1;
217 *out_fd = -1;
218 if (alias == k_posix_root_alias_tmp) {
219 leaf = "tmp";
220 }
221 if (alias == k_posix_root_alias_var) {
222 leaf = "var";
223 }
224 if (leaf != nullptr) {
225 private_fd = openat(root_fd, "private", O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
226 if (private_fd < 0) {
227 status = priv_fs_posix_errno(errno);
228 } else {
229 opened = openat(private_fd, leaf, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
230 if (opened < 0) {
231 status = priv_fs_posix_errno(errno);
232 } else {
233 status = k_ra8_ok;
234 }
235 }
236 }
237 if (private_fd >= 0) {
238 const ra8_err_t closed = priv_fs_posix_close_fd(&private_fd);
239 if (status == k_ra8_ok) {
240 if (closed != k_ra8_ok) {
241 status = closed;
242 }
243 }
244 }
245 if (status == k_ra8_ok) {
246 *out_fd = opened;
247 opened = -1;
248 }
249 if (opened >= 0) {
250 status = priv_fs_posix_close_fd_preserve(&opened, status);
251 }
252 return status;
253}
254
255#ifdef RA8_POSIX_TEST
257static fw_fs_posix_test_dir_read_fn_t s_test_directory_reader;
258
260static void* s_test_directory_reader_ctx;
261
263ra8_fs_posix_test_set_directory_reader(fw_fs_posix_test_dir_read_fn_t reader, void* ctx)
264{
265 if (reader == nullptr) {
266 return k_ra8_err_null_ptr;
267 }
268 if (ctx == nullptr) {
269 return k_ra8_err_null_ptr;
270 }
271 s_test_directory_reader = reader;
272 s_test_directory_reader_ctx = ctx;
273 return k_ra8_ok;
274}
275#endif
276
297static int64_t internal_directory_read_native(void* ctx,
298 int fd,
299 uint8_t* buffer,
300 uint32_t capacity,
301 int* out_errno)
302{
303 (void)ctx;
304#if defined(__linux__) && defined(SYS_getdents64)
305 const long result = syscall(SYS_getdents64, fd, buffer, (size_t)capacity);
306 *out_errno = (result < 0L) ? errno : 0;
307 return (int64_t)result;
308#elif defined(__APPLE__) && defined(SYS_getdirentries64)
309 off_t position = 0;
310#ifdef __clang__
311 /* macOS marks the raw descriptor syscall deprecated, but this bounded native
312 * record reader needs its byte count and avoids libc DIR stream state. Limit
313 * the compiler waiver to the single syscall expression. */
314#pragma clang diagnostic push
315/* Suppression rationale: Darwin exposes no non-deprecated raw getdirentries64 wrapper. */
316#pragma clang diagnostic ignored "-Wdeprecated-declarations"
317#endif
318 const int result = syscall(SYS_getdirentries64, fd, (char*)buffer, (size_t)capacity, &position);
319#ifdef __clang__
320#pragma clang diagnostic pop
321#endif
322 *out_errno = (result < 0) ? errno : 0;
323 return (int64_t)result;
324#else
325 (void)fd;
326 (void)buffer;
327 (void)capacity;
328 *out_errno = ENOTSUP;
329 return -1;
330#endif
331}
332
352static int64_t
353internal_directory_read_once(int fd, uint8_t* buffer, uint32_t capacity, int* out_errno)
354{
355#ifdef RA8_POSIX_TEST
356 if (s_test_directory_reader != nullptr) {
357 return s_test_directory_reader(s_test_directory_reader_ctx, fd, buffer, capacity, out_errno);
358 }
359#endif
360 return internal_directory_read_native(nullptr, fd, buffer, capacity, out_errno);
361}
362
384static ra8_err_t
385internal_directory_fill(int fd, uint8_t* buffer, uint32_t capacity, uint32_t* out_bytes)
386{
387 for (uint16_t attempt = 0U; attempt < (uint16_t)k_posix_directory_read_retries; ++attempt) {
388 int read_errno = 0;
389 const int64_t result = internal_directory_read_once(fd, buffer, capacity, &read_errno);
390 if (result >= 0) {
391 if ((uint64_t)result > (uint64_t)capacity) {
393 }
394 *out_bytes = (uint32_t)result;
395 return k_ra8_ok;
396 }
397 if (read_errno != EINTR) {
398 return (read_errno == 0) ? k_ra8_err_invalid_state : priv_fs_posix_errno(read_errno);
399 }
400 }
401 return k_ra8_err_busy;
402}
403
404#ifdef __linux__
424static ra8_err_t
425internal_directory_decode(const uint8_t* bytes, uint32_t available, posix_directory_record_t* out)
426{
427 const uint32_t minimum = (uint32_t)k_posix_linux_name_offset + 1U;
428 if (available < minimum) {
430 }
431 uint16_t record_bytes = 0U;
432 (void)memcpy(&record_bytes, &bytes[(uint8_t)k_posix_linux_reclen_offset], sizeof(record_bytes));
433 if ((uint32_t)record_bytes < minimum) {
435 }
436 if ((uint32_t)record_bytes > available) {
438 }
439 if ((record_bytes & ((uint16_t)k_posix_linux_record_align - 1U)) != 0U) {
441 }
442 const uint16_t name_capacity = (uint16_t)(record_bytes - (uint16_t)k_posix_linux_name_offset);
443 const char* name = (const char*)&bytes[(uint8_t)k_posix_linux_name_offset];
444 const char* terminator = (const char*)memchr(name, '\0', (size_t)name_capacity);
445 if (terminator == nullptr) {
447 }
448 if (terminator == name) {
450 }
451 const size_t name_bytes = (size_t)(terminator - name);
452 if (name_bytes >= (size_t)k_posix_component_cap) {
454 }
455 out->name = name;
456 out->name_bytes = (uint16_t)name_bytes;
457 out->record_bytes = record_bytes;
458 return k_ra8_ok;
459}
460#elif defined(__APPLE__)
480static ra8_err_t
481internal_directory_decode(const uint8_t* bytes, uint32_t available, posix_directory_record_t* out)
482{
483 const uint32_t minimum = (uint32_t)k_posix_darwin_name_offset + 1U;
484 if (available < minimum) {
486 }
487 uint16_t record_bytes = 0U;
488 uint16_t name_bytes = 0U;
489 (void)memcpy(&record_bytes, &bytes[(uint8_t)k_posix_darwin_reclen_offset], sizeof(record_bytes));
490 (void)memcpy(&name_bytes, &bytes[(uint8_t)k_posix_darwin_namlen_offset], sizeof(name_bytes));
491 if ((uint32_t)record_bytes < minimum) {
493 }
494 if ((uint32_t)record_bytes > available) {
496 }
497 if ((record_bytes & ((uint16_t)k_posix_darwin_record_align - 1U)) != 0U) {
499 }
500 const uint16_t name_capacity = (uint16_t)(record_bytes - (uint16_t)k_posix_darwin_name_offset);
501 if (name_bytes == 0U) {
503 }
504 if (name_bytes >= (uint16_t)k_posix_component_cap) {
506 }
507 if (name_bytes >= name_capacity) {
509 }
510 const char* name = (const char*)&bytes[(uint8_t)k_posix_darwin_name_offset];
511 if (name[name_bytes] != '\0') {
513 }
514 if (memchr(name, '\0', (size_t)name_bytes) != nullptr) {
516 }
517 out->name = name;
518 out->name_bytes = name_bytes;
519 out->record_bytes = record_bytes;
520 return k_ra8_ok;
521}
522#else
523#error "fw_if_fs_posix requires Linux getdents64 or Darwin getdirentries64"
524#endif
525
529 bool* out_end)
530{
531 if (fd < 0) {
533 }
534 if (reader == nullptr) {
535 return k_ra8_err_null_ptr;
536 }
537 if (out == nullptr) {
538 return k_ra8_err_null_ptr;
539 }
540 if (out_end == nullptr) {
541 return k_ra8_err_null_ptr;
542 }
543 if (reader->valid_bytes > (uint32_t)sizeof(reader->buffer)) {
545 }
546 if (reader->cursor > reader->valid_bytes) {
548 }
549 *out_end = false;
550 if (reader->cursor == reader->valid_bytes) {
551 const ra8_err_t filled = internal_directory_fill(fd,
552 reader->buffer,
553 (uint32_t)sizeof(reader->buffer),
554 &reader->valid_bytes);
555 reader->cursor = 0U;
556 if (filled != k_ra8_ok) {
557 return filled;
558 }
559 if (reader->valid_bytes == 0U) {
560 *out_end = true;
561 return k_ra8_ok;
562 }
563 }
564 const ra8_err_t decoded = internal_directory_decode(&reader->buffer[reader->cursor],
565 reader->valid_bytes - reader->cursor,
566 out);
567 if (decoded != k_ra8_ok) {
568 return decoded;
569 }
570 reader->cursor += (uint32_t)out->record_bytes;
571 return k_ra8_ok;
572}
573
574RA8_PRIV fw_fs_timestamp_t priv_fs_posix_timestamp(time_t seconds, long nanoseconds)
575{
576 fw_fs_timestamp_t portable = {};
577 struct tm utc = {};
578 if (nanoseconds < 0L) {
579 return portable;
580 }
581 if (nanoseconds > (long)k_posix_nanosecond_max) {
582 return portable;
583 }
584 if (gmtime_r(&seconds, &utc) == nullptr) {
585 return portable;
586 }
587 const int64_t year = (int64_t)utc.tm_year + (int64_t)k_posix_epoch_year_offset;
588 if (year < 0) {
589 return portable;
590 }
591 if (year > (int64_t)UINT16_MAX) {
592 return portable;
593 }
594 portable.value.nanosecond = (uint32_t)nanoseconds;
595 portable.value.year = (uint16_t)year;
596 portable.value.utc_offset_min = 0;
597 portable.value.month = (uint8_t)(utc.tm_mon + 1);
598 portable.value.day = (uint8_t)utc.tm_mday;
599 portable.value.hour = (uint8_t)utc.tm_hour;
600 portable.value.minute = (uint8_t)utc.tm_min;
601 portable.value.second = (uint8_t)utc.tm_sec;
602 portable.valid = true;
603 portable.utc_offset_valid = true;
604 return portable;
605}
606
607RA8_PRIV ra8_err_t priv_fs_posix_copy_path(char* out, const char* path)
608{
609 for (uint16_t i = 0U; i < (uint16_t)k_fw_fs_path_cap; ++i) {
610 out[i] = path[i];
611 if (path[i] == '\0') {
612 return k_ra8_ok;
613 }
614 }
616}
617
631RA8_INTERNAL static void internal_hex6(char out[k_posix_stage_hex_digits], uint32_t value)
632{
633 static const char digits[] = "0123456789abcdef";
634 for (uint8_t i = 0U; i < (uint8_t)k_posix_stage_hex_digits; ++i) {
635 const uint8_t shift =
636 (uint8_t)(((uint8_t)k_posix_hex_last_digit - i) * (uint8_t)k_posix_hex_nibble_bits);
637 out[i] = digits[(value >> shift) & (uint32_t)k_posix_hex_nibble_mask];
638 }
639}
640
641RA8_PRIV ra8_err_t priv_fs_posix_stage_path(const char* destination, uint32_t id, char* out)
642{
643 uint16_t last_slash = 0U;
644 uint16_t length = 0U;
645 while (length < (uint16_t)k_fw_fs_path_cap) {
646 if (destination[length] == '\0') {
647 break;
648 }
649 if (destination[length] == '/') {
650 last_slash = length;
651 }
652 ++length;
653 }
654 if (length >= (uint16_t)k_fw_fs_path_cap) {
656 }
657 if ((uint16_t)(last_slash + k_posix_stage_leaf_span) >= (uint16_t)k_fw_fs_path_cap) {
659 }
660 for (uint16_t i = 0U; i <= last_slash; ++i) {
661 out[i] = destination[i];
662 }
663 uint16_t cursor = (uint16_t)(last_slash + 1U);
664 out[cursor++] = 'T';
665 out[cursor++] = 'X';
666 internal_hex6(&out[cursor], id & k_posix_transaction_id_mask);
667 cursor = (uint16_t)(cursor + k_posix_stage_hex_digits);
668 out[cursor++] = '.';
669 out[cursor++] = 'T';
670 out[cursor++] = 'M';
671 out[cursor++] = 'P';
672 out[cursor] = '\0';
673 return k_ra8_ok;
674}
675
677 const char* path,
678 uint32_t max_entries,
679 fw_fs_list_fn_t callback,
680 void* callback_ctx,
681 uint32_t* out_count,
682 bool* out_complete)
683{
684 posix_directory_state_t directory = {.fd = -1};
685 const ra8_err_t opened =
686 priv_fs_posix_dir_open(ctx, path, &directory, (uint32_t)sizeof(directory));
687 if (opened != k_ra8_ok) {
688 return opened;
689 }
690 ra8_err_t result = k_ra8_ok;
691 *out_complete = false;
692 for (;;) {
693 fw_fs_dirent_value_t value = {};
694 bool present = false;
695 result = priv_fs_posix_dir_next(ctx, &directory, &value, &present);
696 if (result != k_ra8_ok) {
697 break;
698 }
699 if (!present) {
700 *out_complete = true;
701 break;
702 }
703 if (*out_count >= max_entries) {
704 break;
705 }
706 const fw_fs_dirent_t entry = {.name = value.name,
707 .size_bytes = value.size_bytes,
708 .name_bytes = value.name_bytes,
709 .type = value.type};
710 bool keep_going = true;
711 result = callback(callback_ctx, &entry, &keep_going);
712 ++(*out_count);
713 if (result != k_ra8_ok) {
714 break;
715 }
716 if (!keep_going) {
717 break;
718 }
719 }
720 const ra8_err_t closed = priv_fs_posix_dir_close(ctx, &directory);
721 return (result == k_ra8_ok) ? closed : result;
722}
#define O_DIRECTORY
No-op directory-open fallback for hosts lacking the flag.
ra8_err_t priv_fs_posix_dir_open(void *ctx, const char *path, void *directory_state, uint32_t state_bytes)
Open a confined raw-directory cursor in caller storage.
ra8_err_t priv_fs_posix_dir_next(void *ctx, void *directory_state, fw_fs_dirent_value_t *out, bool *out_entry)
Copy the next visible raw-directory entry.
ra8_err_t priv_fs_posix_dir_close(void *ctx, void *directory_state)
Close one owned raw-directory descriptor.
#define O_NOFOLLOW
Zero fallback paired with explicit no-follow metadata validation.
#define O_CLOEXEC
Zero fallback when the host lacks close-on-exec open flags.
ra8_err_t priv_fs_posix_stage_path(const char *destination, uint32_t id, char *out)
Build an 8.3-compatible sibling transaction path.
ra8_err_t priv_fs_posix_close_fd(int *fd)
Close exactly once and invalidate the caller's descriptor.
ra8_err_t priv_fs_posix_close_fd_preserve(int *fd, ra8_err_t primary)
Close one owned descriptor while preserving a primary status.
static void internal_hex6(char out[k_posix_stage_hex_digits], uint32_t value)
Render the bounded six-digit transaction suffix.
ra8_err_t priv_fs_posix_root_alias_classify(const char *component, const char *target, size_t target_bytes, posix_root_alias_t *out_alias)
Classify one exact filesystem-root alias component and target pair.
ra8_err_t priv_fs_posix_root_alias_open(int root_fd, posix_root_alias_t alias, int *out_fd)
Open a classified root alias through its canonical components.
ra8_err_t priv_fs_posix_directory_next(int fd, posix_directory_reader_t *reader, posix_directory_record_t *out, bool *out_end)
Read and validate the next raw hosted directory record.
ra8_err_t priv_fs_posix_copy_path(char *out, const char *path)
Copy one bounded portable path.
static int64_t internal_directory_read_native(void *ctx, int fd, uint8_t *buffer, uint32_t capacity, int *out_errno)
Read one raw directory batch without C-runtime stream state.
static int64_t internal_directory_read_once(int fd, uint8_t *buffer, uint32_t capacity, int *out_errno)
Dispatch one raw read through the production or test-only reader.
ra8_err_t priv_fs_posix_errno(int value)
Map one captured errno value into ra8_err_t.
ra8_err_t priv_fs_posix_listdir(void *ctx, const char *path, uint32_t max_entries, fw_fs_list_fn_t callback, void *callback_ctx, uint32_t *out_count, bool *out_complete)
Enumerate a POSIX directory through bounded raw records.
static ra8_err_t internal_directory_fill(int fd, uint8_t *buffer, uint32_t capacity, uint32_t *out_bytes)
Retry a bounded number of interrupted raw directory reads.
static bool internal_bytes_equal(const char *actual, const char *expected, size_t bytes)
Compare one bounded raw byte span with an expected byte sequence.
fw_fs_timestamp_t priv_fs_posix_timestamp(time_t seconds, long nanoseconds)
Convert a POSIX UTC instant into the portable civil representation.
Shared errno/descriptor helpers for the POSIX filesystem port.
posix_root_alias_t
Classification of a verified filesystem-root directory alias.
@ k_posix_root_alias_tmp
Root tmp resolves to private/tmp.
@ k_posix_root_alias_none
Component is not an approved root alias.
@ k_posix_root_alias_var
Root var resolves to private/var.
@ k_posix_transaction_id_mask
Six hexadecimal digits.
@ k_posix_nanosecond_max
Largest valid subsecond.
@ k_posix_epoch_year_offset
struct tm year origin.
@ k_posix_directory_read_retries
Maximum interrupted reads.
@ k_posix_stage_leaf_span
Stage leaf plus terminating NUL.
@ k_posix_component_cap
Component buffer including NUL.
@ k_posix_linux_name_offset
Offset of d_name.
@ k_posix_linux_reclen_offset
Offset of d_reclen.
@ k_posix_linux_record_align
Kernel record alignment.
@ k_posix_hex_nibble_mask
Low-nibble mask.
@ k_posix_hex_last_digit
Highest valid index in a stage identifier.
@ k_posix_stage_hex_digits
Hex digits in a stage identifier.
@ k_posix_hex_nibble_bits
Bits represented by one hex digit.
@ k_posix_darwin_name_offset
Offset of d_name.
@ k_posix_darwin_record_align
Kernel record alignment.
@ k_posix_darwin_reclen_offset
Offset of d_reclen.
@ k_posix_darwin_namlen_offset
Offset of d_namlen.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
ra8_err_t(* fw_fs_list_fn_t)(void *ctx, const fw_fs_dirent_t *entry, bool *out_continue)
Bounded list callback.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_TEST_HELPER
Mark a symbol as externally-linked but only callable from tests.
#define RA8_LOOP_BOUND(ceiling)
NASA Power-of-10 Rule 2: bind ONE loop to a compile-time ceiling.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_err_not_empty
Container still holds members – the operation requires it empty.
Definition ra8_err.h:258
@ k_ra8_fail
Generic unspecified failure.
Definition ra8_err.h:133
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_exists
Item already exists – cannot create again.
Definition ra8_err.h:216
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_access_denied
Operation refused because the target is protected against it.
Definition ra8_err.h:276
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memchr(const void *s, int c, size_t n)
Locate a byte in a memory area.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
uint16_t year
Full civil year.
int16_t utc_offset_min
Offset from UTC when the validity flag is set.
uint8_t month
Month, 1..12.
uint32_t nanosecond
Fraction within second, 0..999,999,999.
uint8_t second
Second, 0..59.
uint8_t day
Day, 1..31.
uint8_t hour
Hour, 0..23.
uint8_t minute
Minute, 0..59.
One directory entry, valid only for the callback invocation.
Stable caller-owned value returned by fw_fs_dir_next.
uint64_t size_bytes
File length; zero for dirs.
uint16_t name_bytes
Bytes excluding the NUL.
fw_fs_node_type_t type
Entry kind.
char name[k_fw_fs_path_cap]
Copied NUL-terminated leaf.
One portable timestamp and independent availability facts.
fw_fs_datetime_t value
Decoded civil date and time.
bool utc_offset_valid
True when utc_offset_min is known.
bool valid
True when the field is meaningful.
Caller-owned cursor and fixed storage for raw directory batches.
uint8_t buffer[k_posix_directory_buffer_bytes]
Kernel record bytes.
uint32_t valid_bytes
Bytes in buffer.
uint32_t cursor
Next record offset.
Validated view over one raw host directory record.
uint16_t name_bytes
Name length excluding the terminator.
const char * name
NUL-terminated name inside the read buffer.
uint16_t record_bytes
Complete aligned record length.
POSIX state placed in caller directory workspace.