ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_library.c
Go to the documentation of this file.
1
9#include "mdl_library.h"
10
11#include <stdint.h>
12#include <string.h>
13
14#include "mdl_sanitize.h"
15#include "ra8_attributes.h"
16
18static const char s_state_basename[] = ".mdl_state";
19
28
30{
31 return (mdl_library_policy_t){.max_entries = (uint32_t)k_mdl_library_entry_limit,
32 .max_operations = (uint32_t)k_mdl_library_operation_limit,
33 .max_depth = (uint16_t)k_mdl_library_depth_limit};
34}
35
37 void* directory_workspace,
38 uint32_t directory_workspace_bytes)
39{
40 if ((workspace == nullptr) || (directory_workspace == nullptr) ||
41 (directory_workspace_bytes == 0U)) {
43 }
44 *workspace = (mdl_library_workspace_t){.directory_workspace = directory_workspace,
45 .directory_workspace_bytes = directory_workspace_bytes};
46 return k_ra8_ok;
47}
48
63{
64 workspace->entries = 0U;
65 workspace->required_entries = 0U;
66 workspace->entry_limit = 0U;
67 workspace->operations = 0U;
68 workspace->depth = 0U;
69 memset(workspace->paths, 0, sizeof(workspace->paths));
70}
71
88{
89 if ((policy == nullptr) || (policy->max_entries == 0U) || (policy->max_operations == 0U)) {
91 }
92 if ((policy->max_entries > (uint32_t)k_mdl_library_entry_limit) ||
93 (policy->max_operations > (uint32_t)k_mdl_library_operation_limit) ||
94 (policy->max_depth > (uint16_t)k_mdl_library_depth_limit)) {
96 }
97 return k_ra8_ok;
98}
99
119 const fw_fs_dirent_value_t* entry,
120 size_t* out_length)
121{
122 if (entry->name_bytes == 0U) {
124 }
125 const size_t length = strnlen(entry->name, (size_t)k_fw_fs_path_cap);
126 if ((length >= (size_t)k_fw_fs_path_cap) || (length != (size_t)entry->name_bytes) ||
127 (length > (size_t)storage->fs->caps.name_max_bytes)) {
129 }
130 if ((strcmp(entry->name, ".") == 0) || (strcmp(entry->name, "..") == 0) ||
131 (strpbrk(entry->name, "/\\") != nullptr)) {
133 }
134 *out_length = length;
135 return k_ra8_ok;
136}
137
155 const fw_fs_dirent_value_t* entry,
156 bool* out_continue)
157{
158 *out_continue = true;
159 if (entry->type != k_fw_fs_node_directory) {
160 return k_ra8_ok;
161 }
162 char series[k_fw_fs_path_cap];
163 char state[k_fw_fs_path_cap];
164 if (!mdl_path_join(walk->root, entry->name, series, sizeof(series)) ||
165 !mdl_path_join(series, s_state_basename, state, sizeof(state))) {
167 }
168 ra8_err_t err = k_ra8_ok;
169 fw_fs_stat_t node = {};
170 err = fw_fs_stat(&walk->storage->fs->names, series, &node);
171 if (err != k_ra8_ok) {
172 return err;
173 }
174 if (!node.exists || (node.type != entry->type)) {
176 }
177 bool tracked = false;
178 err = mdl_state_probe(walk->storage, state, &tracked);
179 if ((err != k_ra8_ok) || !tracked) {
180 *out_continue = !tracked && (err == k_ra8_ok);
181 return err;
182 }
183 err = mdl_state_load_authenticated(walk->storage, state, walk->state);
184 if (err != k_ra8_ok) {
185 return err;
186 }
187 bool user_continue = false;
188 err = walk->callback(series, state, walk->state, walk->callback_ctx, &user_continue);
189 if (err != k_ra8_ok) {
190 return err;
191 }
192 *out_continue = user_continue;
193 return k_ra8_ok;
194}
195
212{
213 if (!directory->is_open) {
214 return first;
215 }
216 const ra8_err_t closed = fw_fs_dir_close(directory);
217 return (first == k_ra8_ok) ? closed : first;
218}
219
239internal_library_root(mdl_storage_t* storage, const char* root_path, bool* out_exists)
240{
241 *out_exists = false;
242 fw_fs_stat_t root = {};
243 const ra8_err_t err = fw_fs_stat(&storage->fs->names, root_path, &root);
244 if ((err != k_ra8_ok) || !root.exists) {
245 return err;
246 }
247 if (root.type == k_fw_fs_node_symlink) {
249 }
250 *out_exists = root.type == k_fw_fs_node_directory;
251 return *out_exists ? k_ra8_ok : k_ra8_err_invalid_arg;
252}
253
273 const mdl_library_policy_t* policy,
274 mdl_library_workspace_t* workspace)
275{
276 fw_fs_dir_t directory = {};
277 ra8_err_t err = fw_fs_dir_open(&walk->storage->fs->names,
278 walk->root,
279 &directory,
280 workspace->directory_workspace,
281 workspace->directory_workspace_bytes);
282 while (err == k_ra8_ok) {
283 fw_fs_dirent_value_t entry = {};
284 bool present = false;
285 err = fw_fs_dir_next(&directory, &entry, &present);
286 if ((err != k_ra8_ok) || !present) {
287 break;
288 }
289 ++workspace->required_entries;
290 if (workspace->required_entries > policy->max_entries) {
292 break;
293 }
294 ++workspace->entries;
295 bool keep_going = false;
296 err = internal_library_visit(walk, &entry, &keep_going);
297 if ((err != k_ra8_ok) || !keep_going) {
298 break;
299 }
300 }
301 return internal_library_close(&directory, err);
302}
303
305 const char* out_dir,
306 mdl_state_t* state_scratch,
307 mdl_library_workspace_t* workspace,
308 const mdl_library_policy_t* policy,
309 mdl_library_fn callback,
310 void* callback_ctx)
311{
312 if ((storage == nullptr) || (storage->fs == nullptr) || (out_dir == nullptr) ||
313 (state_scratch == nullptr) || (workspace == nullptr) || (callback == nullptr) ||
314 (workspace->directory_workspace == nullptr) || (workspace->directory_workspace_bytes == 0U)) {
316 }
319 workspace->entry_limit = (policy != nullptr) ? policy->max_entries : 0U;
320 bool root_exists = false;
321 if (err == k_ra8_ok) {
322 err = internal_library_root(storage, out_dir, &root_exists);
323 }
324 if ((err != k_ra8_ok) || !root_exists) {
325 return err;
326 }
327 mdl_library_enumeration_t walk = {.storage = storage,
328 .root = out_dir,
329 .state = state_scratch,
330 .callback = callback,
331 .callback_ctx = callback_ctx};
332 return internal_library_enumerate(&walk, policy, workspace);
333}
334
351 mdl_library_workspace_t* workspace)
352{
353 if (workspace->operations >= policy->max_operations) {
355 }
356 ++workspace->operations;
357 return k_ra8_ok;
358}
359
382 const char* path,
383 const mdl_library_policy_t* policy,
384 mdl_library_workspace_t* workspace,
386 bool* out_present)
387{
388 const uint32_t remaining = policy->max_operations - workspace->operations;
389 if (remaining < 3U) {
391 }
392 workspace->operations += 3U;
393 fw_fs_dir_t directory = {};
394 ra8_err_t err = fw_fs_dir_open(&storage->fs->names,
395 path,
396 &directory,
397 workspace->directory_workspace,
398 workspace->directory_workspace_bytes);
399 if (err != k_ra8_ok) {
400 workspace->operations -= 2U;
401 return err;
402 }
403 err = fw_fs_dir_next(&directory, out, out_present);
404 return internal_library_close(&directory, err);
405}
406
431 const mdl_library_policy_t* policy,
432 mdl_library_workspace_t* workspace,
433 const char* path,
434 fw_fs_stat_t node)
435{
436 if (node.type == k_fw_fs_node_directory) {
437 if (workspace->depth >= policy->max_depth) {
439 }
440 ++workspace->depth;
441 memcpy(workspace->paths[workspace->depth], path, strlen(path) + 1U);
442 return k_ra8_ok;
443 }
444 if (node.type == k_fw_fs_node_symlink) {
446 }
447 if (node.type != k_fw_fs_node_file) {
449 }
450 const ra8_err_t err = internal_library_take_operation(policy, workspace);
451 return (err == k_ra8_ok) ? fw_fs_unlink(&storage->fs->names, path) : err;
452}
453
473 const mdl_library_policy_t* policy,
474 mdl_library_workspace_t* workspace,
475 const fw_fs_dirent_value_t* child)
476{
477 size_t length = 0U;
478 ra8_err_t err = internal_library_leaf(storage, child, &length);
479 (void)length;
480 if (err != k_ra8_ok) {
481 return err;
482 }
483 ++workspace->required_entries;
484 if (workspace->required_entries > policy->max_entries) {
486 }
487 ++workspace->entries;
488 char path[k_fw_fs_path_cap];
489 if (!mdl_path_join(workspace->paths[workspace->depth], child->name, path, sizeof(path))) {
491 }
492 err = internal_library_take_operation(policy, workspace);
493 fw_fs_stat_t node = {};
494 if (err == k_ra8_ok) {
495 err = fw_fs_stat(&storage->fs->names, path, &node);
496 }
497 if (err != k_ra8_ok) {
498 return err;
499 }
500 if (!node.exists || (node.type != child->type)) {
502 }
503 return internal_library_act_on_node(storage, policy, workspace, path, node);
504}
505
526 const char* dir,
527 const mdl_library_policy_t* policy,
528 mdl_library_workspace_t* workspace)
529{
531 workspace->entry_limit = policy->max_entries;
532 if ((dir[0] == '/') && (dir[1] == '\0')) {
534 }
535 ra8_err_t err = internal_library_take_operation(policy, workspace);
536 fw_fs_stat_t root = {};
537 if (err == k_ra8_ok) {
538 err = fw_fs_stat(&storage->fs->names, dir, &root);
539 }
540 if ((err != k_ra8_ok) || !root.exists) {
541 return err;
542 }
543 if (root.type == k_fw_fs_node_symlink) {
545 }
546 if (root.type != k_fw_fs_node_directory) {
548 }
549 const size_t root_length = strnlen(dir, sizeof(workspace->paths[0]));
550 if (root_length >= sizeof(workspace->paths[0])) {
552 }
553 memcpy(workspace->paths[0], dir, root_length + 1U);
554 return k_ra8_ok;
555}
556
576 const mdl_library_policy_t* policy,
577 mdl_library_workspace_t* workspace)
578{
579 for (;;) {
580 fw_fs_dirent_value_t child = {};
581 bool present = false;
583 workspace->paths[workspace->depth],
584 policy,
585 workspace,
586 &child,
587 &present);
588 if (err != k_ra8_ok) {
589 return err;
590 }
591 if (present) {
592 err = internal_library_remove_child(storage, policy, workspace, &child);
593 if (err != k_ra8_ok) {
594 return err;
595 }
596 continue;
597 }
598 err = internal_library_take_operation(policy, workspace);
599 if (err == k_ra8_ok) {
600 err = fw_fs_rmdir(&storage->fs->names, workspace->paths[workspace->depth]);
601 }
602 if ((err != k_ra8_ok) || (workspace->depth == 0U)) {
603 return err;
604 }
605 --workspace->depth;
606 }
607}
608
610 const char* dir,
611 const mdl_library_policy_t* policy,
612 mdl_library_workspace_t* workspace)
613{
614 if ((storage == nullptr) || (storage->fs == nullptr) || (dir == nullptr) ||
615 (workspace == nullptr) || (workspace->directory_workspace == nullptr) ||
616 (workspace->directory_workspace_bytes == 0U)) {
618 }
620 if (err == k_ra8_ok) {
621 err = internal_library_remove_root(storage, dir, policy, workspace);
622 }
623 return ((err == k_ra8_ok) && (workspace->paths[0][0] != '\0'))
624 ? internal_library_remove_walk(storage, policy, workspace)
625 : err;
626}
ra8_err_t fw_fs_stat(const fw_fs_namespace_t *names, const char *path, fw_fs_stat_t *out)
Query a path; a miss is success with out->exists == false.
Definition fw_if_fs.c:480
ra8_err_t fw_fs_rmdir(const fw_fs_namespace_t *names, const char *path)
Remove one empty directory; recursive deletion is deliberately absent.
Definition fw_if_fs.c:584
ra8_err_t fw_fs_dir_next(fw_fs_dir_t *directory, fw_fs_dirent_value_t *out, bool *out_entry)
Copy one stable directory entry from an open cursor.
ra8_err_t fw_fs_dir_close(fw_fs_dir_t *directory)
Close and consume an open directory cursor, including on close error.
ra8_err_t fw_fs_unlink(const fw_fs_namespace_t *names, const char *path)
Remove one regular file; directories require fw_fs_rmdir.
Definition fw_if_fs.c:575
ra8_err_t fw_fs_dir_open(const fw_fs_namespace_t *names, const char *path, fw_fs_dir_t *directory, void *workspace, uint32_t workspace_size)
Open one directory cursor into caller-owned backend workspace.
@ k_fw_fs_node_directory
Directory.
@ k_fw_fs_node_file
Regular byte stream.
@ k_fw_fs_node_symlink
Symbolic link, if observable.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
static ra8_err_t internal_library_remove_walk(mdl_storage_t *storage, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace)
Execute iterative post-order removal from a retained valid root.
static ra8_err_t internal_library_close(fw_fs_dir_t *directory, ra8_err_t first)
Preserve the first traversal error while always consuming a cursor.
static ra8_err_t internal_library_remove_child(mdl_storage_t *storage, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace, const fw_fs_dirent_value_t *child)
Remove or descend into one captured child.
static ra8_err_t internal_library_visit(mdl_library_enumeration_t *walk, const fw_fs_dirent_value_t *entry, bool *out_continue)
Authenticate and deliver one stable cursor entry.
static ra8_err_t internal_library_policy(const mdl_library_policy_t *policy)
Validate a caller-selected policy against hard ceilings.
Definition mdl_library.c:87
ra8_err_t mdl_library_workspace_init(mdl_library_workspace_t *workspace, void *directory_workspace, uint32_t directory_workspace_bytes)
Bind caller-owned directory storage to a reusable library workspace.
Definition mdl_library.c:36
ra8_err_t mdl_library_for_each(mdl_storage_t *storage, const char *out_dir, mdl_state_t *state_scratch, mdl_library_workspace_t *workspace, const mdl_library_policy_t *policy, mdl_library_fn callback, void *callback_ctx)
Visit every authenticated tracked series under a library root.
static ra8_err_t internal_library_take_operation(const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace)
Consume one removal namespace-operation budget unit.
static ra8_err_t internal_library_act_on_node(mdl_storage_t *storage, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace, const char *path, fw_fs_stat_t node)
Act on one revalidated child node according to its type.
static ra8_err_t internal_library_leaf(const mdl_storage_t *storage, const fw_fs_dirent_value_t *entry, size_t *out_length)
Validate and measure one borrowed backend leaf name.
static void internal_library_workspace_reset(mdl_library_workspace_t *workspace)
Clear traversal state while preserving caller cursor storage.
Definition mdl_library.c:62
static const char s_state_basename[]
Logical marker basename within one tracked series.
Definition mdl_library.c:18
static ra8_err_t internal_library_root(mdl_storage_t *storage, const char *root_path, bool *out_exists)
Validate one library root before cursor open.
static ra8_err_t internal_library_first_child(mdl_storage_t *storage, const char *path, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace, fw_fs_dirent_value_t *out, bool *out_present)
Copy at most one child then close before any namespace mutation.
static ra8_err_t internal_library_remove_root(mdl_storage_t *storage, const char *dir, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace)
Validate and retain the root of one removal traversal.
static ra8_err_t internal_library_enumerate(mdl_library_enumeration_t *walk, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace)
Advance one cursor while authenticating entries between next calls.
mdl_library_policy_t mdl_library_policy_default(void)
Return the production library traversal policy.
Definition mdl_library.c:29
ra8_err_t mdl_library_remove_tree(mdl_storage_t *storage, const char *dir, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace)
Remove one canonical directory tree through portable namespace calls.
Portable bounded operations over a tracked media library.
@ k_mdl_library_entry_limit
Maximum discovered entries.
Definition mdl_library.h:30
@ k_mdl_library_operation_limit
Maximum namespace calls.
Definition mdl_library.h:31
@ k_mdl_library_depth_limit
Maximum child-dir nesting.
Definition mdl_library.h:32
ra8_err_t(* mdl_library_fn)(const char *series_dir, const char *state_path, const mdl_state_t *state, void *ctx, bool *out_continue)
Per-series visitor callback for mdl_library_for_each.
Neutralise untrusted names before they reach a filesystem or XML sink.
bool mdl_path_join(const char *parent, const char *seg, char *out, size_t cap)
Join one safe child segment under a parent directory path.
ra8_err_t mdl_state_load_authenticated(mdl_storage_t *storage, const char *path, mdl_state_t *st)
Load only an authenticated checksummed state generation.
ra8_err_t mdl_state_probe(mdl_storage_t *storage, const char *path, bool *out_exists)
Probe the complete two-generation state marker through portable storage.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_access_denied
Operation refused because the target is protected against it.
Definition ra8_err.h:276
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
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.
size_t strnlen(const char *s, size_t maxlen)
Calculate bounded string length.
uint16_t name_max_bytes
Component bytes excluding NUL.
Caller-owned open directory cursor; fields are private to the facade.
bool is_open
Facade lifecycle guard.
Stable caller-owned value returned by fw_fs_dir_next.
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.
Result of a portable metadata query.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
fw_fs_caps_t caps
Shared capabilities.
fw_fs_namespace_t names
Namespace operations.
State threaded through one immediate-library enumeration.
Definition mdl_library.c:21
void * callback_ctx
Opaque visitor context.
Definition mdl_library.c:26
mdl_library_fn callback
Authenticated visitor.
Definition mdl_library.c:25
mdl_storage_t * storage
Portable dependency bundle.
Definition mdl_library.c:22
mdl_state_t * state
Authentication scratch.
Definition mdl_library.c:24
const char * root
Canonical library root.
Definition mdl_library.c:23
Caller-selected limits within the compile-time hard ceilings.
Definition mdl_library.h:39
uint32_t max_operations
Namespace calls permitted for removal.
Definition mdl_library.h:41
uint32_t max_entries
Entries accepted before fail-closed stop.
Definition mdl_library.h:40
uint16_t max_depth
Child-directory nesting below the root.
Definition mdl_library.h:42
Caller-owned directory cursor storage and iterative traversal stack.
Definition mdl_library.h:53
uint32_t required_entries
Entries observed through cap+1.
Definition mdl_library.h:59
uint16_t depth
Current stack depth, root is zero.
Definition mdl_library.h:62
char paths[(size_t) k_mdl_library_depth_limit+1U][k_fw_fs_path_cap]
DFS path stack, one canonical path at each permitted depth.
Definition mdl_library.h:55
void * directory_workspace
Backend cursor workspace.
Definition mdl_library.h:56
uint32_t entry_limit
Active explicit traversal limit.
Definition mdl_library.h:60
uint32_t entries
Entries accepted by the traversal.
Definition mdl_library.h:58
uint32_t operations
Namespace calls attempted.
Definition mdl_library.h:61
uint32_t directory_workspace_bytes
Cursor workspace extent.
Definition mdl_library.h:57
One series' complete persistent state (declare at file scope).
Definition mdl_state.h:175
One non-reentrant downloader filesystem dependency bundle.
Definition mdl_storage.h:40
const fw_fs_t * fs
Injected portable filesystem.
Definition mdl_storage.h:41