ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_check.c
Go to the documentation of this file.
1
41
42#include <stddef.h>
43#include <stdint.h>
44
45#include "ra8_attributes.h"
46#include "ra8_fs.h"
47#include "ra8_fs_check.h"
49#include "ra8_fs_fat_internal.h"
50
62typedef enum : uint32_t {
65 k_check_bad_fat32 = 0x0FFFFFF7U,
67
79typedef enum : uint32_t {
83
102
103/* =============================================================================
104 * Shared scaffolding (used by the exFAT half too)
105 * =============================================================================
106 */
107
108/* `priv_check_fault()`: see header for the documented contract. */
111 uint32_t cluster,
112 uint64_t lba,
113 uint32_t entry_off)
114{
115 if (ctx->rep->faults_total == 0U) {
116 ctx->rep->first_fault.kind = kind;
117 ctx->rep->first_fault.cluster = cluster;
118 ctx->rep->first_fault.lba = lba;
119 ctx->rep->first_fault.entry_off = entry_off;
120 }
121 ctx->rep->faults_total++;
122}
123
124/* `priv_check_in_range()`: see header for the documented contract. */
125bool priv_check_in_range(const ra8_fs_check_ctx_t* ctx, uint32_t cluster)
126{
127 if (cluster < (uint32_t)k_cluster_first_data) {
128 return false;
129 }
130 return (cluster - (uint32_t)k_cluster_first_data) < ctx->rep->clusters_total;
131}
132
133/* `priv_check_mark()`: see header for the documented contract. */
134bool priv_check_mark(ra8_fs_check_ctx_t* ctx, uint32_t cluster)
135{
136 const uint32_t idx = cluster - (uint32_t)k_cluster_first_data;
137 const uint32_t byte = idx >> (uint32_t)k_check_byte_shift;
138 const uint8_t mask = (uint8_t)(1U << (idx & (uint32_t)k_check_bit_mask));
139 if ((ctx->bitmap[byte] & mask) != 0U) {
140 return true;
141 }
142 ctx->bitmap[byte] = (uint8_t)(ctx->bitmap[byte] | mask);
143 return false;
144}
145
146/* `priv_check_visit()`: see header for the documented contract. */
148{
149 if (!priv_check_in_range(ctx, cluster)) {
150 if (oor_kind == k_ra8_fs_check_fault_bad_dir_entry) {
151 ctx->rep->entries_bad++;
152 }
153 priv_check_fault(ctx, oor_kind, cluster, 0U, 0U);
154 return true;
155 }
156 if (priv_check_mark(ctx, cluster)) {
157 ctx->rep->chains_crosslinked++;
159 return true;
160 }
161 return false;
162}
163
164/* `priv_check_zero_bitmap()`: see header for the documented contract. */
166{
167 const uint32_t nbytes =
168 (ctx->bitmap_bits + (uint32_t)k_check_bit_mask) >> (uint32_t)k_check_byte_shift;
169 for (uint32_t i = 0U; i < nbytes; i++) {
170 ctx->bitmap[i] = 0U;
171 }
172}
173
174/* =============================================================================
175 * Pass 1: classify every FAT entry
176 * =============================================================================
177 */
178
198{
199 if (m->type == k_ra8_fs_type_fat12) {
200 return (uint32_t)k_check_bad_fat12;
201 }
202 if (m->type == k_ra8_fs_type_fat16) {
203 return (uint32_t)k_check_bad_fat16;
204 }
205 return (uint32_t)k_check_bad_fat32;
206}
207
234static void internal_fat_classify_one(ra8_fs_check_ctx_t* ctx, uint32_t cluster, uint32_t value)
235{
236 if (value == (uint32_t)k_cluster_free) {
237 ctx->rep->clusters_free++;
238 return;
239 }
240 if (value == internal_fat_bad_marker(ctx->m)) {
241 ctx->rep->clusters_bad++;
242 return;
243 }
244 ctx->rep->clusters_used++;
245 if (priv_is_eoc(ctx->m, value) != 0U) {
246 return;
247 }
248 if (!priv_check_in_range(ctx, value)) {
250 }
251}
252
271{
272 const uint32_t last = (uint32_t)k_cluster_first_data + ctx->rep->clusters_total;
273 for (uint32_t c = (uint32_t)k_cluster_first_data; c < last; c++) {
274 uint32_t v = 0U;
275 const ra8_err_t err = priv_fat_get(ctx->m, c, &v);
276 if (err != k_ra8_ok) {
277 return err;
278 }
279 internal_fat_classify_one(ctx, c, v);
280 }
281 return k_ra8_ok;
282}
283
284/* =============================================================================
285 * Pass 2: walk the directory tree, marking referenced clusters
286 * =============================================================================
287 */
288
318{
319 uint32_t c = first;
320 for (uint32_t hop = 0U; hop < ctx->rep->clusters_total; hop++) {
322 return k_ra8_ok;
323 }
324 uint32_t v = 0U;
325 const ra8_err_t err = priv_fat_get(ctx->m, c, &v);
326 if (err != k_ra8_ok) {
327 return err;
328 }
329 if (priv_is_eoc(ctx->m, v) != 0U) {
330 return k_ra8_ok;
331 }
332 if (!priv_check_in_range(ctx, v)) {
334 return k_ra8_ok;
335 }
336 c = v;
337 }
339 return k_ra8_ok;
340}
341
364static void internal_fat_push(ra8_fs_check_ctx_t* ctx, fat_dir_stack_t* stack, uint32_t clus)
365{
366 if (stack->top >= (uint32_t)k_ra8_fs_check_max_dirs) {
367 if (stack->truncated == 0U) {
368 stack->truncated = 1U;
370 }
371 return;
372 }
373 stack->items[stack->top].is_root = 0U;
374 stack->items[stack->top].cluster = clus;
375 stack->top++;
376}
377
378/* ra8_fs_check_test_fat_push_overflow(): see header for the test-only contract. */
381 uint32_t cluster,
382 bool already_truncated)
383{
384 fat_dir_stack_t stack = {
385 .top = (uint32_t)k_ra8_fs_check_max_dirs,
386 .truncated = already_truncated ? 1U : 0U,
387 };
388 internal_fat_push(ctx, &stack, cluster);
389}
390
421 fat_dir_stack_t* stack,
422 const uint8_t* ent,
423 uint64_t lba,
424 uint32_t entry_off,
425 uint8_t* out_eod)
426{
427 *out_eod = 0U;
428 const uint8_t name0 = ent[k_dir_off_name];
429 const uint8_t attr = ent[k_dir_off_attr];
430 if (name0 == (uint8_t)k_dir_marker_free_perm) {
431 *out_eod = 1U;
432 return k_ra8_ok;
433 }
434 if (name0 == (uint8_t)k_dir_marker_free_used) {
435 return k_ra8_ok;
436 }
437 if (attr == (uint8_t)k_ra8_fs_attr_lfn) {
438 return k_ra8_ok;
439 }
440 if (name0 == (uint8_t)k_dir_marker_dot) {
441 return k_ra8_ok;
442 }
443 const uint8_t is_dir = ((attr & (uint8_t)k_ra8_fs_attr_directory) != 0U) ? 1U : 0U;
444 if ((is_dir == 0U) && ((attr & (uint8_t)k_ra8_fs_attr_volume_id) != 0U)) {
445 return k_ra8_ok; /* a volume-label entry owns no chain */
446 }
447 const uint32_t first = priv_entry_first_cluster(ent);
448 if ((first != 0U) && !priv_check_in_range(ctx, first)) {
449 ctx->rep->entries_bad++;
450 priv_check_fault(ctx, k_ra8_fs_check_fault_bad_dir_entry, first, lba, entry_off);
451 return k_ra8_ok;
452 }
453 if (is_dir != 0U) {
454 if (first != 0U) {
455 internal_fat_push(ctx, stack, first);
456 }
457 return k_ra8_ok;
458 }
459 ctx->rep->files_visited++;
460 if (first != 0U) {
461 return internal_fat_mark_chain(ctx, first);
462 }
463 return k_ra8_ok;
464}
465
488 fat_dir_stack_t* stack,
489 const uint8_t* buf,
490 uint64_t lba,
491 uint8_t* out_eod)
492{
493 for (uint32_t e = 0U; e < priv_dir_eps(ctx->m); e++) {
494 const uint32_t off = e * (uint32_t)k_ra8_fs_dir_entry_bytes;
495 uint8_t eod = 0U;
496 const ra8_err_t err = internal_fat_entry(ctx, stack, &buf[off], lba, off, &eod);
497 if (err != k_ra8_ok) {
498 return err;
499 }
500 if (eod != 0U) {
501 *out_eod = 1U;
502 return k_ra8_ok;
503 }
504 }
505 *out_eod = 0U;
506 return k_ra8_ok;
507}
508
528{
529 const uint32_t secs = (ctx->m->root_entries + (priv_dir_eps(ctx->m) - 1U)) / priv_dir_eps(ctx->m);
530 for (uint32_t s = 0U; s < secs; s++) {
531 const uint64_t lba = ctx->m->first_root_lba + s;
532 uint8_t* const buf = priv_sec_walk();
533 ra8_err_t err = priv_read_sector(ctx->m, lba, buf);
534 if (err != k_ra8_ok) {
535 return err;
536 }
537 uint8_t eod = 0U;
538 err = internal_fat_visit_sector(ctx, stack, buf, lba, &eod);
539 if (err != k_ra8_ok) {
540 return err;
541 }
542 if (eod != 0U) {
543 return k_ra8_ok;
544 }
545 }
546 return k_ra8_ok;
547}
548
576static ra8_err_t
578{
579 uint32_t c = first;
580 for (uint32_t hop = 0U; hop < ctx->rep->clusters_total; hop++) {
582 return k_ra8_ok;
583 }
584 const uint64_t base = priv_cluster_to_lba(ctx->m, c);
585 for (uint32_t s = 0U; s < ctx->m->sectors_per_cluster; s++) {
586 uint8_t* const buf = priv_sec_walk();
587 ra8_err_t err = priv_read_sector(ctx->m, base + s, buf);
588 if (err != k_ra8_ok) {
589 return err;
590 }
591 uint8_t eod = 0U;
592 err = internal_fat_visit_sector(ctx, stack, buf, base + s, &eod);
593 if (err != k_ra8_ok) {
594 return err;
595 }
596 if (eod != 0U) {
597 return k_ra8_ok;
598 }
599 }
600 uint32_t v = 0U;
601 const ra8_err_t err = priv_fat_get(ctx->m, c, &v);
602 if (err != k_ra8_ok) {
603 return err;
604 }
605 if (priv_is_eoc(ctx->m, v) != 0U) {
606 return k_ra8_ok;
607 }
608 c = v;
609 }
611 return k_ra8_ok;
612}
613
616{
617 fat_dir_stack_t stack = {};
618 return internal_fat_scan_cluster_dir(ctx, &stack, first);
619}
620
639{
640 fat_dir_stack_t stack = {};
641 stack.items[0].is_root = 1U;
642 stack.items[0].cluster = 0U;
643 stack.top = 1U;
644 const bool fat32 = (ctx->m->type == k_ra8_fs_type_fat32);
645 while (stack.top > 0U) {
646 stack.top--;
647 const dir_loc_t loc = stack.items[stack.top];
648 ctx->rep->dirs_visited++;
649 ra8_err_t err = k_ra8_ok;
650 if ((loc.is_root != 0U) && !fat32) {
651 err = internal_fat_scan_fixed_root(ctx, &stack);
652 } else {
653 const uint32_t first = (loc.is_root != 0U) ? ctx->m->root_cluster : loc.cluster;
654 err = internal_fat_scan_cluster_dir(ctx, &stack, first);
655 }
656 if (err != k_ra8_ok) {
657 return err;
658 }
659 }
660 return k_ra8_ok;
661}
662
663/* =============================================================================
664 * Pass 3: diff for lost clusters, and the FAT32 FSInfo free count
665 * =============================================================================
666 */
667
686{
687 const uint32_t marker = internal_fat_bad_marker(ctx->m);
688 const uint32_t last = (uint32_t)k_cluster_first_data + ctx->rep->clusters_total;
689 for (uint32_t c = (uint32_t)k_cluster_first_data; c < last; c++) {
690 uint32_t v = 0U;
691 const ra8_err_t err = priv_fat_get(ctx->m, c, &v);
692 if (err != k_ra8_ok) {
693 return err;
694 }
695 if ((v == (uint32_t)k_cluster_free) || (v == marker)) {
696 continue;
697 }
698 const uint32_t idx = c - (uint32_t)k_cluster_first_data;
699 const uint8_t mask = (uint8_t)(1U << (idx & (uint32_t)k_check_bit_mask));
700 if ((ctx->bitmap[idx >> (uint32_t)k_check_byte_shift] & mask) == 0U) {
701 ctx->rep->clusters_lost++;
703 }
704 }
705 return k_ra8_ok;
706}
707
729{
730 if (ctx->m->type != k_ra8_fs_type_fat32) {
731 return k_ra8_ok;
732 }
733 uint8_t* const boot = priv_sec_walk();
734 const ra8_err_t be = priv_read_sector(ctx->m, 0U, boot);
735 if (be != k_ra8_ok) {
736 return be;
737 }
738 const uint32_t lba = (uint32_t)priv_rd16(&boot[k_fmt_off_f32_fsinfo]);
739 if ((lba == 0U) || (lba >= ctx->m->reserved_sectors)) {
740 return k_ra8_ok;
741 }
742 uint8_t* const sec = priv_sec_walk();
743 const ra8_err_t se = priv_read_sector(ctx->m, lba, sec);
744 if (se != k_ra8_ok) {
745 return se;
746 }
747 if (priv_rd32(&sec[k_fmt_fsi_off_lead]) != (uint32_t)k_fmt_fsi_lead_sig) {
748 return k_ra8_ok;
749 }
750 if (priv_rd32(&sec[k_fmt_fsi_off_struct]) != (uint32_t)k_fmt_fsi_struct_sig) {
751 return k_ra8_ok;
752 }
753 if (priv_rd32(&sec[k_fmt_fsi_off_trail]) != (uint32_t)k_fmt_fsi_trail_sig) {
754 return k_ra8_ok;
755 }
756 const uint32_t stored = priv_rd32(&sec[k_fmt_fsi_off_free]);
757 if ((stored != (uint32_t)k_fs_free_unknown) && (stored != ctx->rep->clusters_free)) {
759 }
760 return k_ra8_ok;
761}
762
763/* `priv_check_fat()`: see header for the documented contract. */
765{
767 if (err != k_ra8_ok) {
768 return err;
769 }
770 if (ctx->bitmap != nullptr) {
772 err = internal_fat_tree(ctx);
773 if (err != k_ra8_ok) {
774 return err;
775 }
776 err = internal_fat_diff(ctx);
777 if (err != k_ra8_ok) {
778 return err;
779 }
780 }
781 return internal_fat_fsinfo(ctx);
782}
783
784/* =============================================================================
785 * Public entry point -- the lock bracket
786 * =============================================================================
787 */
788
815static bool internal_check_bitmap_ok(uint32_t total, const uint8_t* bitmap, uint32_t bitmap_bytes)
816{
817 if (bitmap == nullptr) {
818 return false;
819 }
820 return bitmap_bytes >= ((total + (uint32_t)k_check_bit_mask) >> (uint32_t)k_check_byte_shift);
821}
822
855RA8_EXPECTS_LOCK("ra8_fs_lock")
857 uint8_t* bitmap,
858 uint32_t bitmap_bytes,
859 ra8_fs_check_report_t* report)
860{
861 if ((handle == nullptr) || (report == nullptr)) {
862 return k_ra8_err_null_ptr;
863 }
864 if (handle->in_use == 0U) {
865 return k_ra8_err_invalid_state;
866 }
867 ra8_fs_check_report_t candidate = {};
868 candidate.type = handle->type;
869 candidate.clusters_total = handle->count_of_clusters;
870 const bool have_bitmap =
871 internal_check_bitmap_ok(handle->count_of_clusters, bitmap, bitmap_bytes);
872 candidate.referenced_scan = have_bitmap;
873 candidate.clusters_lost = have_bitmap ? 0U : (uint32_t)k_ra8_fs_check_unknown;
874 ra8_fs_check_ctx_t ctx = {.m = handle,
875 .rep = &candidate,
876 .bitmap = have_bitmap ? bitmap : nullptr,
877 .bitmap_bits = handle->count_of_clusters};
878 ra8_err_t err = k_ra8_ok;
879 if (handle->type == k_ra8_fs_type_exfat) {
880 err = priv_check_exfat(&ctx);
881 } else {
882 err = priv_check_fat(&ctx);
883 }
884 if (err != k_ra8_ok) {
885 return err;
886 }
887 *report = candidate;
888 return k_ra8_ok;
889}
890
891RA8_OWNS_RESOURCE("ra8_fs_lock")
893 uint8_t* bitmap,
894 uint32_t bitmap_bytes,
895 ra8_fs_check_report_t* report)
896{
898 const ra8_err_t err = internal_check_locked(handle, bitmap, bitmap_bytes, report);
900 return err;
901}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_OWNS_RESOURCE(kind)
RAII-style resource ownership contract.
#define RA8_TEST_HELPER
Mark a symbol as externally-linked but only callable from tests.
#define RA8_EXPECTS_LOCK(name)
The function expects the named thread/IRQ lock to be held on entry.
#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
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
Read-only on-device volume consistency check (fsck) for ra8_fs.
@ k_ra8_fs_check_unknown
A count the check could not determine (no bitmap supplied).
ra8_err_t ra8_fs_check(ra8_fs_mount_t *handle, uint8_t *bitmap, uint32_t bitmap_bytes, ra8_fs_check_report_t *report)
Scan a mounted volume for consistency, read-only, and report findings.
ra8_fs_check_fault_kind_t
The category of a single consistency finding.
@ k_ra8_fs_check_fault_bad_fat_value
FAT entry is out of range / reserved.
@ k_ra8_fs_check_fault_bad_dir_entry
A directory entry's first cluster is invalid.
@ k_ra8_fs_check_fault_bad_chain
A chain runs into free space or off-volume.
@ k_ra8_fs_check_fault_lost_cluster
A cluster is allocated but referenced by none.
@ k_ra8_fs_check_fault_scan_truncated
The directory worklist hit its static bound.
@ k_ra8_fs_check_fault_free_count_bad
FAT32 FSInfo free count disagrees.
@ k_ra8_fs_check_fault_crosslink
A cluster is reached by more than one chain.
uint32_t priv_rd32(const uint8_t *p)
Decode a little-endian uint32_t from a byte buffer.
Definition ra8_fs_fat.c:48
ra8_err_t priv_fat_get(const ra8_fs_mount_t *m, uint32_t cluster, uint32_t *out_value)
Fetch the FAT entry for cluster, returning the next-cluster value.
Definition ra8_fs_fat.c:187
uint16_t priv_rd16(const uint8_t *p)
Decode a little-endian uint16_t from a byte buffer.
Definition ra8_fs_fat.c:42
uint64_t priv_cluster_to_lba(const ra8_fs_mount_t *m, uint32_t cluster)
Convert a cluster number into its first data-region LBA.
Definition ra8_fs_fat.c:541
uint32_t priv_dir_eps(const ra8_fs_mount_t *m)
Directory entries per sector on one mounted volume.
Definition ra8_fs_fat.c:96
uint8_t priv_is_eoc(const ra8_fs_mount_t *m, uint32_t value)
Test whether value is an end-of-chain marker for this FAT type.
Definition ra8_fs_fat.c:511
ra8_err_t priv_read_sector(const ra8_fs_mount_t *m, uint64_t lba, uint8_t *buf)
Read a single sector into the module scratch buffer.
Definition ra8_fs_fat.c:134
@ k_fs_free_unknown
MS FAT spec sec 5: count not known.
uint8_t * priv_sec_walk(void)
The WALK-role sector buffer (directory scans and entry RMW).
void priv_check_zero_bitmap(ra8_fs_check_ctx_t *ctx)
Zero the scratch visited-bitmap over its valid bit range.
static ra8_err_t internal_check_locked(ra8_fs_mount_t *handle, uint8_t *bitmap, uint32_t bitmap_bytes, ra8_fs_check_report_t *report)
Consistency check – the guarded body of ra8_fs_check().
static ra8_err_t internal_fat_tree(ra8_fs_check_ctx_t *ctx)
Walk the whole directory tree from the root with an explicit worklist.
static ra8_err_t internal_fat_scan_fixed_root(ra8_fs_check_ctx_t *ctx, fat_dir_stack_t *stack)
Walk the FAT12/16 fixed root directory region.
void ra8_fs_check_test_fat_push_overflow(ra8_fs_check_ctx_t *ctx, uint32_t cluster, bool already_truncated)
Exercise the FAT directory-worklist overflow guard from a host test.
static ra8_err_t internal_fat_fsinfo(ra8_fs_check_ctx_t *ctx)
Compare a FAT32 volume's FSInfo free count against the classify pass.
static bool internal_check_bitmap_ok(uint32_t total, const uint8_t *bitmap, uint32_t bitmap_bytes)
Decide whether the caller's bitmap enables the reference passes.
static void internal_fat_classify_one(ra8_fs_check_ctx_t *ctx, uint32_t cluster, uint32_t value)
Classify one FAT entry value into the report's cluster tallies.
ra8_fs_check_bit_t
Bit-arithmetic constants for the caller-supplied visited bitmap.
@ k_check_byte_shift
log2(8): cluster index -> bitmap byte.
@ k_check_bit_mask
Cluster index -> bit within its byte.
bool priv_check_in_range(const ra8_fs_check_ctx_t *ctx, uint32_t cluster)
True when cluster is a real data cluster of the volume under check.
static ra8_err_t internal_fat_visit_sector(ra8_fs_check_ctx_t *ctx, fat_dir_stack_t *stack, const uint8_t *buf, uint64_t lba, uint8_t *out_eod)
Process the 16 directory entries of one loaded sector.
static ra8_err_t internal_fat_classify(ra8_fs_check_ctx_t *ctx)
Pass 1: read and classify every data cluster's FAT entry.
ra8_err_t priv_check_fat(ra8_fs_check_ctx_t *ctx)
Run the FAT12/16/32 consistency check into the context's report.
static void internal_fat_push(ra8_fs_check_ctx_t *ctx, fat_dir_stack_t *stack, uint32_t clus)
Push a subdirectory onto the walk stack, capping the depth.
static ra8_err_t internal_fat_diff(ra8_fs_check_ctx_t *ctx)
Pass 3: flag allocated clusters no directory chain reached.
bool priv_check_mark(ra8_fs_check_ctx_t *ctx, uint32_t cluster)
Mark cluster visited in the scratch bitmap; report a prior visit.
static ra8_err_t internal_fat_scan_cluster_dir(ra8_fs_check_ctx_t *ctx, fat_dir_stack_t *stack, uint32_t first)
Walk a cluster-chained directory (a FAT32 root or any subdirectory).
static uint32_t internal_fat_bad_marker(const ra8_fs_mount_t *m)
The FAT defective-cluster marker for the mounted variant.
static ra8_err_t internal_fat_mark_chain(ra8_fs_check_ctx_t *ctx, uint32_t first)
Mark a file's whole cluster chain, detecting cross-links and breaks.
static ra8_err_t internal_fat_entry(ra8_fs_check_ctx_t *ctx, fat_dir_stack_t *stack, const uint8_t *ent, uint64_t lba, uint32_t entry_off, uint8_t *out_eod)
Process one 32-byte FAT directory entry.
ra8_err_t ra8_fs_check_test_fat_scan_cluster_dir(ra8_fs_check_ctx_t *ctx, uint32_t first)
Exercise the FAT cluster-directory walker from a host unit test.
bool priv_check_visit(ra8_fs_check_ctx_t *ctx, uint32_t cluster, ra8_fs_check_fault_kind_t oor_kind)
Visit a cluster during a walk: mark it, and report a range or link fault.
void priv_check_fault(ra8_fs_check_ctx_t *ctx, ra8_fs_check_fault_kind_t kind, uint32_t cluster, uint64_t lba, uint32_t entry_off)
Record one consistency finding into the report.
ra8_fs_check_marker_t
The FAT defective-cluster marker for each FAT width.
@ k_check_bad_fat16
FAT16 defective-cluster marker.
@ k_check_bad_fat12
FAT12 defective-cluster marker.
@ k_check_bad_fat32
FAT32 defective-cluster marker.
Cross-TU state and helpers for the volume consistency check (fsck).
@ k_ra8_fs_check_max_dirs
Directory worklist depth cap.
uint32_t priv_entry_first_cluster(const uint8_t *entry)
Read the first cluster from a 32-byte directory entry.
Cross-TU shared declarations for the FAT/exFAT ra8_fs adapter.
void priv_lock_release(void)
Drop the library lock taken by priv_lock_acquire.
void priv_lock_acquire(void)
Take the library lock, if the caller installed one.
@ k_fmt_fsi_off_free
FSInfo FSI_Free_Count offset.
@ k_fmt_fsi_off_struct
FSInfo FSI_StrucSig offset.
@ k_fmt_off_f32_fsinfo
FAT32 BPB_FSInfo sector number.
@ k_fmt_fsi_off_lead
FSInfo FSI_LeadSig offset.
@ k_fmt_fsi_off_trail
FSInfo FSI_TrailSig offset.
@ k_dir_off_attr
MS FAT spec sec 6 "DIR_Attr".
@ k_dir_off_name
MS FAT spec sec 6 "DIR_Name" (11 bytes).
@ k_fmt_fsi_lead_sig
FSInfo lead signature "RRaA".
@ k_fmt_fsi_trail_sig
FSInfo trailing signature.
@ k_fmt_fsi_struct_sig
FSInfo struct signature "rrAa".
@ k_dir_marker_free_used
Slot was used, deleted.
@ k_dir_marker_free_perm
End-of-directory.
@ k_cluster_free
Cluster free.
@ k_cluster_first_data
Cluster numbers start at 2.
@ k_ra8_fs_type_fat12
count_of_clusters < 4085.
@ k_ra8_fs_type_fat32
count_of_clusters >= 65525.
@ k_ra8_fs_type_exfat
exFAT (read + streaming write + format).
@ k_ra8_fs_type_fat16
4085 <= count_of_clusters < 65525.
@ k_ra8_fs_attr_lfn
Long-file-name marker (we skip).
@ k_ra8_fs_attr_volume_id
MS FAT spec sec 6 "ATTR_VOLUME_ID".
@ k_ra8_fs_attr_directory
MS FAT spec sec 6 "ATTR_DIRECTORY".
@ k_ra8_fs_dir_entry_bytes
MS FAT spec sec 6 "Directory Entry".
Identifies the directory a lookup/scan should operate in.
uint8_t is_root
1 => the volume root; 0 => the subdirectory at cluster.
uint32_t cluster
First cluster of the subdirectory (ignored when root).
Bounded worklist of directories still to walk (NASA P10 Rule 1).
uint8_t truncated
1 once an overflow was dropped.
dir_loc_t items[k_ra8_fs_check_max_dirs]
The pending directory locations.
uint32_t top
Count of pending entries.
The state one ra8_fs_check run threads through its passes.
ra8_fs_check_report_t * rep
The report being filled.
uint32_t bitmap_bits
Valid bit count (== clusters_total).
ra8_fs_mount_t * m
The mounted volume under check.
uint8_t * bitmap
Scratch visited-cluster bitmap, or NULL.
ra8_fs_check_fault_kind_t kind
Category of the first finding.
uint32_t cluster
Cluster the finding concerns (0 if n/a).
uint64_t lba
Volume-relative sector of the entry (0 if n/a).
uint32_t entry_off
Byte offset of the entry in that sector (0 n/a).
The structured result of one ra8_fs_check run.
ra8_fs_check_fault_t first_fault
Kind + location of the first finding.
uint32_t clusters_used
Clusters that read as allocated.
uint32_t chains_crosslinked
Clusters reached by more than one chain.
uint32_t entries_bad
Bad dir entry / SetChecksum / NameHash findings.
uint32_t clusters_total
Data-region cluster count.
uint32_t clusters_lost
Allocated but referenced by nothing; k_ra8_fs_check_unknown when referenced_scan is false.
uint32_t faults_total
Every finding, across all categories (0 == clean).
uint32_t clusters_bad
FAT defective-marker clusters (informational).
uint32_t clusters_free
Clusters that read as free.
uint32_t files_visited
Files walked.
ra8_fs_type_t type
The volume variant that was checked.
uint32_t dirs_visited
Directories walked.
Cached parse of one mounted FAT volume.
uint32_t reserved_sectors
BPB BPB_RsvdSecCnt.
uint32_t root_cluster
BPB BPB_RootClus (FAT32 only).
ra8_fs_type_t type
FAT12 / FAT16 / FAT32.
uint32_t root_entries
BPB BPB_RootEntCnt (FAT12/16).
uint32_t sectors_per_cluster
BPB BPB_SecPerClus.
uint64_t first_root_lba
FAT12/16 fixed root-dir start.