44 return read(fd, buf, count);
64 return write(fd, buf, count);
85 return pread(fd, buf, count, offset);
106 return pwrite(fd, buf, count, offset);
137 return (
emu_io_result_t){.status = status, .transferred = transferred, .os_error = os_error};
174 if ((fd < 0) || ((buf ==
nullptr) && (count != 0U)) || (fn ==
nullptr)) {
178 size_t interrupted = 0U;
179 while (done < count) {
180 ssize_t amount = fn(fd, (uint8_t*)buf + done, count - done, offset + (off_t)done);
182 done += (size_t)amount;
217 return s_ops->read_fn(fd, buf, count);
239 return s_ops->write_fn(fd, buf, count);
260 return s_ops->pread_fn(fd, buf, count, offset);
281 return s_ops->pwrite_fn(fd, buf, count, offset);
321 if ((fd < 0) || (format ==
nullptr)) {
327 const int needed = vsnprintf(text,
sizeof(text), format, copy);
332 if ((
size_t)needed >=
sizeof(text)) {
358 va_start(args, format);
367 va_start(args, format);
387 va_start(args, format);
395 if ((path ==
nullptr) || (path[0] ==
'\0') || (file ==
nullptr)) {
400 const int fd = open(path, O_RDONLY |
O_CLOEXEC);
404 struct stat info = {};
405 if ((fstat(fd, &info) != 0) || !S_ISREG(info.st_mode) || (info.st_size < 0)) {
406 const int saved = (errno == 0) ? EINVAL : errno;
411 file->size = (int64_t)info.st_size;
417 if ((file ==
nullptr) || (file->fd < 0)) {
420 const int fd = file->fd;
429 if ((path ==
nullptr) || (txn ==
nullptr)) {
432 const int final_n = snprintf(txn->
final,
sizeof(txn->
final),
"%s", path);
433 const int temp_n = snprintf(txn->
temp,
sizeof(txn->
temp),
"%s.tmp.XXXXXX", path);
434 if ((final_n < 1) || ((
size_t)final_n >=
sizeof(txn->
final)) || (temp_n < 1) ||
435 ((
size_t)temp_n >=
sizeof(txn->
temp))) {
439 txn->
fd = mkstemp(txn->
temp);
443 (void)fcntl(txn->
fd, F_SETFD, FD_CLOEXEC);
449 if ((txn ==
nullptr) || (txn->
fd < 0)) {
452 if (fsync(txn->
fd) != 0) {
455 if (close(txn->
fd) != 0) {
460 if (rename(txn->
temp, txn->
final) != 0) {
469 if (txn ==
nullptr) {
473 (void)close(txn->
fd);
476 if (txn->
temp[0] !=
'\0') {
477 (void)unlink(txn->
temp);
static RA8_INTERNAL ssize_t internal_write_adapter(int fd, void *buf, size_t count, off_t offset)
Adapt sequential output to the common positioned callback shape.
emu_io_result_t priv_emu_io_err_text(const char *text)
Write a NUL-terminated literal to the injected error descriptor.
emu_io_result_t priv_emu_io_out_text(const char *text)
Write a NUL-terminated literal to the injected output descriptor.
emu_io_result_t priv_emu_io_write_exact(int fd, const void *buf, size_t count)
Write exactly count sequential bytes or report fault progress.
static RA8_INTERNAL ssize_t internal_write(int fd, const void *buf, size_t count)
Call the default sequential output primitive.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
emu_io_result_t priv_emu_io_pread_exact(int fd, void *buf, size_t count, off_t offset)
Read exactly count bytes at offset without changing the cursor.
static RA8_INTERNAL ssize_t internal_pread_adapter(int fd, void *buf, size_t count, off_t offset)
Dispatch positioned input through the configured operation table.
emu_io_result_t priv_emu_io_pwrite_exact(int fd, const void *buf, size_t count, off_t offset)
Write exactly count bytes at offset without changing the cursor.
emu_io_result_t priv_emu_io_outf(const char *format,...)
Format bounded text and write it to the injected output descriptor.
emu_io_result_t priv_emu_io_filef(int fd, const char *format,...)
Format bounded text and write it to an explicit raw descriptor.
static RA8_INTERNAL emu_io_result_t internal_transfer(int fd, void *buf, size_t count, off_t offset, internal_transfer_fn_t fn, bool input)
Complete one exact raw transfer with bounded EINTR retries.
emu_io_result_t priv_emu_io_read_exact(int fd, void *buf, size_t count)
Read exactly count sequential bytes or report EOF/fault progress.
static const emu_io_ops_t * s_ops
void priv_emu_io_configure(int out_fd, int err_fd, const emu_io_ops_t *ops)
Inject process output descriptors and optional raw transfer hooks.
emu_io_result_t priv_emu_io_err_bytes(const void *bytes, size_t length)
Write an exact non-NUL-terminated byte fragment to the error sink.
static RA8_INTERNAL ssize_t internal_pread(int fd, void *buf, size_t count, off_t offset)
Call the default positioned input primitive.
static RA8_INTERNAL ssize_t internal_pwrite_adapter(int fd, void *buf, size_t count, off_t offset)
Dispatch positioned output through the configured operation table.
void priv_emu_io_txn_abort(emu_io_txn_t *txn)
Close and unlink an active sibling transaction without publication.
static RA8_INTERNAL emu_io_result_t internal_result(emu_io_status_t status, size_t transferred, int os_error)
Construct one complete public operation result.
static RA8_INTERNAL ssize_t internal_pwrite(int fd, const void *buf, size_t count, off_t offset)
Call the default positioned output primitive.
@ k_emu_io_eintr_max
Consecutive EINTR retry bound.
@ k_emu_io_format_cap
Per-call stack formatting capacity.
static const emu_io_ops_t s_k_default_ops
static RA8_INTERNAL emu_io_result_t internal_vformat(int fd, const char *format, va_list args)
Render one bounded format operation and write it exactly.
ssize_t(* internal_transfer_fn_t)(int fd, void *buf, size_t count, off_t offset)
emu_io_result_t priv_emu_io_file_char(int fd, char value)
Write one byte to an explicit raw descriptor.
emu_io_result_t priv_emu_io_txn_commit(emu_io_txn_t *txn)
Sync, close, and atomically rename an active sibling transaction.
static RA8_INTERNAL ssize_t internal_read_adapter(int fd, void *buf, size_t count, off_t offset)
Adapt sequential input to the common positioned callback shape.
emu_io_result_t priv_emu_io_close(emu_io_file_t *file)
Close and invalidate an owned raw file descriptor.
emu_io_result_t priv_emu_io_file_text(int fd, const char *text)
Write a NUL-terminated literal to an explicit raw descriptor.
emu_io_result_t priv_emu_io_txn_begin(const char *path, emu_io_txn_t *txn)
Create a sibling temporary output for failure-atomic publication.
emu_io_result_t priv_emu_io_open_read(const char *path, emu_io_file_t *file)
Open and stat a regular file for bounded raw reading.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_status_t
Result status for an emulator host-I/O operation.
@ k_emu_io_eof
Input ended before the requested byte count.
@ k_emu_io_ok
The complete operation succeeded.
@ k_emu_io_error
A host syscall failed; os_error carries errno.
@ k_emu_io_invalid
A pointer, descriptor, size, or path was invalid.
@ k_emu_io_truncated
Formatted text exceeded the bounded scratch buffer.
static uint32_t internal_read(void)
Read current GPT counter ticks, or return UINT32_MAX on err.
#define O_CLOEXEC
Zero fallback when the host lacks close-on-exec open flags.
static ra8_err_t internal_write(void *ctx, void *file_state, const uint8_t *src, uint32_t len, uint32_t *out_written)
static ra8_err_t internal_read(void *ctx, void *file_state, uint8_t *dst, uint32_t cap, uint32_t *out_read)
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
size_t strlen(const char *s)
Calculate string length.
Raw descriptor plus its stat-derived byte length.
Injectable raw operations used by the exact-transfer loops.
Complete, caller-visible result of a raw host-I/O operation.
Sibling temporary file used for failure-atomic publication.
char temp[544]
Sibling mkstemp template / active temporary path.
char final[512]
Final publication path.
int fd
Owned temporary descriptor, or -1 when inactive.