ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
fw_if_fs.c
Go to the documentation of this file.
1
16
17#include "fw_if_fs.h"
18
19#include <stddef.h>
20#include <stdint.h>
21#include <string.h>
22
23#include "fw_if_fs_backend.h"
24#include "fw_if_fs_types.h"
25#include "ra8_attributes.h"
26#include "ra8_err.h"
27
29typedef enum : uint8_t {
33
49RA8_INTERNAL static bool internal_power_of_two(uint32_t value)
50{
51 if (value == 0U) {
52 return false;
53 }
54 return (value & (value - 1U)) == 0U;
55}
56
79internal_workspace(void* workspace, uint32_t bytes, uint32_t need, uint8_t align)
80{
81 if (workspace == nullptr) {
82 return k_ra8_err_null_ptr;
83 }
84 if (bytes < need) {
85 return k_ra8_err_no_mem;
86 }
87 if (!internal_power_of_two((uint32_t)align)) {
89 }
90 if (((uintptr_t)workspace % (uintptr_t)align) != 0U) {
92 }
93 return k_ra8_ok;
94}
95
113{
114 if (names == nullptr) {
115 return k_ra8_err_null_ptr;
116 }
117 if (names->iface == nullptr) {
119 }
120 return k_ra8_ok;
121}
122
141{
142 if (file == nullptr) {
143 return k_ra8_err_null_ptr;
144 }
145 if (!file->is_open) {
147 }
148 if (file->iface == nullptr) {
150 }
151 return k_ra8_ok;
152}
153
172{
173 if (transaction == nullptr) {
174 return k_ra8_err_null_ptr;
175 }
176 if (!transaction->active) {
178 }
179 if (transaction->iface == nullptr) {
181 }
182 return k_ra8_ok;
183}
184
203RA8_INTERNAL static ra8_err_t internal_component(const char* path, uint16_t start, uint16_t length)
204{
205 if (length == 0U) {
207 }
208 if (length == 1U) {
209 if (path[start] == '.') {
211 }
212 }
213 if (length == 2U) {
214 if (path[start] == '.') {
215 if (path[(uint16_t)(start + 1U)] == '.') {
217 }
218 }
219 }
220 return k_ra8_ok;
221}
222
248 const char* path)
249{
250 uint16_t component_start = 1U;
251 uint16_t component_len = 0U;
252 for (uint16_t i = 1U; i < caps->path_max_bytes; ++i) {
253 const unsigned char value = (unsigned char)path[i];
254 if (value == (unsigned char)'\0') {
255 return internal_component(path, component_start, component_len);
256 }
257 if (value == (unsigned char)'/') {
258 const ra8_err_t component = internal_component(path, component_start, component_len);
259 if (component != k_ra8_ok) {
260 return component;
261 }
262 component_start = (uint16_t)(i + 1U);
263 component_len = 0U;
264 continue;
265 }
266 if (value == (unsigned char)':') {
268 }
269 if (value == (unsigned char)'\\') {
271 }
272 if (value < (unsigned char)k_fw_fs_ascii_space) {
274 }
275 if (value == (unsigned char)k_fw_fs_ascii_delete) {
277 }
278 ++component_len;
279 if (component_len > caps->name_max_bytes) {
281 }
282 }
284}
285
286ra8_err_t fw_fs_path_validate(const fw_fs_caps_t* caps, const char* path)
287{
288 if (caps == nullptr) {
289 return k_ra8_err_null_ptr;
290 }
291 if (path == nullptr) {
292 return k_ra8_err_null_ptr;
293 }
294 if (caps->path_max_bytes < 2U) {
296 }
297 if (caps->path_max_bytes > (uint16_t)k_fw_fs_path_cap) {
299 }
300 if (caps->name_max_bytes == 0U) {
302 }
303 if (path[0] != '/') {
305 }
306 if (path[1] == '\0') {
307 return k_ra8_ok;
308 }
309 return internal_fw_fs_scan_components(caps, path);
310}
311
331 const fw_fs_stream_iface_t* streams,
332 const fw_fs_transaction_iface_t* transactions)
333{
334 if (names->stat == nullptr || names->listdir == nullptr) {
336 }
337 if (names->dir_open == nullptr || names->dir_next == nullptr || names->dir_close == nullptr) {
339 }
340 if (names->mkdir == nullptr || names->unlink == nullptr) {
342 }
343 if (names->rmdir == nullptr || names->rename == nullptr) {
345 }
346 if (streams->open == nullptr || streams->read == nullptr) {
348 }
349 if (streams->write == nullptr || streams->close == nullptr) {
351 }
352 if (streams->seek == nullptr || streams->tell == nullptr || streams->size == nullptr) {
354 }
355 if (transactions == nullptr) {
356 return k_ra8_ok;
357 }
358 if (transactions->begin == nullptr || transactions->write == nullptr) {
360 }
361 if (transactions->seek == nullptr || transactions->validate == nullptr) {
363 }
364 return (transactions->commit == nullptr || transactions->abort == nullptr) ? k_ra8_err_invalid_arg
365 : k_ra8_ok;
366}
367
391 const fw_fs_stream_iface_t* stream_iface,
392 const fw_fs_transaction_iface_t* transaction_iface,
393 const fw_fs_caps_t* caps)
394{
395 const uint32_t required = (uint32_t)k_fw_fs_cap_namespace | (uint32_t)k_fw_fs_cap_stream;
396 if ((caps->flags & required) != required) {
398 }
399 if (((caps->flags & (uint32_t)k_fw_fs_cap_space_query) != 0U) &&
400 (namespace_iface->space == nullptr)) {
402 }
403 if (((caps->flags & (uint32_t)k_fw_fs_cap_file_sync) != 0U) && (stream_iface->sync == nullptr)) {
405 }
406 if (((caps->flags & (uint32_t)k_fw_fs_cap_durable_file_sync) != 0U) &&
407 ((caps->flags & (uint32_t)k_fw_fs_cap_file_sync) == 0U)) {
409 }
410 if (((caps->flags & (uint32_t)k_fw_fs_cap_transactions) != 0U) &&
411 (transaction_iface == nullptr)) {
413 }
416 }
417 if ((caps->directory_workspace_bytes == 0U) || (caps->max_open_directories == 0U) ||
420 }
423 }
424 return k_ra8_ok;
425}
426
428 const fw_fs_namespace_iface_t* namespace_iface,
429 const fw_fs_stream_iface_t* stream_iface,
430 const fw_fs_transaction_iface_t* transaction_iface,
431 void* ctx,
432 const fw_fs_caps_t* caps)
433{
434 if (out == nullptr || namespace_iface == nullptr || stream_iface == nullptr) {
435 return k_ra8_err_null_ptr;
436 }
437 if (ctx == nullptr || caps == nullptr) {
438 return k_ra8_err_null_ptr;
439 }
440 const ra8_err_t interfaces =
441 internal_interfaces(namespace_iface, stream_iface, transaction_iface);
442 if (interfaces != k_ra8_ok) {
443 return interfaces;
444 }
445 const ra8_err_t caps_status =
446 internal_fw_fs_caps_validate(namespace_iface, stream_iface, transaction_iface, caps);
447 if (caps_status != k_ra8_ok) {
448 return caps_status;
449 }
450 const ra8_err_t root_path = fw_fs_path_validate(caps, "/");
451 if (root_path != k_ra8_ok) {
452 return root_path;
453 }
454
455 out->caps = *caps;
456 out->names.iface = namespace_iface;
457 out->names.ctx = ctx;
458 out->names.caps = *caps;
459 out->streams.iface = stream_iface;
460 out->streams.ctx = ctx;
461 out->streams.caps = *caps;
462 out->transactions.iface = transaction_iface;
463 out->transactions.ctx = ctx;
464 out->transactions.caps = *caps;
465 return k_ra8_ok;
466}
467
469{
470 if (fs == nullptr || out == nullptr) {
471 return k_ra8_err_null_ptr;
472 }
473 if (fs->names.iface == nullptr) {
475 }
476 *out = fs->caps;
477 return k_ra8_ok;
478}
479
480ra8_err_t fw_fs_stat(const fw_fs_namespace_t* names, const char* path, fw_fs_stat_t* out)
481{
482 const ra8_err_t valid = internal_names(names);
483 if (valid != k_ra8_ok) {
484 return valid;
485 }
486 if (out == nullptr) {
487 return k_ra8_err_null_ptr;
488 }
489 const ra8_err_t path_err = fw_fs_path_validate(&names->caps, path);
490 if (path_err != k_ra8_ok) {
491 return path_err;
492 }
493 (void)memset(out, 0, sizeof(*out));
494 const ra8_err_t result = names->iface->stat(names->ctx, path, out);
495 if (result == k_ra8_ok) {
496 const bool type_invalid = (uint32_t)out->type > (uint32_t)k_fw_fs_node_other;
497 const bool missing_invalid =
498 !out->exists && ((out->type != k_fw_fs_node_none) || (out->size_bytes != 0U));
499 const bool present_invalid = out->exists && (out->type == k_fw_fs_node_none);
500 const bool directory_invalid = (out->type == k_fw_fs_node_directory) && (out->size_bytes != 0U);
501 if (type_invalid || missing_invalid || present_invalid || directory_invalid) {
502 (void)memset(out, 0, sizeof(*out));
504 }
505 }
506 return result;
507}
508
510 const char* path,
511 uint32_t max_entries,
512 fw_fs_list_fn_t callback,
513 void* callback_ctx,
514 uint32_t* out_count,
515 bool* out_complete)
516{
517 const ra8_err_t valid = internal_names(names);
518 if (valid != k_ra8_ok) {
519 return valid;
520 }
521 if (callback == nullptr || out_count == nullptr || out_complete == nullptr) {
522 return k_ra8_err_null_ptr;
523 }
524 if (max_entries == 0U) {
526 }
527 const ra8_err_t path_err = fw_fs_path_validate(&names->caps, path);
528 if (path_err != k_ra8_ok) {
529 return path_err;
530 }
531 *out_count = 0U;
532 *out_complete = false;
533 const ra8_err_t result =
534 names->iface
535 ->listdir(names->ctx, path, max_entries, callback, callback_ctx, out_count, out_complete);
536 if (*out_count > max_entries) {
537 *out_count = 0U;
538 *out_complete = false;
540 }
541 return result;
542}
543
546 const char* path,
547 ra8_err_t (*operation)(void*, const char*))
548{
549 const ra8_err_t valid = internal_names(names);
550 if (valid != k_ra8_ok) {
551 return valid;
552 }
553 if (operation == nullptr) {
555 }
556 const ra8_err_t path_err = fw_fs_path_validate(&names->caps, path);
557 if (path_err != k_ra8_ok) {
558 return path_err;
559 }
560 if (path[1] == '\0') {
562 }
563 return operation(names->ctx, path);
564}
565
566ra8_err_t fw_fs_mkdir(const fw_fs_namespace_t* names, const char* path)
567{
568 const ra8_err_t valid = internal_names(names);
569 if (valid != k_ra8_ok) {
570 return valid;
571 }
572 return internal_name_op(names, path, names->iface->mkdir);
573}
574
575ra8_err_t fw_fs_unlink(const fw_fs_namespace_t* names, const char* path)
576{
577 const ra8_err_t valid = internal_names(names);
578 if (valid != k_ra8_ok) {
579 return valid;
580 }
581 return internal_name_op(names, path, names->iface->unlink);
582}
583
584ra8_err_t fw_fs_rmdir(const fw_fs_namespace_t* names, const char* path)
585{
586 const ra8_err_t valid = internal_names(names);
587 if (valid != k_ra8_ok) {
588 return valid;
589 }
590 return internal_name_op(names, path, names->iface->rmdir);
591}
592
594 const char* old_path,
595 const char* new_path,
596 bool replace)
597{
598 const ra8_err_t valid = internal_names(names);
599 if (valid != k_ra8_ok) {
600 return valid;
601 }
602 if (replace) {
603 if ((names->caps.flags & (uint32_t)k_fw_fs_cap_atomic_replace) == 0U) {
605 }
606 } else if ((names->caps.flags & (uint32_t)k_fw_fs_cap_atomic_noreplace) == 0U) {
608 }
609 const ra8_err_t old_err = fw_fs_path_validate(&names->caps, old_path);
610 if (old_err != k_ra8_ok) {
611 return old_err;
612 }
613 const ra8_err_t new_err = fw_fs_path_validate(&names->caps, new_path);
614 if (new_err != k_ra8_ok) {
615 return new_err;
616 }
617 if (old_path[1] == '\0' || new_path[1] == '\0') {
619 }
620 return names->iface->rename(names->ctx, old_path, new_path, replace);
621}
622
624{
625 const ra8_err_t valid = internal_names(names);
626 if (valid != k_ra8_ok) {
627 return valid;
628 }
629 if (out == nullptr) {
630 return k_ra8_err_null_ptr;
631 }
632 if ((names->caps.flags & (uint32_t)k_fw_fs_cap_space_query) == 0U) {
634 }
635 if (names->iface->space == nullptr) {
637 }
638 (void)memset(out, 0, sizeof(*out));
639 const ra8_err_t result = names->iface->space(names->ctx, out);
640 if ((result == k_ra8_ok) &&
641 ((out->free_bytes > out->total_bytes) || (out->used_bytes > out->total_bytes))) {
642 (void)memset(out, 0, sizeof(*out));
644 }
645 return result;
646}
647
649 const char* path,
651 fw_fs_file_t* file,
652 void* workspace,
653 uint32_t workspace_size)
654{
655 if (streams == nullptr || file == nullptr) {
656 return k_ra8_err_null_ptr;
657 }
658 if (streams->iface == nullptr) {
660 }
661 if (file->is_open) {
662 return k_ra8_err_busy;
663 }
664 if ((uint32_t)mode > (uint32_t)k_fw_fs_open_create_new) {
666 }
667 if (mode == k_fw_fs_open_create_new) {
668 if ((streams->caps.flags & (uint32_t)k_fw_fs_cap_create_exclusive) == 0U) {
670 }
671 }
672 const ra8_err_t path_err = fw_fs_path_validate(&streams->caps, path);
673 if (path_err != k_ra8_ok) {
674 return path_err;
675 }
676 if (path[1] == '\0') {
678 }
679 const ra8_err_t work = internal_workspace(workspace,
680 workspace_size,
681 streams->caps.file_workspace_bytes,
682 streams->caps.file_workspace_align);
683 if (work != k_ra8_ok) {
684 return work;
685 }
686 const ra8_err_t opened =
687 streams->iface->open(streams->ctx, path, mode, workspace, workspace_size);
688 if (opened != k_ra8_ok) {
689 return opened;
690 }
691 file->iface = streams->iface;
692 file->ctx = streams->ctx;
693 file->state = workspace;
694 file->state_bytes = workspace_size;
695 file->is_open = true;
696 return k_ra8_ok;
697}
698
699ra8_err_t fw_fs_read(fw_fs_file_t* file, uint8_t* dst, uint32_t cap, uint32_t* out_read)
700{
701 const ra8_err_t valid = internal_file(file);
702 if (valid != k_ra8_ok) {
703 return valid;
704 }
705 if (dst == nullptr || out_read == nullptr) {
706 return k_ra8_err_null_ptr;
707 }
708 *out_read = 0U;
709 const ra8_err_t result = file->iface->read(file->ctx, file->state, dst, cap, out_read);
710 if (*out_read > cap) {
711 *out_read = 0U;
713 }
714 return result;
715}
716
718fw_fs_write(fw_fs_file_t* file, const uint8_t* source, uint32_t length, uint32_t* out_written)
719{
720 const ra8_err_t valid = internal_file(file);
721 if (valid != k_ra8_ok) {
722 return valid;
723 }
724 if (source == nullptr || out_written == nullptr) {
725 return k_ra8_err_null_ptr;
726 }
727 *out_written = 0U;
728 const ra8_err_t result = file->iface->write(file->ctx, file->state, source, length, out_written);
729 if (*out_written > length) {
730 *out_written = 0U;
732 }
733 return result;
734}
735
736ra8_err_t fw_fs_seek(fw_fs_file_t* file, uint64_t offset)
737{
738 const ra8_err_t valid = internal_file(file);
739 if (valid != k_ra8_ok) {
740 return valid;
741 }
742 return file->iface->seek(file->ctx, file->state, offset);
743}
744
745ra8_err_t fw_fs_tell(fw_fs_file_t* file, uint64_t* out_offset)
746{
747 const ra8_err_t valid = internal_file(file);
748 if (valid != k_ra8_ok) {
749 return valid;
750 }
751 if (out_offset == nullptr) {
752 return k_ra8_err_null_ptr;
753 }
754 *out_offset = 0U;
755 return file->iface->tell(file->ctx, file->state, out_offset);
756}
757
758ra8_err_t fw_fs_file_size(fw_fs_file_t* file, uint64_t* out_size)
759{
760 const ra8_err_t valid = internal_file(file);
761 if (valid != k_ra8_ok) {
762 return valid;
763 }
764 if (out_size == nullptr) {
765 return k_ra8_err_null_ptr;
766 }
767 *out_size = 0U;
768 return file->iface->size(file->ctx, file->state, out_size);
769}
770
772{
773 const ra8_err_t valid = internal_file(file);
774 if (valid != k_ra8_ok) {
775 return valid;
776 }
777 if (file->iface->sync == nullptr) {
779 }
780 return file->iface->sync(file->ctx, file->state);
781}
782
784{
785 const ra8_err_t valid = internal_file(file);
786 if (valid != k_ra8_ok) {
787 return valid;
788 }
789 const ra8_err_t closed = file->iface->close(file->ctx, file->state);
790 file->iface = nullptr;
791 file->ctx = nullptr;
792 file->state = nullptr;
793 file->state_bytes = 0U;
794 file->is_open = false;
795 return closed;
796}
797
823 const fw_fs_transaction_t* transaction,
825{
826 if (port->iface == nullptr) {
827 return ((port->caps.flags & (uint32_t)k_fw_fs_cap_transactions) == 0U)
830 }
831 if ((port->caps.flags & (uint32_t)k_fw_fs_cap_transactions) == 0U) {
833 }
834 if (transaction->active) {
835 return k_ra8_err_busy;
836 }
837 if ((uint32_t)policy > (uint32_t)k_fw_fs_txn_replace_atomic) {
839 }
840 if (policy == k_fw_fs_txn_replace_atomic) {
841 if ((port->caps.flags & (uint32_t)k_fw_fs_cap_atomic_replace) == 0U) {
843 }
844 } else if ((port->caps.flags & (uint32_t)k_fw_fs_cap_atomic_noreplace) == 0U) {
846 }
847 return k_ra8_ok;
848}
849
851 const char* destination,
853 fw_fs_transaction_t* transaction,
854 void* workspace,
855 uint32_t workspace_size)
856{
857 if (port == nullptr || transaction == nullptr) {
858 return k_ra8_err_null_ptr;
859 }
860 const ra8_err_t preamble = internal_fw_fs_transaction_preamble(port, transaction, policy);
861 if (preamble != k_ra8_ok) {
862 return preamble;
863 }
864 const ra8_err_t path_err = fw_fs_path_validate(&port->caps, destination);
865 if (path_err != k_ra8_ok) {
866 return path_err;
867 }
868 if (destination[1] == '\0') {
870 }
871 const ra8_err_t work = internal_workspace(workspace,
872 workspace_size,
875 if (work != k_ra8_ok) {
876 return work;
877 }
878 const ra8_err_t begun =
879 port->iface->begin(port->ctx, workspace, workspace_size, destination, policy);
880 if (begun != k_ra8_ok) {
881 return begun;
882 }
883 transaction->iface = port->iface;
884 transaction->ctx = port->ctx;
885 transaction->state = workspace;
886 transaction->state_bytes = workspace_size;
887 transaction->active = true;
888 transaction->validated = false;
889 return k_ra8_ok;
890}
891
893 const uint8_t* source,
894 uint32_t length,
895 uint32_t* out_written)
896{
897 const ra8_err_t valid = internal_transaction(transaction);
898 if (valid != k_ra8_ok) {
899 return valid;
900 }
901 if (source == nullptr || out_written == nullptr) {
902 return k_ra8_err_null_ptr;
903 }
904 if (transaction->validated) {
906 }
907 *out_written = 0U;
908 const ra8_err_t result =
909 transaction->iface->write(transaction->ctx, transaction->state, source, length, out_written);
910 if (*out_written > length) {
911 *out_written = 0U;
913 }
914 return result;
915}
916
917ra8_err_t fw_fs_transaction_seek(fw_fs_transaction_t* transaction, uint64_t absolute_offset)
918{
919 const ra8_err_t valid = internal_transaction(transaction);
920 if (valid != k_ra8_ok) {
921 return valid;
922 }
923 if (transaction->validated) {
925 }
926 return transaction->iface->seek(transaction->ctx, transaction->state, absolute_offset);
927}
928
930 fw_fs_validate_fn_t validator,
931 void* validator_ctx)
932{
933 const ra8_err_t valid = internal_transaction(transaction);
934 if (valid != k_ra8_ok) {
935 return valid;
936 }
937 if (validator == nullptr) {
938 return k_ra8_err_null_ptr;
939 }
940 if (transaction->validated) {
942 }
943 const ra8_err_t checked =
944 transaction->iface->validate(transaction->ctx, transaction->state, validator, validator_ctx);
945 if (checked == k_ra8_ok) {
946 transaction->validated = true;
947 }
948 return checked;
949}
950
952{
953 const ra8_err_t valid = internal_transaction(transaction);
954 if (valid != k_ra8_ok) {
955 return valid;
956 }
957 if (out_published == nullptr) {
958 return k_ra8_err_null_ptr;
959 }
960 if (!transaction->validated) {
962 }
963 *out_published = false;
964 const ra8_err_t result =
965 transaction->iface->commit(transaction->ctx, transaction->state, out_published);
966 if ((result == k_ra8_ok) && !*out_published) {
968 }
969 if (*out_published) {
970 transaction->active = false;
971 transaction->validated = false;
972 }
973 return result;
974}
975
977{
978 const ra8_err_t valid = internal_transaction(transaction);
979 if (valid != k_ra8_ok) {
980 return valid;
981 }
982 const ra8_err_t result = transaction->iface->abort(transaction->ctx, transaction->state);
983 if (result == k_ra8_ok) {
984 transaction->active = false;
985 transaction->validated = false;
986 }
987 return result;
988}
static ra8_err_t internal_names(const fw_fs_namespace_t *names)
Validate a namespace facade before dispatch.
Definition fw_if_fs.c:112
ra8_err_t fw_fs_bind(fw_fs_t *out, const fw_fs_namespace_iface_t *namespace_iface, const fw_fs_stream_iface_t *stream_iface, const fw_fs_transaction_iface_t *transaction_iface, void *ctx, const fw_fs_caps_t *caps)
Bind segregated vtables and one context into a complete facade.
Definition fw_if_fs.c:427
fw_fs_ascii_byte_t
ASCII byte boundaries used by portable path validation.
Definition fw_if_fs.c:29
@ k_fw_fs_ascii_delete
DEL control byte.
Definition fw_if_fs.c:31
@ k_fw_fs_ascii_space
First non-control ASCII byte.
Definition fw_if_fs.c:30
static bool internal_power_of_two(uint32_t value)
Test whether an unsigned value is a non-zero power of two.
Definition fw_if_fs.c:49
ra8_err_t fw_fs_open(const fw_fs_stream_port_t *streams, const char *path, fw_fs_open_mode_t mode, fw_fs_file_t *file, void *workspace, uint32_t workspace_size)
Open a file into a caller-owned handle and backend workspace.
Definition fw_if_fs.c:648
static ra8_err_t internal_component(const char *path, uint16_t start, uint16_t length)
Validate one completed portable path component.
Definition fw_if_fs.c:203
ra8_err_t fw_fs_transaction_seek(fw_fs_transaction_t *transaction, uint64_t absolute_offset)
Seek the staging writer to an absolute byte offset for bounded backfill.
Definition fw_if_fs.c:917
ra8_err_t fw_fs_listdir(const fw_fs_namespace_t *names, const char *path, uint32_t max_entries, fw_fs_list_fn_t callback, void *callback_ctx, uint32_t *out_count, bool *out_complete)
Enumerate at most max_entries callback entries.
Definition fw_if_fs.c:509
ra8_err_t fw_fs_get_caps(const fw_fs_t *fs, fw_fs_caps_t *out)
Copy the immutable capability snapshot from a complete binding.
Definition fw_if_fs.c:468
ra8_err_t fw_fs_tell(fw_fs_file_t *file, uint64_t *out_offset)
Report the current absolute offset.
Definition fw_if_fs.c:745
ra8_err_t fw_fs_transaction_abort(fw_fs_transaction_t *transaction)
Close and remove an unpublished staging artifact.
Definition fw_if_fs.c:976
ra8_err_t fw_fs_write(fw_fs_file_t *file, const uint8_t *source, uint32_t length, uint32_t *out_written)
Attempt to write all bytes, reporting any accepted prefix.
Definition fw_if_fs.c:718
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_transaction_validate(fw_fs_transaction_t *transaction, fw_fs_validate_fn_t validator, void *validator_ctx)
Flush/reopen the stage and ask validator to inspect it read-only.
Definition fw_if_fs.c:929
ra8_err_t fw_fs_seek(fw_fs_file_t *file, uint64_t offset)
Seek to an absolute byte offset from the beginning.
Definition fw_if_fs.c:736
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
static ra8_err_t internal_fw_fs_transaction_preamble(const fw_fs_transaction_port_t *port, const fw_fs_transaction_t *transaction, fw_fs_transaction_policy_t policy)
Validate a transaction port, in-flight state, and policy before begin.
Definition fw_if_fs.c:822
static ra8_err_t internal_name_op(const fw_fs_namespace_t *names, const char *path, ra8_err_t(*operation)(void *, const char *))
Common one-path namespace dispatch.
Definition fw_if_fs.c:545
static ra8_err_t internal_fw_fs_scan_components(const fw_fs_caps_t *caps, const char *path)
Walk a validated non-root path byte-by-byte, checking every component.
Definition fw_if_fs.c:247
ra8_err_t fw_fs_read(fw_fs_file_t *file, uint8_t *dst, uint32_t cap, uint32_t *out_read)
Read up to cap bytes; zero bytes is EOF.
Definition fw_if_fs.c:699
ra8_err_t fw_fs_sync(fw_fs_file_t *file)
Request file synchronization or return k_ra8_err_not_supported.
Definition fw_if_fs.c:771
ra8_err_t fw_fs_transaction_begin(const fw_fs_transaction_port_t *port, const char *destination, fw_fs_transaction_policy_t policy, fw_fs_transaction_t *transaction, void *workspace, uint32_t workspace_size)
Create a hidden sibling staging file for one destination.
Definition fw_if_fs.c:850
ra8_err_t fw_fs_transaction_write(fw_fs_transaction_t *transaction, const uint8_t *source, uint32_t length, uint32_t *out_written)
Append bytes to the private staging artifact.
Definition fw_if_fs.c:892
ra8_err_t fw_fs_close(fw_fs_file_t *file)
Close and consume an open handle.
Definition fw_if_fs.c:783
ra8_err_t fw_fs_rename(const fw_fs_namespace_t *names, const char *old_path, const char *new_path, bool replace)
Rename inside one bound root/volume with optional atomic replacement.
Definition fw_if_fs.c:593
static ra8_err_t internal_file(const fw_fs_file_t *file)
Validate an open file facade before dispatch.
Definition fw_if_fs.c:140
static ra8_err_t internal_transaction(const fw_fs_transaction_t *transaction)
Validate an active transaction facade before dispatch.
Definition fw_if_fs.c:171
static ra8_err_t internal_fw_fs_caps_validate(const fw_fs_namespace_iface_t *namespace_iface, const fw_fs_stream_iface_t *stream_iface, const fw_fs_transaction_iface_t *transaction_iface, const fw_fs_caps_t *caps)
Validate capability flags and workspace alignments before a bind.
Definition fw_if_fs.c:390
static ra8_err_t internal_interfaces(const fw_fs_namespace_iface_t *names, const fw_fs_stream_iface_t *streams, const fw_fs_transaction_iface_t *transactions)
Validate all mandatory backend operations before binding them.
Definition fw_if_fs.c:330
ra8_err_t fw_fs_transaction_commit(fw_fs_transaction_t *transaction, bool *out_published)
Publish a validated stage.
Definition fw_if_fs.c:951
ra8_err_t fw_fs_path_validate(const fw_fs_caps_t *caps, const char *path)
Validate a canonical portable path against a binding's limits.
Definition fw_if_fs.c:286
ra8_err_t fw_fs_space(const fw_fs_namespace_t *names, fw_fs_space_t *out)
Report total/free/used bytes when space-query capability is present.
Definition fw_if_fs.c:623
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_file_size(fw_fs_file_t *file, uint64_t *out_size)
Report the open file's current length.
Definition fw_if_fs.c:758
ra8_err_t fw_fs_mkdir(const fw_fs_namespace_t *names, const char *path)
Create exactly one directory; parents must already exist.
Definition fw_if_fs.c:566
static ra8_err_t internal_workspace(void *workspace, uint32_t bytes, uint32_t need, uint8_t align)
Validate a workspace against a backend byte/alignment contract.
Definition fw_if_fs.c:79
Architecture-neutral filesystem namespace, stream, and transaction ports.
Backend-author interface for binding concrete filesystem ports.
Portable filesystem value types and caller-owned opaque handles.
@ k_fw_fs_node_none
No node exists at the path.
@ k_fw_fs_node_directory
Directory.
@ k_fw_fs_node_other
Backend-specific non-file node.
struct fw_fs_stream_iface fw_fs_stream_iface_t
struct fw_fs_transaction_iface fw_fs_transaction_iface_t
ra8_err_t(* fw_fs_validate_fn_t)(void *ctx, fw_fs_file_t *staged)
Validate staged bytes through a read-only generic file handle.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
struct fw_fs_namespace_iface fw_fs_namespace_iface_t
fw_fs_open_mode_t
Open intent for fw_fs_open.
@ k_fw_fs_open_create_new
Create only when leaf is absent.
ra8_err_t(* fw_fs_list_fn_t)(void *ctx, const fw_fs_dirent_t *entry, bool *out_continue)
Bounded list callback.
fw_fs_transaction_policy_t
Destination policy for a staged transaction.
@ k_fw_fs_txn_replace_atomic
Atomically replace an existing file.
@ k_fw_fs_cap_durable_file_sync
Successful file sync reaches durable media.
@ k_fw_fs_cap_stream
Regular-file stream operations are available.
@ k_fw_fs_cap_namespace
Metadata and namespace operations are available.
@ k_fw_fs_cap_space_query
Volume capacity and available bytes can be queried.
@ k_fw_fs_cap_create_exclusive
Open can atomically require that its leaf be absent.
@ k_fw_fs_cap_file_sync
An explicit file-sync operation is available.
@ k_fw_fs_cap_atomic_noreplace
Rename can atomically reject an existing destination.
@ k_fw_fs_cap_transactions
Staged publication operations are available.
@ k_fw_fs_cap_atomic_replace
Rename can atomically replace an existing destination.
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_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ 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_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ 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
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
Static properties and workspace requirements of one bound port.
uint16_t name_max_bytes
Component bytes excluding NUL.
uint8_t directory_workspace_align
Required directory-state alignment.
uint16_t path_max_bytes
Path bytes including NUL.
uint32_t file_workspace_bytes
State bytes required by open.
uint8_t transaction_workspace_align
Required transaction alignment.
uint16_t max_open_directories
Concurrent directory cursors.
uint32_t directory_workspace_bytes
State bytes required by dir open.
uint8_t file_workspace_align
Required file-state alignment.
uint32_t flags
OR of fw_fs_capability_t.
uint32_t transaction_workspace_bytes
State bytes required by begin.
Caller-owned open file; fields are private to the facade.
ra8_err_t(* mkdir)(void *ctx, const char *path)
Create one directory leaf.
ra8_err_t(* listdir)(void *ctx, const char *path, uint32_t max_entries, fw_fs_list_fn_t callback, void *callback_ctx, uint32_t *out_count, bool *out_complete)
Enumerate at most the requested number of directory entries.
ra8_err_t(* rmdir)(void *ctx, const char *path)
Remove one empty directory leaf.
ra8_err_t(* rename)(void *ctx, const char *old_path, const char *new_path, bool replace)
Rename one leaf within the backend volume.
ra8_err_t(* dir_open)(void *ctx, const char *path, void *directory_state, uint32_t state_bytes)
Open a directory cursor in caller-supplied workspace.
ra8_err_t(* stat)(void *ctx, const char *path, fw_fs_stat_t *out)
Query one path without following a symbolic-link leaf.
ra8_err_t(* dir_next)(void *ctx, void *directory_state, fw_fs_dirent_value_t *out, bool *out_entry)
Copy the next visible entry or report clean end-of-directory.
ra8_err_t(* space)(void *ctx, fw_fs_space_t *out)
Query the volume capacity and available byte count.
ra8_err_t(* dir_close)(void *ctx, void *directory_state)
Close a directory cursor and consume its backend state.
ra8_err_t(* unlink)(void *ctx, const char *path)
Remove one regular-file leaf.
Independently injectable path/namespace facade.
fw_fs_caps_t caps
Immutable capabilities.
void * ctx
Backend context.
const fw_fs_namespace_iface_t * iface
Bound private vtable.
Portable volume usage snapshot.
uint64_t free_bytes
Bytes available to new data.
uint64_t total_bytes
Addressable data bytes.
uint64_t used_bytes
Allocated bytes.
Result of a portable metadata query.
uint64_t size_bytes
File length; zero for a directory.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
ra8_err_t(* tell)(void *ctx, void *file_state, uint64_t *out_offset)
Report the current absolute stream position.
ra8_err_t(* close)(void *ctx, void *file_state)
Close the file and release its caller workspace.
ra8_err_t(* open)(void *ctx, const char *path, fw_fs_open_mode_t mode, void *file_state, uint32_t state_bytes)
Initialize caller workspace for one path and open mode.
ra8_err_t(* size)(void *ctx, void *file_state, uint64_t *out_size)
Report the current file length.
ra8_err_t(* read)(void *ctx, void *file_state, uint8_t *dst, uint32_t cap, uint32_t *out_read)
Read bytes at the current stream position.
ra8_err_t(* write)(void *ctx, void *file_state, const uint8_t *src, uint32_t len, uint32_t *out_written)
Write bytes at the current stream position.
ra8_err_t(* sync)(void *ctx, void *file_state)
Request backend file durability when supported.
ra8_err_t(* seek)(void *ctx, void *file_state, uint64_t absolute_offset)
Set the absolute stream position.
Independently injectable open-stream facade.
fw_fs_caps_t caps
Immutable capabilities.
void * ctx
Backend context.
const fw_fs_stream_iface_t * iface
Bound private vtable.
One complete composition-root filesystem binding.
fw_fs_stream_port_t streams
Byte-stream operations.
fw_fs_caps_t caps
Shared capabilities.
fw_fs_namespace_t names
Namespace operations.
fw_fs_transaction_port_t transactions
Staged publication.
ra8_err_t(* abort)(void *ctx, void *transaction_state)
Close and remove an unpublished private stage.
ra8_err_t(* validate)(void *ctx, void *transaction_state, fw_fs_validate_fn_t validator, void *validator_ctx)
Run a caller validator against the staged stream.
ra8_err_t(* begin)(void *ctx, void *transaction_state, uint32_t state_bytes, const char *destination, fw_fs_transaction_policy_t policy)
Create a private stage for the requested destination policy.
ra8_err_t(* write)(void *ctx, void *transaction_state, const uint8_t *src, uint32_t len, uint32_t *out_written)
Append or overwrite bytes in the private stage.
ra8_err_t(* seek)(void *ctx, void *transaction_state, uint64_t absolute_offset)
Set the absolute position within the staged stream.
ra8_err_t(* commit)(void *ctx, void *transaction_state, bool *out_published)
Publish the validated stage under the destination path.
Independently injectable staged-transaction facade.
fw_fs_caps_t caps
Immutable capabilities.
const fw_fs_transaction_iface_t * iface
Bound private vtable.
void * ctx
Backend context.
Caller-owned transaction; fields are private to the facade.
void * ctx
Adapter context.
const fw_fs_transaction_iface_t * iface
Bound vtable.
void * state
Caller workspace.
uint32_t state_bytes
Workspace extent.
bool validated
Stage was accepted.
bool active
Begin succeeded.