ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mkbookimg_books.c
Go to the documentation of this file.
1
20
21#include <fcntl.h>
22#include <stddef.h>
23#include <stdint.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
29#include "mkbookimg_internal.h"
30#include "mkbookimg_names.h"
31#include "ra8_attributes.h"
32#include "ra8_fs.h"
33
35typedef struct {
36 dev_t device;
37 ino_t inode;
38 uint64_t size;
39 time_t modified_sec;
41 time_t changed_sec;
44
59{
60#ifdef __APPLE__
61 const long modified_nsec = metadata->st_mtimespec.tv_nsec;
62 const long changed_nsec = metadata->st_ctimespec.tv_nsec;
63#else
64 const long modified_nsec = metadata->st_mtim.tv_nsec;
65 const long changed_nsec = metadata->st_ctim.tv_nsec;
66#endif
67 return (mkbookimg_input_identity_t){.device = metadata->st_dev,
68 .inode = metadata->st_ino,
69 .size = (uint64_t)metadata->st_size,
70 .modified_sec = metadata->st_mtime,
71 .modified_nsec = modified_nsec,
72 .changed_sec = metadata->st_ctime,
73 .changed_nsec = changed_nsec};
74}
75
92 const struct stat* actual)
93{
94 if (actual->st_size < 0) {
95 return false;
96 }
98 return expected->device == observed.device && expected->inode == observed.inode &&
99 expected->size == observed.size && expected->modified_sec == observed.modified_sec &&
100 expected->modified_nsec == observed.modified_nsec &&
101 expected->changed_sec == observed.changed_sec &&
102 expected->changed_nsec == observed.changed_nsec;
103}
104
121 const mkbookimg_input_identity_t* right)
122{
123 return left->device == right->device && left->inode == right->inode &&
124 left->size == right->size && left->modified_sec == right->modified_sec &&
125 left->modified_nsec == right->modified_nsec && left->changed_sec == right->changed_sec &&
126 left->changed_nsec == right->changed_nsec;
127}
128
145RA8_INTERNAL static bool
146internal_input_open(const char* path, int* out_fd, mkbookimg_input_identity_t* identity)
147{
148 const int fd = open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
149 if (fd < 0) {
150 return false;
151 }
152 struct stat metadata = {};
153 if (fstat(fd, &metadata) != 0 || !S_ISREG(metadata.st_mode) || metadata.st_size <= 0 ||
154 (uint64_t)metadata.st_size > UINT32_MAX) {
155 (void)close(fd);
156 return false;
157 }
158 *identity = internal_input_identity(&metadata);
159 *out_fd = fd;
160 return true;
161}
162
181 const char* name,
182 const char* path,
184{
185 int input_fd = -1;
186 if (!internal_input_open(path, &input_fd, identity)) {
187 return false;
188 }
189 ra8_fs_file_t* card = nullptr;
190 if (ra8_fs_open(mount, name, k_ra8_fs_mode_write, &card) != k_ra8_ok) {
191 (void)close(input_fd);
192 return false;
193 }
194 uint8_t chunk[k_stream_chunk_bytes];
195 uint64_t offset = 0U;
196 bool ok = true;
197 while (ok && offset < identity->size) {
198 size_t take = (size_t)(identity->size - offset);
199 if (take > sizeof(chunk)) {
200 take = sizeof(chunk);
201 }
202 ok = priv_mkbookimg_pread_exact(input_fd, offset, chunk, take) &&
203 ra8_fs_write(card, chunk, (uint32_t)take) == k_ra8_ok;
204 offset += take;
205 }
206 struct stat after = {};
207 if (fstat(input_fd, &after) != 0 || !internal_input_same(identity, &after)) {
208 ok = false;
209 }
210 if (close(input_fd) != 0) {
211 ok = false;
212 }
213 if (ra8_fs_close(card) != k_ra8_ok) {
214 ok = false;
215 }
216 return ok;
217}
218
241 const char* name,
242 const char* path,
243 const mkbookimg_input_identity_t* identity,
244 int* out_input_fd,
245 ra8_fs_file_t** out_card)
246{
247 int input_fd = -1;
249 if (!internal_input_open(path, &input_fd, &again)) {
250 if (input_fd >= 0) {
251 (void)close(input_fd);
252 }
253 return false;
254 }
255 if (!internal_identity_equal(identity, &again)) {
256 (void)close(input_fd);
257 return false;
258 }
259 ra8_fs_file_t* card = nullptr;
260 uint64_t card_size;
261 if (ra8_fs_open(mount, name, k_ra8_fs_mode_read, &card) != k_ra8_ok ||
262 ra8_fs_size(card, &card_size) != k_ra8_ok || card_size != identity->size) {
263 if (card != nullptr) {
264 (void)ra8_fs_close(card);
265 }
266 (void)close(input_fd);
267 return false;
268 }
269 *out_input_fd = input_fd;
270 *out_card = card;
271 return true;
272}
273
292 const char* name,
293 const char* path,
294 const mkbookimg_input_identity_t* identity)
295{
296 int input_fd = -1;
297 ra8_fs_file_t* card = nullptr;
298 if (!internal_verify_book_reopen(mount, name, path, identity, &input_fd, &card)) {
299 return false;
300 }
301 uint8_t source[k_stream_chunk_bytes];
302 uint8_t copied[k_stream_chunk_bytes];
303 uint64_t offset = 0U;
304 bool ok = true;
305 while (ok && offset < identity->size) {
306 uint32_t take = (uint32_t)(identity->size - offset);
307 if (take > (uint32_t)sizeof(source)) {
308 take = (uint32_t)sizeof(source);
309 }
310 uint32_t got = 0U;
311 ok = priv_mkbookimg_pread_exact(input_fd, offset, source, take) &&
312 ra8_fs_read(card, copied, take, &got) == k_ra8_ok && got == take &&
313 memcmp(source, copied, take) == 0;
314 offset += take;
315 }
316 struct stat after = {};
317 if (fstat(input_fd, &after) != 0 || !internal_input_same(identity, &after)) {
318 ok = false;
319 }
320 if (close(input_fd) != 0 || ra8_fs_close(card) != k_ra8_ok) {
321 ok = false;
322 }
323 return ok;
324}
325
341RA8_INTERNAL static bool internal_duplicate_name(char** arguments, int index)
342{
343 const char* name = mkbookimg_basename(arguments[2 + index]);
344 for (int prior = 0; prior < index; ++prior) {
345 if (strcmp(name, mkbookimg_basename(arguments[2 + prior])) == 0) {
346 return true;
347 }
348 }
349 return false;
350}
351
368 ra8_fs_mount_t** mount)
369{
370 const ra8_fs_format_opts_t options = {.type = k_ra8_fs_type_fat32, .label = "RABOOKS"};
371 if (ra8_fs_format(backend, &options) != k_ra8_ok) {
372 priv_mkbookimg_diag("mkbookimg: ra8_fs_format failed\n");
373 return false;
374 }
375 if (ra8_fs_mount(backend, mount) != k_ra8_ok) {
376 priv_mkbookimg_diag("mkbookimg: ra8_fs_mount failed\n");
377 return false;
378 }
379 return true;
380}
381
398RA8_INTERNAL static bool
399internal_write_books(ra8_fs_mount_t* mount, char** arguments, int book_count)
400{
401 for (int index = 0; index < book_count; ++index) {
402 char name[k_mkbookimg_name_cap];
403 if (!mkbookimg_dest_name(arguments[2 + index], name, sizeof(name))) {
404 priv_mkbookimg_diag("mkbookimg: unusable card name for ");
405 priv_mkbookimg_diag(arguments[2 + index]);
407 return false;
408 }
409 if (internal_duplicate_name(arguments, index)) {
410 priv_mkbookimg_diag("mkbookimg: duplicate card name ");
413 return false;
414 }
416 if (!internal_stream_book(mount, name, arguments[2 + index], &identity) ||
417 !internal_verify_book(mount, name, arguments[2 + index], &identity)) {
418 priv_mkbookimg_diag("mkbookimg: input changed or could not be copied exactly: ");
419 priv_mkbookimg_diag(arguments[2 + index]);
421 return false;
422 }
423 priv_mkbookimg_diag("mkbookimg: + ");
427 priv_mkbookimg_diag(" bytes) <- ");
428 priv_mkbookimg_diag(arguments[2 + index]);
430 }
431 return true;
432}
433
436 char** argv,
437 int book_count,
438 const mkbookimg_disk_t* disk)
439{
440 ra8_fs_mount_t* mount = nullptr;
441 bool ok = internal_format_mount(backend, &mount);
442 if (ok) {
443 ok = internal_write_books(mount, argv, book_count);
444 if (ra8_fs_unmount(mount) != k_ra8_ok) {
445 ok = false;
446 }
447 }
448 if (disk->io_failed) {
449 ok = false;
450 }
451 return ok;
452}
#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_verify_book_reopen(ra8_fs_mount_t *mount, const char *name, const char *path, const mkbookimg_input_identity_t *identity, int *out_input_fd, ra8_fs_file_t **out_card)
Reopen host and card handles and confirm identity and size.
static bool internal_duplicate_name(char **arguments, int index)
Detect whether one input would overwrite an earlier basename.
static bool internal_identity_equal(const mkbookimg_input_identity_t *left, const mkbookimg_input_identity_t *right)
Compare two captured host-input identities field by field.
static mkbookimg_input_identity_t internal_input_identity(const struct stat *metadata)
Extract nanosecond-resolution identity fields portably.
static bool internal_format_mount(const ra8_fs_backend_t *backend, ra8_fs_mount_t **mount)
Format and mount the descriptor-backed FAT32 image.
static bool internal_stream_book(ra8_fs_mount_t *mount, const char *name, const char *path, mkbookimg_input_identity_t *identity)
Stream one host input into a newly truncated filesystem file.
static bool internal_input_same(const mkbookimg_input_identity_t *expected, const struct stat *actual)
Compare a captured identity with a fresh fstat result.
static bool internal_input_open(const char *path, int *out_fd, mkbookimg_input_identity_t *identity)
Open and identify one immutable regular input without following its leaf.
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.
static bool internal_write_books(ra8_fs_mount_t *mount, char **arguments, int book_count)
Stream and verify every requested book through the mounted filesystem.
static bool internal_verify_book(ra8_fs_mount_t *mount, const char *name, const char *path, const mkbookimg_input_identity_t *identity)
Re-read host and card bytes to prove the streamed copy and input stability.
Module-private seams shared by the two mkbookimg translation units.
bool priv_mkbookimg_pread_exact(int fd, uint64_t offset, uint8_t *bytes, size_t length)
Read exactly one bounded positioned byte range.
Definition mkbookimg.c:75
void priv_mkbookimg_diag(const char *text)
Write a complete diagnostic fragment to the standard-error descriptor.
Definition mkbookimg.c:41
void priv_mkbookimg_diag_u64(uint64_t value)
Emit an unsigned decimal value without a formatting runtime.
Definition mkbookimg.c:58
@ k_stream_chunk_bytes
Bounded copy chunk bytes.
Derive an on-card file name from a source book path (long-name capable).
static bool mkbookimg_dest_name(const char *path, char *out, size_t cap)
Derive the on-card destination name for a source book path.
@ k_mkbookimg_name_cap
Destination-name buffer bytes incl.
static const char * mkbookimg_basename(const char *path)
Return the basename of path: the run after its last '/'.
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_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
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_write(ra8_fs_file_t *file, const uint8_t *buf, uint32_t len)
Write len bytes; allocate new clusters from FAT free-space scan as needed.
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_size(const ra8_fs_file_t *file, uint64_t *out_bytes)
Report the file's size in bytes (64-bit on exFAT, #676).
ra8_err_t ra8_fs_read(ra8_fs_file_t *file, uint8_t *buf, uint32_t max_len, uint32_t *got_len)
Read up to max_len bytes; advance the cluster chain on cluster crossings.
ra8_err_t ra8_fs_open(ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
Open or create a file by path, 8.3 or long.
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_close(ra8_fs_file_t *file)
Close an open file, stamping its final modification time.
@ k_ra8_fs_type_fat32
count_of_clusters >= 65525.
@ k_ra8_fs_mode_read
Read-only, must exist.
@ k_ra8_fs_mode_write
Truncate (or create) for writing.
Host descriptor-backed block device bound into ra8_fs.
bool io_failed
Sticky positioned-I/O failure.
Stable facts used to detect input replacement or mutation.
long modified_nsec
Modification nanoseconds.
dev_t device
Host device identity.
ino_t inode
Host inode identity.
time_t changed_sec
Metadata-change seconds.
time_t modified_sec
Modification seconds.
uint64_t size
Captured input length.
long changed_nsec
Metadata-change nanoseconds.
Block-device interface that ra8_fs runs on top of.
Open-file state.
Tunables for ra8_fs_format() (the on-disk geometry of a fresh volume).
Cached parse of one mounted FAT volume.