44 size_t length =
strlen(text);
45 while (offset < length) {
46 const ssize_t written =
write(STDERR_FILENO, &text[offset], length - offset);
47 if ((written < 0) && (errno == EINTR)) {
53 offset += (size_t)written;
64 reverse[digits++] = (char)(
'0' + (value % (uint64_t)
k_decimal_base));
66 }
while (value != 0U);
67 for (
size_t i = 0U; i < digits; ++i) {
68 forward[i] = reverse[digits - i - 1U];
70 forward[digits] =
'\0';
77 if (offset > (uint64_t)INT64_MAX || length > ((uint64_t)INT64_MAX - offset)) {
81 while (done < length) {
82 size_t request = length - done;
83 if (request > (
size_t)SSIZE_MAX) {
84 request = (size_t)SSIZE_MAX;
86 const ssize_t got = pread(fd, &bytes[done], request, (off_t)(offset + done));
87 if ((got < 0) && (errno == EINTR)) {
118 if (offset > (uint64_t)INT64_MAX || length > ((uint64_t)INT64_MAX - offset)) {
122 while (done < length) {
123 size_t request = length - done;
124 if (request > (
size_t)SSIZE_MAX) {
125 request = (size_t)SSIZE_MAX;
127 const ssize_t put = pwrite(fd, &bytes[done], request, (off_t)(offset + done));
128 if ((put < 0) && (errno == EINTR)) {
160 uint64_t* out_offset,
169 const uint64_t offset = lba * disk->
block_size;
170 const size_t bytes = (size_t)count * disk->
block_size;
171 if (offset > (uint64_t)INT64_MAX || bytes > ((uint64_t)INT64_MAX - offset)) {
174 *out_offset = offset;
203 if (disk ==
nullptr || buffer ==
nullptr || disk->
io_failed ||
238 if (disk ==
nullptr || buffer ==
nullptr || disk->
io_failed ||
269 if (disk ==
nullptr || block_count ==
nullptr || block_size ==
nullptr) {
297 const size_t length =
strlen(path);
301 size_t slash = length;
302 while (slash > 0U && path[slash - 1U] !=
'/') {
305 const size_t leaf_start = slash;
306 const size_t leaf_bytes = length - leaf_start;
310 (void)
memcpy(final_name, &path[leaf_start], leaf_bytes);
311 final_name[leaf_bytes] =
'\0';
312 if (
strcmp(final_name,
".") == 0 ||
strcmp(final_name,
"..") == 0) {
318 }
else if (slash == 1U) {
322 const size_t parent_bytes = slash - 1U;
323 (void)
memcpy(parent, path, parent_bytes);
324 parent[parent_bytes] =
'\0';
348 static const char s_prefix[] =
".mkbookimg.tmp.";
350 size_t offset =
sizeof(
s_prefix) - 1U;
352 uint64_t values[2] = {process, attempt};
353 for (uint8_t field = 0U; field < 2U; ++field) {
356 reverse[digits++] = (char)(
'0' + (values[field] % (uint64_t)
k_decimal_base));
358 }
while (values[field] != 0U);
362 while (digits > 0U) {
363 out[offset++] = reverse[--digits];
365 out[offset++] = (field == 0U) ?
'.' :
'\0';
408 if (errno != EEXIST) {
413 if (output->
image_fd < 0 || image_bytes > (uint64_t)INT64_MAX ||
414 ftruncate(output->
image_fd, (off_t)image_bytes) != 0) {
474 bool ok = fsync(output->
image_fd) == 0;
545 const int book_count = argc - 2;
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_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 ra8_err_t internal_disk_read(void *ctx, uint64_t lba, uint32_t count, uint8_t *buffer)
Read blocks from the sparse unpublished image.
#define O_DIRECTORY
No-op directory-open fallback for hosts lacking the flag.
static ra8_err_t internal_disk_capacity(void *ctx, uint64_t *block_count, uint32_t *block_size)
Report the fixed card-image geometry.
#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.
static bool internal_output_commit(mkbookimg_output_t *output)
Durably publish the complete image with one same-directory rename.
static ra8_err_t internal_disk_write(void *ctx, uint64_t lba, uint32_t count, const uint8_t *buffer)
Write sectors to the temporary image for ra8_fs.
bool priv_mkbookimg_pread_exact(int fd, uint64_t offset, uint8_t *bytes, size_t length)
Read exactly one bounded positioned byte range.
static bool internal_split_output(const char *path, char parent[k_host_path_cap], char final_name[k_host_name_cap])
Split an output path into an existing parent directory and safe leaf.
int main(int argc, char **argv)
Validate CLI input, construct, verify, and atomically publish one image.
static ra8_err_t internal_disk_read(void *ctx, uint64_t lba, uint32_t count, uint8_t *buffer)
Read sectors from the temporary image for ra8_fs.
void priv_mkbookimg_diag(const char *text)
Write a complete diagnostic fragment to the standard-error descriptor.
static bool internal_block_range(const mkbookimg_disk_t *disk, uint64_t lba, uint32_t count, uint64_t *out_offset, size_t *out_bytes)
Validate and translate a block range to a host byte range.
void priv_mkbookimg_diag_u64(uint64_t value)
Emit an unsigned decimal value without a formatting runtime.
static bool internal_output_begin(const char *final_path, mkbookimg_output_t *output)
Create and size a private sibling temporary for atomic publication.
static ra8_err_t internal_disk_capacity(void *ctx, uint64_t *block_count, uint32_t *block_size)
Report fixed image geometry to ra8_fs.
static void internal_output_abort(mkbookimg_output_t *output)
Close and remove an unpublished temporary image.
static bool internal_temp_name(char out[k_host_name_cap], uint64_t process, uint32_t attempt)
Build one hidden sibling-temporary leaf from process id and attempt.
static bool internal_pwrite_exact(int fd, uint64_t offset, const uint8_t *bytes, size_t length)
Write exactly one bounded positioned byte range.
static void internal_print_success(const char *out_path, int book_count)
Print the final success diagnostic line.
Module-private seams shared by the two mkbookimg translation units.
@ k_host_path_cap
Hosted path capacity.
@ k_block_size
Bytes per image sector.
@ k_img_sectors
Sectors in the 64 MiB image.
@ k_decimal_base
Decimal conversion radix.
@ k_host_name_cap
Hosted leaf capacity.
@ k_temp_create_attempts
Exclusive-create retry bound.
@ k_output_create_mode
Hosted output creation mode.
@ k_decimal_u64_digits
Maximum uint64_t digits.
@ k_max_books
Maximum input-book count.
bool priv_mkbookimg_build_image(const ra8_fs_backend_t *backend, char **argv, int book_count, const mkbookimg_disk_t *disk)
Format, populate, and unmount the destination image.
Derive an on-card file name from a source book path (long-name capable).
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ 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).
static const uint8_t s_prefix[k_ra8_net_provision_prefix_bytes]
Exact protocol prefix, including the first field separator.
Host descriptor-backed block device bound into ra8_fs.
bool io_failed
Sticky positioned-I/O failure.
uint64_t block_count
Addressable sectors.
int fd
Open sibling-temporary descriptor.
uint32_t block_size
Bytes in one sector.
Caller-owned atomic-publication state.
bool temp_exists
Temp leaf requires unlink.
int image_fd
Open temporary image.
int directory_fd
Destination-directory handle.
char final_name[k_host_name_cap]
Destination leaf.
char temp_name[k_host_name_cap]
Owned temporary leaf.
Block-device interface that ra8_fs runs on top of.