33typedef enum : uint16_t {
58 if (c >=
'a' && c <=
'z') {
59 return (
char)(c -
'a' +
'A');
89 const char* path = *path_io;
91 while (*path !=
'\0' && *path !=
'.') {
95 if ((uint32_t)(
unsigned char)*path > (uint32_t)
k_lfn_del) {
100 if (base_len == 0U) {
135 uint32_t ext_len = 0U;
136 while (*path !=
'\0') {
140 if ((uint32_t)(
unsigned char)*path > (uint32_t)
k_lfn_del) {
152 if (path ==
nullptr || out11 ==
nullptr) {
155 while (*path ==
'/') {
205 if ((c >=
'A') && (c <=
'Z')) {
209 const uint32_t lowered = (uint32_t)c + ((uint32_t)
'a' - (uint32_t)
'A');
210 return (
char)lowered;
223 if (in11[i] ==
' ') {
284 if (set[i] ==
'\0') {
287 if ((uint32_t)(
unsigned char)set[i] == (uint32_t)u) {
329 static const char lfn_illegal[] =
"\"*/:<>?\\|";
331 const uint32_t v = (uint32_t)u;
376 static const char sfn_extra_illegal[] =
"+,;=[] ";
381 if (u == (uint16_t)(
unsigned char)
'.') {
418 for (uint32_t i = 0U; i < n; i++) {
419 if (leaf[i] == (uint16_t)(
unsigned char)
'.') {
457 const uint32_t base_len = dot;
462 const uint32_t ext_len = (n - dot) - 1U;
467 for (uint32_t i = 0U; i < n; i++) {
506 for (uint32_t i = from; i < to; i++) {
507 const uint32_t c = (uint32_t)leaf[i];
508 if ((c >= (uint32_t)
'A') && (c <= (uint32_t)
'Z')) {
510 }
else if ((c >= (uint32_t)
'a') && (c <= (uint32_t)
'z')) {
548 uint8_t base_seen = 0U;
549 uint8_t ext_seen = 0U;
573 uint32_t* out_nunits,
577 if ((leaf ==
nullptr) || (out_units ==
nullptr) || (out_nunits ==
nullptr)) {
580 if ((out83 ==
nullptr) || (out_ntres ==
nullptr)) {
596 for (uint32_t i = 0U; i < n; i++) {
688 for (uint32_t i = from; (i < to) && (got < cap); i++) {
689 const uint16_t u = leaf[i];
690 if ((u == (uint16_t)(
unsigned char)
' ') || (u == (uint16_t)(
unsigned char)
'.')) {
726 for (uint32_t i = 1U; (i + 1U) < n; i++) {
727 if (leaf[i] == (uint16_t)(
unsigned char)
'.') {
758 uint32_t digits = 1U;
777 if (base_len == 0U) {
778 base[0] = (uint8_t)
'_';
790 if (base_len < keep) {
793 for (uint32_t i = 0U; i < keep; i++) {
796 out11[keep] = (uint8_t)
'~';
797 uint32_t rest = tail;
798 for (uint32_t d = 0U; d < digits; d++) {
800 out11[(keep + digits) - d] = (uint8_t)((uint32_t)
'0' + digit);
840 const uint32_t root_dir_sectors =
913 const uint8_t* name83,
915 uint32_t* out_entry_off,
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
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.
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.
uint32_t priv_dir_eps(const ra8_fs_mount_t *m)
Directory entries per sector on one mounted volume.
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.
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.
uint32_t priv_bps(const ra8_fs_mount_t *m)
One mounted volume's sector size in bytes.
uint8_t priv_byte_equal(const uint8_t *a, const uint8_t *b, uint32_t n)
Compare two byte buffers for equality (length n).
void priv_byte_copy(uint8_t *dst, const uint8_t *src, uint32_t n)
Length-checked byte copy used in place of memcpy().
uint8_t * priv_sec_walk(void)
The WALK-role sector buffer (directory scans and entry RMW).
Cross-TU shared declarations for the FAT/exFAT ra8_fs adapter.
void priv_lfn_alias_basis(const uint16_t *leaf, uint32_t n, uint32_t tail, uint8_t *out11)
Derive the LONGNA~N.TXT 8.3 alias a long name is filed under.
static char internal_case_apply(char c, uint8_t lower)
Lower-case one ASCII character when a DIR_NTRes flag asks for it.
static uint8_t internal_name_is_83(const uint16_t *leaf, uint32_t n)
Can leaf be stored as a packed 8.3 name without losing anything?
void priv_dir_walk_init_loc(const ra8_fs_mount_t *m, const dir_loc_t *loc, dir_walk_t *w)
Initialise a directory walker for an arbitrary directory location.
static uint32_t internal_alias_digits(uint32_t tail)
Decimal digit count of tail (1..k_lfn_alias_tail_max).
ra8_fs_name_local_t
Small constants used only by this translation unit's name analysis.
@ k_case_seen_upper
An upper-case letter was seen.
@ k_alias_radix
The alias tail is written in decimal.
@ k_lfn_space
Lowest character code a long name may hold.
@ k_alias_digits_max
Digits in k_lfn_alias_tail_max.
@ k_case_seen_mixed
Both were: no NTRes flag can express it.
@ k_case_seen_lower
A lower-case letter was seen.
@ k_lfn_del
DEL: a control code, not a name character.
static uint8_t internal_alias_map_unit(uint16_t u)
Map one long-name character into the short-name character set.
uint8_t priv_path_to_83(const char *path, uint8_t *out11)
Convert a "/FILE.TXT"-style path to packed 11-byte 8.3 form.
static uint8_t internal_pack_base(const char **path_io, uint8_t *out11)
Pack the base portion of a path into out11[0..7].
static uint8_t internal_unit_is_83_legal(uint16_t u)
Is c usable verbatim inside a packed 8.3 short name?
static void internal_case_observe(const uint16_t *leaf, uint32_t from, uint32_t to, uint8_t *seen)
Fold one half of a name into "has upper" / "has lower" observations.
static void internal_dir_walk_init_root(const ra8_fs_mount_t *m, dir_walk_t *w)
Initialise a walker that iterates the volume root directory.
static uint8_t internal_unit_is_lfn_legal(uint16_t u)
Is u a code unit a VFAT long name is allowed to hold?
ra8_err_t priv_dir_find(const ra8_fs_mount_t *m, const dir_loc_t *loc, const uint8_t *name83, uint64_t *out_lba, uint32_t *out_entry_off, uint8_t out_entry[k_ra8_fs_dir_entry_bytes])
Find a directory entry by 8.3 name within a given directory.
static uint32_t internal_name_dot_index(const uint16_t *leaf, uint32_t n)
Index of the field-separating dot, or n when there is none.
static ra8_fs_name_kind_t internal_name_case_kind(const uint16_t *leaf, uint32_t n, uint8_t *out_ntres)
Decide the case shape of an 8.3-representable leaf.
static uint32_t internal_alias_collect(const uint16_t *leaf, uint32_t from, uint32_t to, uint32_t cap, uint8_t *out)
Collect up to cap alias characters from from up to to.
static uint32_t internal_alias_ext_dot(const uint16_t *leaf, uint32_t n)
Index of the dot that separates the alias extension, or n if none.
static uint8_t internal_unit_in_set(uint16_t u, const char *set)
Does u appear in the NUL-terminated ASCII set set?
ra8_err_t priv_dir_walk_next_sector(const ra8_fs_mount_t *m, dir_walk_t *w, uint8_t *out_eod)
Advance the walker to the next sector.
char priv_to_upper(char c)
Convert "FILE.TXT" (caller-supplied path) to packed 11-byte 8.3.
ra8_fs_name_kind_t priv_name_classify(const char *leaf, uint16_t *out_units, uint32_t *out_nunits, uint8_t *out83, uint8_t *out_ntres)
Decide whether a leaf needs one entry, one entry plus case flags, or a chain.
static uint8_t internal_pack_ext(const char *path, uint8_t *out11)
Pack the extension portion of a path into out11[8..10].
void priv_83_to_str(const uint8_t *in11, uint8_t ntres, char *out13)
Unpack on-disk 11-byte 8.3 name into NUL-terminated "NAME.EXT".
ra8_fs_name_kind_t
How a leaf component has to be stored in a FAT directory.
@ k_name_kind_invalid
Empty, over-long, or holds an illegal character.
@ k_name_kind_short
Fits 8.3; store one entry (+ NTRes case bits).
@ k_name_kind_long
Needs a VFAT chain and a generated ~N alias.
@ k_dir_off_attr
MS FAT spec sec 6 "DIR_Attr".
@ k_dir_name_field_len
8 + 3 raw chars (no dot).
@ k_dir_off_name
MS FAT spec sec 6 "DIR_Name" (11 bytes).
@ k_dir_marker_free_used
Slot was used, deleted.
@ k_dir_marker_kanji_e5
0xE5 in raw name, escaped.
@ k_dir_marker_free_perm
End-of-directory.
@ k_max_8_3_name
8.3 packed length without dot.
@ k_filename_ext_len
Filename ext length.
@ k_filename_base_len
Filename base length.
@ k_lfn_write_max
Longest name we WRITE (k_lfn_max_entries).
@ k_ntres_base_lower
Render DIR_Name[0..7] lower case.
@ k_ntres_ext_lower
Render DIR_Name[8..10] lower case.
@ k_ra8_fs_type_fat32
count_of_clusters >= 65525.
@ k_ra8_fs_attr_lfn
Long-file-name marker (we skip).
@ k_ra8_fs_dir_entry_bytes
MS FAT spec sec 6 "Directory Entry".
ra8_err_t priv_utf8_to_utf16(const char *in, uint16_t *out, uint32_t cap, uint32_t *out_units)
Convert a NUL-terminated UTF-8 name into UTF-16LE code units.
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).
Internal cursor used by the directory iterator.
uint32_t cluster
Current cluster (FAT32 root case).
uint32_t sector_in_cluster
0..SPC-1 inside cluster.
uint64_t cur_lba
Currently loaded LBA.
uint32_t entry_idx
Byte offset within the loaded sector.
uint32_t cluster_hops
FAT-chain follows so far (cycle guard).
uint32_t fixed_remaining
Sectors left in fixed region.
uint8_t is_root_fixed
1 = FAT12/16 fixed root dir region.
Cached parse of one mounted FAT volume.
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.
uint32_t count_of_clusters
Per MS spec: data_sectors / SPC.