43#define O_DIRECTORY (0)
52typedef enum : uint32_t {
91 {
"/\xD0\x9F\xD0\xB0\xD0\xBF\xD0\xBA\xD0\xB0",
"Cyrillic directory (Papka)",
true},
92 {
"/\xE4\xBD\xA0\xE5\xA5\xBD",
"CJK directory (ni hao)",
true},
93 {
"/Caf\xC3\xA9.txt",
"Latin-1 accent (Cafe.txt)",
false},
94 {
"/\xE4\xBD\xA0\xE5\xA5\xBD.txt",
"CJK filename",
false},
95 {
"/\xF0\x9F\x98\x80.txt",
"astral-plane emoji, a surrogate pair on disk",
false},
96 {
"/\xD0\x9F\xD0\xB0\xD0\xBF\xD0\xBA\xD0\xB0/n\xC3\xB6te.txt",
97 "non-ASCII file inside a non-ASCII directory",
99 {
"/README.txt",
"plain ASCII control",
false},
117 size_t length =
strlen(text);
118 while (offset < length) {
119 const ssize_t written =
write(fd, &text[offset], length - offset);
120 if ((written < 0) && (errno == EINTR)) {
126 offset += (size_t)written;
150 }
while (value != 0U);
151 for (
size_t i = 0U; i < digits; ++i) {
152 forward[i] = reverse[digits - i - 1U];
154 forward[digits] =
'\0';
178 if (offset > (uint64_t)INT64_MAX || length > ((uint64_t)INT64_MAX - offset)) {
182 while (done < length) {
183 size_t request = length - done;
184 if (request > (
size_t)SSIZE_MAX) {
185 request = (size_t)SSIZE_MAX;
187 const ssize_t got = pread(fd, &bytes[done], request, (off_t)(offset + done));
188 if ((got < 0) && (errno == EINTR)) {
219 if (offset > (uint64_t)INT64_MAX || length > ((uint64_t)INT64_MAX - offset)) {
223 while (done < length) {
224 size_t request = length - done;
225 if (request > (
size_t)SSIZE_MAX) {
226 request = (size_t)SSIZE_MAX;
228 const ssize_t put = pwrite(fd, &bytes[done], request, (off_t)(offset + done));
229 if ((put < 0) && (errno == EINTR)) {
261 uint64_t* out_offset,
268 const uint64_t offset = lba * disk->
block_size;
269 const size_t bytes = (size_t)count * disk->
block_size;
270 if (offset > (uint64_t)INT64_MAX || bytes > ((uint64_t)INT64_MAX - offset)) {
273 *out_offset = offset;
303 if (disk ==
nullptr || buffer ==
nullptr || disk->
io_failed ||
339 if (disk ==
nullptr || buffer ==
nullptr || disk->
io_failed ||
370 if (disk ==
nullptr || block_count ==
nullptr || block_size ==
nullptr) {
397 const size_t length =
strlen(path);
401 size_t slash = length;
402 while (slash > 0U && path[slash - 1U] !=
'/') {
405 const size_t leaf_bytes = length - slash;
406 if (leaf_bytes == 0U || leaf_bytes >= (
size_t)
k_mk_name_cap) {
409 (void)
memcpy(leaf, &path[slash], leaf_bytes);
410 leaf[leaf_bytes] =
'\0';
411 if (
strcmp(leaf,
".") == 0 ||
strcmp(leaf,
"..") == 0) {
417 }
else if (slash == 1U) {
421 const size_t parent_bytes = slash - 1U;
422 (void)
memcpy(parent, path, parent_bytes);
423 parent[parent_bytes] =
'\0';
447 static const char s_prefix[] =
".exfat_mkimage.tmp.";
449 size_t offset =
sizeof(
s_prefix) - 1U;
451 uint64_t values[2] = {process, attempt};
452 for (uint8_t field = 0U; field < 2U; ++field) {
457 }
while (values[field] != 0U);
461 while (digits > 0U) {
462 out[offset++] = reverse[--digits];
464 out[offset++] = (field == 0U) ?
'.' :
'\0';
486 *output = (
mk_output_t){.directory_fd = -1, .image_fd = -1};
503 if (output->
image_fd >= 0 || errno != EEXIST) {
514 if (bytes > (uint64_t)INT64_MAX || ftruncate(output->
image_fd, (off_t)bytes) != 0) {
569 bool ok = fsync(output->
image_fd) == 0;
612 for (uint32_t i = 0U; i < (uint32_t)
k_mk_payload; ++i) {
621 internal_log(STDERR_FILENO,
"exfat_mkimage: cannot create ");
655 internal_log(STDERR_FILENO,
"usage: exfat_mkimage [output.img]\n");
658 const char* out_path = (argc == 2) ? argv[1] :
"exfat_showcase.img";
661 internal_log(STDERR_FILENO,
"exfat_mkimage: cannot create safe sibling temporary\n");
690 internal_log(STDERR_FILENO,
"exfat_mkimage: generation failed; destination preserved\n");
697 internal_log(STDOUT_FILENO,
" bytes) -- the card exactly as ra8_fs left it\n");
static ra8_err_t internal_disk_write(void *ctx, uint64_t lba, uint32_t count, const uint8_t *buffer)
Write blocks into the sparse unpublished image.
static bool internal_temp_name(char out[k_mk_name_cap], uint64_t process, uint32_t attempt)
Build one hidden temporary leaf from process id and retry index.
static const mk_entry_t s_entries[]
Deterministic UTF-8 showcase contents.
int main(int argc, char **argv)
Format, populate, verify closure, and atomically publish one image.
static bool internal_block_range(const mk_disk_t *disk, uint64_t lba, uint32_t count, uint64_t *out_offset, size_t *out_bytes)
Translate one sector range into bounded hosted byte coordinates.
static void internal_output_abort(mk_output_t *output)
Close and remove an unpublished temporary.
static ra8_err_t internal_disk_read(void *ctx, uint64_t lba, uint32_t count, uint8_t *buffer)
Read blocks from the sparse unpublished image.
static void internal_log_u64(int fd, uint64_t value)
Log one unsigned decimal value without a formatting stream.
#define O_DIRECTORY
No-op directory-open fallback for hosts lacking the flag.
static bool internal_output_commit(mk_output_t *output)
Sync and atomically publish one complete sibling temporary.
static void internal_log(int fd, const char *text)
Write one complete diagnostic fragment to a raw descriptor.
static ra8_err_t internal_disk_capacity(void *ctx, uint64_t *block_count, uint32_t *block_size)
Report the fixed card-image geometry.
static bool internal_split_output(const char *path, char parent[k_mk_path_cap], char leaf[k_mk_name_cap])
Split a destination into bounded parent and leaf components.
static ra8_err_t internal_populate(ra8_fs_mount_t *mount)
Populate every deterministic UTF-8 showcase entry.
static bool internal_pread_exact(int fd, uint64_t offset, uint8_t *bytes, size_t length)
Read an exact positioned range from a regular descriptor.
static bool internal_pwrite_exact(int fd, uint64_t offset, const uint8_t *bytes, size_t length)
Write an exact positioned range to a regular descriptor.
static bool internal_output_begin(const char *path, mk_output_t *output)
Create and exact-size one private sibling temporary.
mk_limit_t
Image geometry and bounded hosted-storage constants.
@ k_mk_alphabet
ASCII payload cycle length.
@ k_mk_decimal_base
Decimal conversion radix.
@ k_mk_decimal_digits
Maximum uint64_t digits.
@ k_mk_temp_attempts
Exclusive-create retry bound.
@ k_mk_payload
Bytes in each showcase file.
@ k_mk_block_count
Blocks in the 64 MiB image.
@ k_mk_path_cap
Hosted path capacity.
@ k_mk_create_mode
Hosted output creation mode.
@ k_mk_block_size
Bytes per image block.
@ k_mk_name_cap
Hosted leaf capacity.
#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.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_fail
Generic unspecified failure.
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
int renameat(int old_dir_fd, const char *old_path, int new_dir_fd, const char *new_path)
Rename one directory-relative path to another atomically.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
ra8_err_t ra8_fs_format(const ra8_fs_backend_t *backend, const ra8_fs_format_opts_t *opts)
Format a block device as a fresh, empty FAT12/FAT16/FAT32/exFAT volume.
ra8_err_t ra8_fs_mount(const ra8_fs_backend_t *backend, ra8_fs_mount_t **out_handle)
Mount a FAT volume from a block-device backend, auto-selecting the first partition.
ra8_err_t ra8_fs_unmount(ra8_fs_mount_t *handle)
Unmount a previously mounted volume and release its slot.
ra8_err_t ra8_fs_mkdir(const ra8_fs_mount_t *handle, const char *path)
Create a directory at path.
ra8_err_t ra8_fs_write_file(ra8_fs_mount_t *handle, const char *path, const uint8_t *data, uint32_t len)
Create a whole file in one call (provisioning helper).
@ k_ra8_fs_type_exfat
exFAT (read + streaming write + format).
static const uint8_t s_prefix[k_ra8_net_provision_prefix_bytes]
Exact protocol prefix, including the first field separator.
Descriptor-backed card state bound into ra8_fs.
int fd
Open temporary image descriptor.
bool io_failed
Sticky positioned-I/O failure.
uint32_t block_size
Bytes per logical block.
uint64_t block_count
Addressable logical blocks.
One showcase volume entry.
bool is_dir
True for a directory.
const char * meaning
Human-readable description.
const char * path
Absolute UTF-8 volume path.
Caller-owned atomic-publication state.
int directory_fd
Parent directory handle.
bool temp_exists
Temp unlink guard.
int image_fd
Temporary image handle.
char final_name[k_mk_name_cap]
Destination leaf.
char temp_name[k_mk_name_cap]
Hidden temporary leaf.
Block-device interface that ra8_fs runs on top of.
Cached parse of one mounted FAT volume.