21#error "port/posix is host-only and must never be compiled or linked into target firmware."
39#if defined(__linux__) || defined(__APPLE__)
40#include <sys/syscall.h>
100 const int value = *fd;
105 if (close(value) != 0) {
114 return (primary !=
k_ra8_ok) ? primary : cleanup;
140 for (
size_t index = 0U; index < bytes; ++index) {
141 if (actual[index] != expected[index]) {
154 const char* expected =
nullptr;
155 size_t expected_bytes = 0U;
159 if (
strcmp(component,
"tmp") == 0) {
160 expected =
"private/tmp";
161 expected_bytes =
sizeof(
"private/tmp") - 1U;
164 if (
strcmp(component,
"var") == 0) {
165 expected =
"private/var";
166 expected_bytes =
sizeof(
"private/var") - 1U;
169 if (expected !=
nullptr) {
170 if (target_bytes == expected_bytes) {
172 *out_alias = classified;
182 const char* component,
185 struct stat parent_meta;
186 struct stat root_meta;
189 if (fstat(parent_fd, &parent_meta) != 0) {
191 }
else if (stat(
"/", &root_meta) != 0) {
193 }
else if (parent_meta.st_dev != root_meta.st_dev) {
195 }
else if (parent_meta.st_ino != root_meta.st_ino) {
199 const ssize_t target_bytes = readlinkat(parent_fd, component, target,
sizeof(target));
200 if (target_bytes < 0) {
213 const char* leaf =
nullptr;
224 if (leaf !=
nullptr) {
226 if (private_fd < 0) {
237 if (private_fd >= 0) {
257static fw_fs_posix_test_dir_read_fn_t s_test_directory_reader;
260static void* s_test_directory_reader_ctx;
263ra8_fs_posix_test_set_directory_reader(fw_fs_posix_test_dir_read_fn_t reader,
void* ctx)
265 if (reader ==
nullptr) {
268 if (ctx ==
nullptr) {
271 s_test_directory_reader = reader;
272 s_test_directory_reader_ctx = 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)
314#pragma clang diagnostic push
316#pragma clang diagnostic ignored "-Wdeprecated-declarations"
318 const int result = syscall(SYS_getdirentries64, fd, (
char*)buffer, (
size_t)capacity, &position);
320#pragma clang diagnostic pop
322 *out_errno = (result < 0) ? errno : 0;
323 return (int64_t)result;
328 *out_errno = ENOTSUP;
356 if (s_test_directory_reader !=
nullptr) {
357 return s_test_directory_reader(s_test_directory_reader_ctx, fd, buffer, capacity, out_errno);
391 if ((uint64_t)result > (uint64_t)capacity) {
394 *out_bytes = (uint32_t)result;
397 if (read_errno != EINTR) {
428 if (available < minimum) {
431 uint16_t record_bytes = 0U;
433 if ((uint32_t)record_bytes < minimum) {
436 if ((uint32_t)record_bytes > available) {
444 const char* terminator = (
const char*)
memchr(name,
'\0', (
size_t)name_capacity);
445 if (terminator ==
nullptr) {
448 if (terminator == name) {
451 const size_t name_bytes = (size_t)(terminator - name);
460#elif defined(__APPLE__)
484 if (available < minimum) {
487 uint16_t record_bytes = 0U;
488 uint16_t name_bytes = 0U;
491 if ((uint32_t)record_bytes < minimum) {
494 if ((uint32_t)record_bytes > available) {
501 if (name_bytes == 0U) {
507 if (name_bytes >= name_capacity) {
511 if (name[name_bytes] !=
'\0') {
514 if (
memchr(name,
'\0', (
size_t)name_bytes) !=
nullptr) {
523#error "fw_if_fs_posix requires Linux getdents64 or Darwin getdirentries64"
534 if (reader ==
nullptr) {
537 if (out ==
nullptr) {
540 if (out_end ==
nullptr) {
553 (uint32_t)
sizeof(reader->
buffer),
578 if (nanoseconds < 0L) {
584 if (gmtime_r(&seconds, &utc) ==
nullptr) {
591 if (year > (int64_t)UINT16_MAX) {
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;
602 portable.
valid =
true;
611 if (path[i] ==
'\0') {
633 static const char digits[] =
"0123456789abcdef";
635 const uint8_t shift =
643 uint16_t last_slash = 0U;
644 uint16_t length = 0U;
646 if (destination[length] ==
'\0') {
649 if (destination[length] ==
'/') {
660 for (uint16_t i = 0U; i <= last_slash; ++i) {
661 out[i] = destination[i];
663 uint16_t cursor = (uint16_t)(last_slash + 1U);
678 uint32_t max_entries,
691 *out_complete =
false;
694 bool present =
false;
700 *out_complete =
true;
703 if (*out_count >= max_entries) {
710 bool keep_going =
true;
711 result = callback(callback_ctx, &entry, &keep_going);
721 return (result ==
k_ra8_ok) ? closed : result;
#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.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
@ k_ra8_err_not_empty
Container still holds members – the operation requires it empty.
@ k_ra8_fail
Generic unspecified failure.
@ k_ra8_err_invalid_arg
Invalid function argument.
@ k_ra8_err_exists
Item already exists – cannot create again.
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
@ k_ra8_err_access_denied
Operation refused because the target is protected against it.
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
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 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.