ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_name.c File Reference

FAT 8.3 short-name pack/unpack and directory walking. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_fs.h"
#include "ra8_fs_fat_internal.h"
Include dependency graph for ra8_fs_fat_name.c:

Go to the source code of this file.

Enumerations

enum  ra8_fs_name_local_t : uint16_t {
  k_lfn_space = 0x20U ,
  k_lfn_del = 0x7FU ,
  k_case_seen_upper = 0x01U ,
  k_case_seen_lower = 0x02U ,
  k_case_seen_mixed = 0x03U ,
  k_alias_radix = 10U ,
  k_alias_digits_max = 6U
}
 Small constants used only by this translation unit's name analysis. More...

Functions

char priv_to_upper (char c)
 Convert "FILE.TXT" (caller-supplied path) to packed 11-byte 8.3.
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_pack_ext (const char *path, uint8_t *out11)
 Pack the extension portion of a path into out11[8..10].
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 char internal_case_apply (char c, uint8_t lower)
 Lower-case one ASCII character when a DIR_NTRes flag asks for it.
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".
static uint8_t internal_unit_in_set (uint16_t u, const char *set)
 Does u appear in the NUL-terminated ASCII set set?
static uint8_t internal_unit_is_lfn_legal (uint16_t u)
 Is u a code unit a VFAT long name is allowed to hold?
static uint8_t internal_unit_is_83_legal (uint16_t u)
 Is c usable verbatim inside a packed 8.3 short name?
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 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?
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 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.
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_alias_map_unit (uint16_t u)
 Map one long-name character into the short-name character set.
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 uint32_t internal_alias_digits (uint32_t tail)
 Decimal digit count of tail (1..k_lfn_alias_tail_max).
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 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.
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.
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.
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.

Detailed Description

FAT 8.3 short-name pack/unpack and directory walking.

8.3 short-name encode/decode, the directory-walk cursor, and the short-name directory lookup primitives for the ra8_fs FAT adapter.

Since
0.1.0

Definition in file ra8_fs_fat_name.c.

Enumeration Type Documentation

◆ ra8_fs_name_local_t

enum ra8_fs_name_local_t : uint16_t

Small constants used only by this translation unit's name analysis.

The case observations are a two-bit set rather than two booleans so that "mixed" is a value the code can name, instead of a conjunction the reader has to work out at each test.

Invariant
k_case_seen_mixed is exactly the two case bits together.
See also
priv_name_case_kind()
Since
0.1.0
Enumerator
k_lfn_space 

Lowest character code a long name may hold.

k_lfn_del 

DEL: a control code, not a name character.

k_case_seen_upper 

An upper-case letter was seen.

k_case_seen_lower 

A lower-case letter was seen.

k_case_seen_mixed 

Both were: no NTRes flag can express it.

k_alias_radix 

The alias tail is written in decimal.

k_alias_digits_max 

Digits in k_lfn_alias_tail_max.

Definition at line 33 of file ra8_fs_fat_name.c.

Function Documentation

◆ internal_alias_collect()

uint32_t internal_alias_collect ( const uint16_t * leaf,
uint32_t from,
uint32_t to,
uint32_t cap,
uint8_t * out )
static

Collect up to cap alias characters from from up to to.

Spaces and dots are dropped rather than mapped – the FAT specification removes them before translating – so My Report.v2 contributes MYREPORT and not MY_REPORT.

Parameters
[in]leafLeaf component's code units.
[in]fromFirst index to read.
[in]toOne past the last index to read.
[in]capMaximum characters to emit.
[out]outReceives up to cap mapped characters.
Returns
Number of characters written.
Return values
0..capHow many of out were filled.
Precondition
leaf and out are non-NULL; out holds cap bytes.
from is at most to.
Postcondition
Exactly the returned count of out bytes were written.
leaf is not modified.
Note
Pure function; trivially thread-safe against distinct out.
Since
0.1.0

Definition at line 685 of file ra8_fs_fat_name.c.

References internal_alias_map_unit().

Referenced by priv_lfn_alias_basis().

◆ internal_alias_digits()

uint32_t internal_alias_digits ( uint32_t tail)
static

Decimal digit count of tail (1..k_lfn_alias_tail_max).

Drives how much of the basis name survives: the numeric tail and its ~ must fit inside the eight-character base field, so ~1 leaves six characters and ~999999 leaves one.

Parameters
[in]tailAlias sequence number.
Returns
Number of decimal digits.
Return values
1..6Digit count for the supported range.
Precondition
tail is at least 1.
tail is at most k_lfn_alias_tail_max.
Postcondition
No state is modified.
The result is at most k_filename_base_len - 2.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 756 of file ra8_fs_fat_name.c.

References k_alias_digits_max, and k_alias_radix.

Referenced by priv_lfn_alias_basis().

◆ internal_alias_ext_dot()

uint32_t internal_alias_ext_dot ( const uint16_t * leaf,
uint32_t n )
static

Index of the dot that separates the alias extension, or n if none.

The LAST dot, and only when it has at least one character on each side: a leading dot (.profile) names no extension, and a trailing one (notes.) supplies no characters for it.

Parameters
[in]leafLeaf component's code units.
[in]nLength of leaf in code units.
Returns
Separator index, or n when the alias has no extension.
Return values
1..n-2The separating dot.
nNo usable extension.
Precondition
leaf is non-NULL and holds at least n units.
n is non-zero.
Postcondition
leaf is not modified.
The result is either n or a valid interior index.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 723 of file ra8_fs_fat_name.c.

Referenced by priv_lfn_alias_basis().

◆ internal_alias_map_unit()

uint8_t internal_alias_map_unit ( uint16_t u)
static

Map one long-name character into the short-name character set.

Upper-cases, then substitutes _ for anything an 8.3 name cannot hold. This is the FAT specification's "Basis-Name Generation Algorithm" step that makes the alias representable at all: without it a name like Design (final).txt would generate an alias with a space and parentheses in it, which no 8.3 reader accepts.

Parameters
[in]uCode unit from the caller's long name.
Returns
The character to place in the alias.
Return values
'_'u is not legal in an 8.3 name – which now includes every unit above ASCII, exactly as VFAT does for a character its OEM code page cannot represent.
otherThe upper-cased u.
Precondition
u passed ::priv_unit_is_lfn_legal().
The caller has already discarded spaces and dots.
Postcondition
No state is modified.
The result is always legal in a packed 8.3 name.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 646 of file ra8_fs_fat_name.c.

References internal_unit_is_83_legal(), k_lfn_del, and priv_to_upper().

Referenced by internal_alias_collect().

◆ internal_case_apply()

char internal_case_apply ( char c,
uint8_t lower )
static

Lower-case one ASCII character when a DIR_NTRes flag asks for it.

The FAT directory entry always stores the upper-case 8.3 form; the case a user typed survives in two bits of DIR_NTRes, one for the base and one for the extension. This applies the bit that governs the half of the name the character came from.

Parameters
[in]cCharacter straight out of the packed 11-byte name field.
[in]lowerNon-zero when this half of the name is flagged lower case.
Returns
The character to render.
Return values
'a'..'z'c was 'A'..'Z' and lower was set.
cOtherwise, unchanged.
Precondition
c is one byte of a packed 8.3 name field.
lower is 0 or non-zero; no other interpretation is placed on it.
Postcondition
No state outside the return value is touched.
Characters outside 'A'..'Z' are returned verbatim whatever lower is.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 200 of file ra8_fs_fat_name.c.

Referenced by priv_83_to_str().

◆ internal_case_observe()

void internal_case_observe ( const uint16_t * leaf,
uint32_t from,
uint32_t to,
uint8_t * seen )
static

Fold one half of a name into "has upper" / "has lower" observations.

Walks leaf from from up to (not including) to and ORs a bit into seen for each case class present. Digits and punctuation set neither, so "IMG_01" is upper-only and "01" is neither, which is what makes a case-flagged short name possible for both.

Parameters
[in]leafLeaf component's code units.
[in]fromFirst index to inspect.
[in]toOne past the last index to inspect.
[in,out]seenBit 0 set when an upper-case letter is seen, bit 1 when a lower-case one is.
Returns
Nothing.
Precondition
leaf is non-NULL and holds at least to units.
from is at most to and seen is non-NULL.
Postcondition
seen has only bits it already had, plus the ones observed here.
leaf is not modified.
Note
Pure accumulation; trivially thread-safe against distinct seen.
Since
0.1.0

Definition at line 504 of file ra8_fs_fat_name.c.

References k_case_seen_lower, and k_case_seen_upper.

Referenced by internal_name_case_kind().

◆ internal_dir_walk_init_root()

void internal_dir_walk_init_root ( const ra8_fs_mount_t * m,
dir_walk_t * w )
static

Initialise a walker that iterates the volume root directory.

FAT12/16 use a fixed root region; FAT32 uses a cluster chain rooted at m->root_cluster.

Parameters
[in]mMount providing geometry and FAT type.
[out]wWalker cursor to initialise.
Precondition
m and w are non-NULL.
m has been fully populated by priv_compute_geometry.
Postcondition
w points at the first sector of the root directory.
w->entry_idx is zero.
Note
Pure init – does not touch the backend.
Since
0.1.0

Definition at line 831 of file ra8_fs_fat_name.c.

References dir_walk_t::cluster, dir_walk_t::cluster_hops, dir_walk_t::cur_lba, dir_walk_t::entry_idx, ra8_fs_mount_t::first_root_lba, dir_walk_t::fixed_remaining, dir_walk_t::is_root_fixed, k_ra8_fs_dir_entry_bytes, k_ra8_fs_type_fat32, priv_bps(), priv_cluster_to_lba(), ra8_fs_mount_t::root_cluster, ra8_fs_mount_t::root_entries, dir_walk_t::sector_in_cluster, and ra8_fs_mount_t::type.

Referenced by priv_dir_walk_init_loc().

◆ internal_name_case_kind()

ra8_fs_name_kind_t internal_name_case_kind ( const uint16_t * leaf,
uint32_t n,
uint8_t * out_ntres )
static

Decide the case shape of an 8.3-representable leaf.

A half of the name that is all one case round-trips through a DIR_NTRes bit; a half that mixes cases does not, and the whole name then needs a long-name chain to survive. The two halves are judged independently, exactly as the two flag bits are.

Parameters
[in]leafLeaf component's units, already known to pack to 8.3.
[in]nLength of leaf in code units.
[out]out_ntresReceives the DIR_NTRes byte to store.
Returns
The on-disk shape required.
Return values
k_name_kind_shortOne entry plus out_ntres suffices.
k_name_kind_longA half mixes cases; a chain is required.
Precondition
leaf and out_ntres are non-NULL; n is leaf's length.
::priv_name_is_83() has already returned 1 for leaf.
Postcondition
out_ntres is written on both outcomes (0 on the long one).
leaf is not modified.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 545 of file ra8_fs_fat_name.c.

References internal_case_observe(), internal_name_dot_index(), k_case_seen_lower, k_case_seen_mixed, k_name_kind_long, k_name_kind_short, k_ntres_base_lower, and k_ntres_ext_lower.

Referenced by priv_name_classify().

◆ internal_name_dot_index()

uint32_t internal_name_dot_index ( const uint16_t * leaf,
uint32_t n )
static

Index of the field-separating dot, or n when there is none.

The LAST dot, because that is the one an extension would follow. A name holding more than one is not 8.3 anyway: the earlier dots then sit inside the base, where ::priv_unit_is_83_legal() refuses them, so the rejection needs no special case here.

Parameters
[in]leafLeaf component's code units (no slashes).
[in]nLength of leaf in code units.
Returns
Dot index, or n when there is none.
Return values
0..n-1The last dot's index.
nThere is no dot.
Precondition
leaf is non-NULL and holds at least n units.
n is at most k_lfn_write_max.
Postcondition
leaf is not modified.
The scan visits exactly n units.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 415 of file ra8_fs_fat_name.c.

Referenced by internal_name_case_kind(), and internal_name_is_83().

◆ internal_name_is_83()

uint8_t internal_name_is_83 ( const uint16_t * leaf,
uint32_t n )
static

Can leaf be stored as a packed 8.3 name without losing anything?

Requires a 1..8 character base, a 0 or 1..3 character extension, and every character legal in a short name. A second dot is caught by that last rule rather than by a count of its own: everything before the LAST dot is the base, so an earlier one is simply a character the base may not hold. A trailing dot ("REPORT.") fails the extension test and is therefore stored as a long name, which is the only way to read it back as it was written.

Parameters
[in]leafLeaf component's code units (no slashes).
[in]nLength of leaf in code units.
Returns
Representability flag.
Return values
1Uleaf packs to 8.3 losslessly, up to case.
0Uleaf needs a long-name chain.
Precondition
leaf is non-NULL and holds at least n units.
n is non-zero and at most k_lfn_write_max.
Postcondition
leaf is not modified.
The verdict is independent of the volume's contents.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 454 of file ra8_fs_fat_name.c.

References internal_name_dot_index(), internal_unit_is_83_legal(), k_filename_base_len, and k_filename_ext_len.

Referenced by priv_name_classify().

◆ internal_pack_base()

uint8_t internal_pack_base ( const char ** path_io,
uint8_t * out11 )
static

Pack the base portion of a path into out11[0..7].

Returns 0 on error.

Reads characters from *path_io up to a . or NUL, upper-cases them, and writes them into out11[0..7].

Parameters
[in,out]path_ioCursor into the input path; advanced on success.
[out]out1111-byte buffer; first 8 bytes are written.
Returns
1 on success, 0 on overflow or empty base.
Return values
1Base name packed.
0Base too long or zero-length.
Precondition
path_io, *path_io, and out11 are non-NULL.
out11 has been pre-padded with spaces by the caller.
Postcondition
On success, out11[0..7] holds the upper-cased base.
On success, *path_io points at the . or terminator.
Note
Helper used only by priv_path_to_83.
Since
0.1.0

Definition at line 87 of file ra8_fs_fat_name.c.

References k_filename_base_len, k_lfn_del, and priv_to_upper().

Referenced by priv_path_to_83().

◆ internal_pack_ext()

uint8_t internal_pack_ext ( const char * path,
uint8_t * out11 )
static

Pack the extension portion of a path into out11[8..10].

Returns 0 on error.

If *path is not ., returns success with no writes.

Parameters
[in]pathCursor at the . or terminator following the base.
[out]out1111-byte buffer; bytes 8..10 are written.
Returns
1 on success, 0 on overflow.
Return values
1Extension packed (or absent).
0Extension too long.
Precondition
path and out11 are non-NULL.
out11 has been pre-padded with spaces by the caller.
Postcondition
On success, out11[8..10] holds the upper-cased extension.
*path is not modified.
Note
Helper used only by priv_path_to_83.
Since
0.1.0

Definition at line 129 of file ra8_fs_fat_name.c.

References k_filename_base_len, k_filename_ext_len, k_lfn_del, and priv_to_upper().

Referenced by priv_path_to_83().

◆ internal_unit_in_set()

uint8_t internal_unit_in_set ( uint16_t u,
const char * set )
static

Does u appear in the NUL-terminated ASCII set set?

Linear scan, bounded by k_lfn_write_max so the loop has a static upper limit even though both call sites pass a string literal (NASA Power of 10 Rule 2). Every set here is ASCII, so a unit above that range simply never matches – no widening is needed.

Parameters
[in]uCode unit to look for.
[in]setNUL-terminated set of characters.
Returns
Membership flag.
Return values
1Uu is in set.
0Uu is not in set.
Precondition
set is non-NULL and NUL-terminated.
set is shorter than k_lfn_write_max characters.
Postcondition
Neither u nor set is modified.
The scan visits at most k_lfn_write_max characters.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 281 of file ra8_fs_fat_name.c.

References k_lfn_write_max.

Referenced by internal_unit_is_83_legal(), and internal_unit_is_lfn_legal().

◆ internal_unit_is_83_legal()

uint8_t internal_unit_is_83_legal ( uint16_t u)
static

Is c usable verbatim inside a packed 8.3 short name?

Stricter than ::priv_unit_is_lfn_legal() by the extra short-name exclusions, by the dot – which in an 8.3 name is a field separator rather than a character – and by the ASCII cut, which belongs here rather than there: a packed 8.3 field is an OEM-code-page byte and this adapter only writes ASCII into one, while a long name has the whole of UTF-16 available to it.

Parameters
[in]uCandidate code unit.
Returns
Legality flag.
Return values
1Uu may appear in the base or extension field.
0Uu may not; a name containing it needs a long-name chain.
Precondition
u already passed ::priv_unit_is_lfn_legal().
u is one code unit of a caller-supplied leaf component.
Postcondition
No state is modified.
The verdict depends only on u.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 370 of file ra8_fs_fat_name.c.

References internal_unit_in_set(), and k_lfn_del.

Referenced by internal_alias_map_unit(), and internal_name_is_83().

◆ internal_unit_is_lfn_legal()

uint8_t internal_unit_is_lfn_legal ( uint16_t u)
static

Is u a code unit a VFAT long name is allowed to hold?

Rejects the control range, DEL, and the explicit illegal set from the FAT specification. Everything above ASCII is ALLOWED: the slots store UTF-16 and this adapter now reads them back as such, so the old "at or above DEL" cut – which existed only because the reader substituted ? for those units – would refuse names the format and the reader both handle (#606).

Parameters
[in]uCandidate code unit.
Returns
Legality flag.
Return values
1Uu may appear in a long name.
0Uu may not; the whole leaf is rejected.
Precondition
u is one code unit of a caller-supplied leaf component.
The caller treats a 0 result as a fatal name error, not a fallback.
Postcondition
No state is modified.
The verdict depends only on u.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 322 of file ra8_fs_fat_name.c.

References internal_unit_in_set(), k_lfn_del, and k_lfn_space.

Referenced by priv_name_classify().

◆ priv_83_to_str()

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".

Trims trailing space pad in the base portion, restores the 0x05 -> 0xE5 kanji escape, and emits the dot + extension only when the extension is non-empty. The two DIR_NTRes case flags are applied as they are unpacked, so an entry written for data.log – stored upper-case with both flags set – reads back as data.log rather than DATA.LOG. Pass 0 for ntres to get the raw upper-case form.

Parameters
[in]in11Packed 11-byte name.
[in]ntresThe entry's DIR_NTRes byte (0 when it has none).
[out]out13Buffer of at least 13 bytes (8 + . + 3 + NUL).
Precondition
in11 and out13 are non-NULL.
out13 has at least 13 writable bytes.
Postcondition
out13 is NUL-terminated.
Trailing space padding has been stripped.
Note
Helper used only by ra8_fs_listdir.
Since
0.1.0

Definition at line 216 of file ra8_fs_fat_name.c.

References internal_case_apply(), k_dir_marker_free_used, k_dir_marker_kanji_e5, k_filename_base_len, k_filename_ext_len, k_ntres_base_lower, and k_ntres_ext_lower.

Referenced by internal_fat_dir_scan_sector(), and internal_listdir_visit_sector().

◆ priv_dir_find()

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.

Walks the directory loc (root or a subdirectory) and matches on the packed 11-byte name field. Skips LFN entries (attr 0x0F) and deleted slots.

Parameters
[in]mMount providing geometry and backend.
[in]locDirectory to search (root or a subdirectory).
[in]name83Packed 11-byte name.
[out]out_lbaSector containing the entry.
[out]out_entry_offByte offset within the sector.
[out]out_entry32 bytes of the entry payload.
Returns
Error code.
Return values
k_ra8_okEntry found; out parameters populated.
k_ra8_err_not_foundEnd-of-directory reached without a match.
k_ra8_err_*Backend error.
Precondition
All output pointers are non-NULL.
name83 is non-NULL and points to 11 bytes.
Postcondition
On success, out parameters identify the on-disk entry.
On failure, out parameters are unspecified.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 911 of file ra8_fs_fat_name.c.

References dir_walk_t::cur_lba, k_dir_marker_free_perm, k_dir_marker_free_used, k_dir_name_field_len, k_dir_off_attr, k_dir_off_name, k_ra8_err_not_found, k_ra8_fs_attr_lfn, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_byte_copy(), priv_byte_equal(), priv_dir_eps(), priv_dir_walk_init_loc(), priv_dir_walk_next_sector(), priv_read_sector(), and priv_sec_walk().

Referenced by internal_alias_unique(), internal_setattr_fat(), internal_stat_fat(), internal_utime_fat(), and priv_dir_lookup_any().

◆ priv_dir_walk_init_loc()

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.

Dispatches to priv_dir_walk_init_root for the root, or sets up a plain cluster-chain walk starting at loc->cluster for a subdirectory (the same machinery the FAT32 root uses, so priv_dir_walk_next_sector follows the chain unchanged).

Parameters
[in]mMount providing geometry and FAT type.
[in]locDirectory to walk (root or a subdirectory cluster).
[out]wWalker cursor to initialise.
Precondition
m, loc, and w are non-NULL.
For a subdirectory, loc->cluster >= k_cluster_first_data.
Postcondition
w points at the first sector of the chosen directory.
w->entry_idx is zero.
Note
Pure init – does not touch the backend.
Since
0.1.0

Definition at line 853 of file ra8_fs_fat_name.c.

References dir_loc_t::cluster, dir_walk_t::cluster, dir_walk_t::cluster_hops, dir_walk_t::cur_lba, dir_walk_t::entry_idx, dir_walk_t::fixed_remaining, internal_dir_walk_init_root(), dir_loc_t::is_root, dir_walk_t::is_root_fixed, priv_cluster_to_lba(), and dir_walk_t::sector_in_cluster.

Referenced by internal_dir_collect_chain(), internal_dir_grow(), internal_dir_is_empty(), internal_fat_find_free_root(), internal_fat_find_vol_id(), priv_dir_find(), priv_dir_find_free_run(), and priv_dir_find_long().

◆ priv_dir_walk_next_sector()

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.

For fixed-region roots simply increments the LBA. For cluster-chain roots advances within the cluster, then follows the FAT chain when the cluster is exhausted.

Parameters
[in]mMount providing geometry and backend.
[in,out]wWalker cursor to advance.
[out]out_eodSet to 1 if end-of-directory reached, else 0.
Returns
Error code.
Return values
k_ra8_okWalker advanced (or EOD signalled in *out_eod).
k_ra8_err_protocol_errorCluster-chain cycle detected (corrupt FAT).
k_ra8_err_*Backend error from a FAT read.
Precondition
m, w, and out_eod are non-NULL.
Walker has been initialized by priv_dir_walk_init_root.
Postcondition
On success w either points at a new sector or *out_eod is 1.
w->entry_idx is reset to 0 on a successful advance.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 869 of file ra8_fs_fat_name.c.

References dir_walk_t::cluster, dir_walk_t::cluster_hops, ra8_fs_mount_t::count_of_clusters, dir_walk_t::cur_lba, dir_walk_t::entry_idx, dir_walk_t::fixed_remaining, dir_walk_t::is_root_fixed, k_ra8_err_protocol_error, k_ra8_ok, priv_cluster_to_lba(), priv_fat_get(), priv_is_eoc(), dir_walk_t::sector_in_cluster, and ra8_fs_mount_t::sectors_per_cluster.

Referenced by internal_dir_collect_chain(), internal_dir_grow(), internal_dir_is_empty(), internal_fat_dir_advance_sector(), internal_fat_find_free_root(), internal_fat_find_vol_id(), internal_slot_advance(), priv_dir_find(), priv_dir_find_free_run(), and priv_dir_find_long().

◆ priv_lfn_alias_basis()

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.

The Microsoft FAT specification's basis-name generation: spaces and all but the last interior dot are dropped, the remainder is upper-cased with anything an 8.3 field cannot hold replaced by _, and the base is truncated to leave room for ~ plus the decimal tail. A leaf that contributes no base characters at all ("...") yields _, because an 8.3 name may not have an empty base.

Every unit above ASCII maps to _, which is what VFAT does with a character its OEM code page cannot express. Working from CODE UNITS rather than UTF-8 bytes is what makes that one underscore per character instead of one per byte.

Parameters
[in]leafLong name being filed, as UTF-16 code units.
[in]nNumber of units in leaf.
[in]tailSequence number, 1..k_lfn_alias_tail_max.
[out]out11Receives the packed, space-padded 11-byte alias.
Returns
Nothing.
Precondition
leaf and out11 are non-NULL; out11 holds k_max_8_3_name bytes.
tail is at least 1 and at most k_lfn_alias_tail_max.
Postcondition
Every byte of out11 is a legal 8.3 character or a space pad.
out11 always contains a ~ followed by tail in decimal.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 769 of file ra8_fs_fat_name.c.

References internal_alias_collect(), internal_alias_digits(), internal_alias_ext_dot(), k_alias_radix, k_filename_base_len, k_filename_ext_len, and k_max_8_3_name.

Referenced by internal_alias_unique().

◆ priv_name_classify()

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.

Decodes leaf from UTF-8 into the code units the on-disk chain carries, which is where a malformed encoding is refused – an over-long form, a raw surrogate, a truncated sequence – and then rejects anything a long name may not hold at all (an empty leaf, one longer than k_lfn_write_max CODE UNITS, a control character, or one of the FAT specification's illegal characters). Characters above ASCII are legal: the slots are UTF-16 and the reader returns them as such. What is left is an 8.3 name if it has a 1..8 character base, a 0 or 1..3 character extension, at most one dot, and no character an 8.3 field cannot hold – a space and a second dot are both enough to disqualify it however short it is. An 8.3 name whose base or extension is all one case round-trips through DIR_NTRes; one that MIXES cases in either half does not, and is reported as needing a chain.

Parameters
[in]leafLeaf component (no slashes), NUL-terminated UTF-8.
[out]out_unitsReceives leaf as UTF-16LE code units.
[out]out_nunitsReceives how many units that is.
[out]out83Receives the packed 11-byte name on a short verdict.
[out]out_ntresReceives the DIR_NTRes case flags (0 unless short).
Returns
The on-disk shape required.
Return values
k_name_kind_shortout83 and out_ntres are ready to write.
k_name_kind_longA chain plus a generated alias is required.
k_name_kind_invalidEmpty, over-long, illegal, or not valid UTF-8.
Precondition
Every pointer is non-NULL.
out_units addresses k_lfn_write_max writable units and out83 addresses k_max_8_3_name writable bytes.
Postcondition
out_ntres and out_nunits are written on every outcome.
leaf is not modified.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 571 of file ra8_fs_fat_name.c.

References internal_name_case_kind(), internal_name_is_83(), internal_unit_is_lfn_legal(), k_lfn_write_max, k_name_kind_invalid, k_name_kind_long, k_ra8_ok, priv_path_to_83(), and priv_utf8_to_utf16().

Referenced by priv_dir_reserve().

◆ priv_path_to_83()

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.

Strips leading /, pre-pads out11 with spaces, calls the base/extension packers, and rewrites a leading 0xE5 byte to the kanji escape 0x05.

Parameters
[in]pathNUL-terminated input path. Must be non-NULL.
[out]out1111-byte output buffer. Must be non-NULL.
Returns
1 on success, 0 on invalid name.
Return values
1Name packed into out11.
0NULL input or name violates 8.3 rules.
Precondition
path and out11 are non-NULL when valid.
out11 has at least k_max_8_3_name writable bytes.
Postcondition
On success, out11 holds the on-disk 8.3 representation.
On failure, out11 content is unspecified.
Note
Pure ASCII upcase; no locale support.
Since
0.1.0

Definition at line 150 of file ra8_fs_fat_name.c.

References internal_pack_base(), internal_pack_ext(), and k_max_8_3_name.

Referenced by internal_setattr_fat(), internal_stat_fat(), internal_utime_fat(), priv_dir_lookup_any(), and priv_name_classify().

◆ priv_to_upper()

char priv_to_upper ( char c)

Convert "FILE.TXT" (caller-supplied path) to packed 11-byte 8.3.

Upper-case ASCII conversion (returns input unchanged if not lowercase).

Result is space-padded as on-disk. Lower-case input is upper-cased. Returns 0 on bad name (>8 base, >3 ext, missing chars), 1 on success.

Definition at line 56 of file ra8_fs_fat_name.c.

Referenced by internal_alias_map_unit(), internal_pack_base(), and internal_pack_ext().