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

Cross-TU helper prototypes for the FAT/exFAT adapter (part B of 2). More...

Include dependency graph for ra8_fs_fat_protos_b_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ra8_err_t priv_exfat_write_dir_set (const ra8_fs_mount_t *m, uint32_t cluster, uint32_t idx, const uint8_t *set, uint32_t bytes)
 Write a pre-built entry set into consecutive directory entries.
ra8_err_t priv_exfat_write_upcase (const ra8_fs_backend_t *backend, uint64_t abs_lba, uint32_t bps, uint32_t *out_csum)
 Write the canonical exFAT up-case table and return its checksum.
void priv_fat_entry_apply_attr (uint8_t *entry, uint8_t set_mask, uint8_t clear_mask)
 Clear then set attribute bits in a 32-byte FAT directory entry.
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.
ra8_err_t priv_fat_set (const ra8_fs_mount_t *m, uint32_t cluster, uint32_t value)
 Write value into the FAT entry for cluster across every FAT copy.
ra8_err_t priv_fmt_choose_geometry (ra8_fs_fmt_geom_t *g, uint32_t spc_hint)
 Pick the cluster size that lands the FAT cluster count in the right band.
ra8_err_t priv_fmt_clear_region (const ra8_fs_backend_t *backend, uint64_t lba, uint64_t count, uint32_t bps)
 Clear count blocks at lba to zero – bulk-erase if the backend can.
ra8_err_t priv_fmt_emit_volume (const ra8_fs_backend_t *backend, const ra8_fs_fmt_geom_t *g, const char *label)
 Lay down the boot sector, FAT seeds, FSInfo, and the empty root.
uint32_t priv_fmt_reserved_for (ra8_fs_type_t type)
 Map a requested FAT type to its reserved-sector count.
void priv_fmt_label_field (uint8_t *dst, const char *label)
 Pad an ASCII volume label into an 11-byte BS_VolLab / label field.
bool priv_fmt_spc_valid (uint8_t spc)
 Validate a caller-pinned sectors-per-cluster value.
ra8_err_t priv_free_chain (const ra8_fs_mount_t *m, uint32_t start)
 Free an entire cluster chain starting at start.
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.
void priv_lfn_add (lfn_state_t *s, const uint8_t *ent)
 Fold one LFN directory entry's 13 UTF-16LE code units into the state.
const uint16_t * priv_lfn_units_for (const lfn_state_t *s, const uint8_t *name83, uint32_t *out_units)
 Code units of the chain that precedes name83, or NULL if none.
void priv_lfn_reset (lfn_state_t *s)
 Reset the LFN reassembly state so a fresh chain can start.
void priv_lock_acquire (void)
 Take the library lock, if the caller installed one.
void priv_lock_release (void)
 Drop the library lock taken by priv_lock_acquire.
ra8_err_t priv_open_locked (ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
 Open a file by path – the guarded body of ra8_fs_open().
ra8_err_t priv_parse_bpb_into_mount (ra8_fs_mount_t *m)
 Parse the BPB layout fields out of g_fs_scratch into m.
ra8_err_t priv_parse_volume (ra8_fs_mount_t *m)
 Parse the volume at the current base: exFAT first, then FAT BPB.
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.
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.
ra8_err_t priv_resolve_dir (const ra8_fs_mount_t *m, const char *path, dir_loc_t *out)
 Resolve a whole path to the directory it names.
ra8_err_t priv_resolve_parent (const ra8_fs_mount_t *m, const char *path, dir_loc_t *out_parent, const char **out_leaf)
 Resolve all-but-the-last path component to a parent directory.
uint32_t priv_strlen (const char *s)
 Length of a NUL-terminated string.
char priv_to_upper (char c)
 Upper-case ASCII conversion (returns input unchanged if not lowercase).
ra8_err_t priv_write_into_sector (const ra8_fs_mount_t *m, uint64_t lba, uint32_t off_in_sector, const uint8_t *src, uint32_t put)
 Merge put bytes into one sector at lba, at off_in_sector.
ra8_err_t priv_write_sector (const ra8_fs_mount_t *m, uint64_t lba, const uint8_t *buf)
 Write a single sector from a caller-provided buffer.

Detailed Description

Cross-TU helper prototypes for the FAT/exFAT adapter (part B of 2).

The second half of the FAT/exFAT adapter's cross-TU helper prototypes. Each helper is defined static-free in exactly one FAT/exFAT translation unit and called from at least one other. This part covers the alphabetical run from priv_exfat_write_dir_set() through priv_write_sector(); the earlier helpers live in ra8_fs_fat_protos_a_internal.h. Both are aggregated by the ra8_fs_fat_internal.h umbrella, which every ra8_fs_fat*.c file includes.

This header aggregates each cross-TU helper's full Doxygen contract.

Since
0.1.0

Definition in file ra8_fs_fat_protos_b_internal.h.

Function Documentation

◆ priv_exfat_write_dir_set()

ra8_err_t priv_exfat_write_dir_set ( const ra8_fs_mount_t * m,
uint32_t cluster,
uint32_t idx,
const uint8_t * set,
uint32_t bytes )

Write a pre-built entry set into consecutive directory entries.

Read-modify-writes each entry slot so neighbouring entries are preserved.

Parameters
[in]mMounted exFAT volume.
[in]clusterDirectory cluster holding the run.
[in]idxEntry index of the run start.
[in]setBuilt entry-set bytes.
[in]bytesTotal size of the set.
Returns
Error code.
Return values
k_ra8_okEntries written.
k_ra8_err_*Backend read/write failure.
Precondition
m and set are non-NULL; the run fits in the cluster.
bytes is a multiple of the entry size.
Postcondition
The directory holds the new entry set.
Read-modify-write preserves neighbouring entries.
Note
Writes one entry (sector RMW) at a time.
Since
0.1.0

Definition at line 517 of file ra8_fs_fat_exfat_write.c.

References k_exfat_entry_bytes, k_ra8_ok, priv_bps(), priv_byte_copy(), priv_cluster_to_lba(), priv_read_sector(), priv_sec_io(), and priv_write_sector().

Referenced by internal_exfat_dir_relen(), internal_exfat_place_rename(), internal_exfat_put_entry(), internal_setattr_exfat(), internal_utime_exfat(), priv_exfat_flush_set(), priv_exfat_link(), priv_exfat_mkdir(), and priv_exfat_set_label().

◆ priv_exfat_write_upcase()

ra8_err_t priv_exfat_write_upcase ( const ra8_fs_backend_t * backend,
uint64_t abs_lba,
uint32_t bps,
uint32_t * out_csum )

Write the canonical exFAT up-case table and return its checksum.

Streams the 5836-byte Microsoft up-case table (k_exfat_fmt_upc_std_bytes, embedded in ra8_fs_fat_exfat_upcase.c) to the device starting at absolute LBA abs_lba, one bps-byte sector at a time, zero-padding the final partial sector. The rotate-add checksum (priv_exfat_csum32) is accumulated over exactly the table bytes – not the pad – so it equals the well-known 0xE619D30D and can be stamped into the root Up-case directory entry.

Parameters
[in]backendBlock-device backend with a non-NULL write_block.
[in]abs_lbaAbsolute (partition-adjusted) first LBA of the up-case table's cluster run.
[in]bpsDevice sector size in bytes (a power of two, 512..4096).
[out]out_csumReceives the table checksum on success.
Returns
Error code from the backend.
Return values
k_ra8_okTable written; out_csum populated.
k_ra8_err_*Backend write_block failure; out_csum unspecified.
Precondition
backend and backend->write_block are non-NULL.
out_csum is non-NULL; abs_lba's cluster run holds the table span.
Postcondition
On k_ra8_ok the up-case cluster run holds the canonical table.
On k_ra8_ok out_csum holds the checksum for the root Up-case entry.
Note
Not thread-safe; uses the module scratch buffer.
Since
0.1.0

Definition at line 477 of file ra8_fs_fat_exfat_upcase.c.

References ra8_fs_backend_t::ctx, g_fs_scratch, k_exfat_fmt_upc_std_bytes, k_ra8_ok, priv_byte_copy(), priv_exfat_csum32(), s_exfat_upcase, and ra8_fs_backend_t::write_block.

Referenced by priv_exfat_format().

◆ priv_fat_entry_apply_attr()

void priv_fat_entry_apply_attr ( uint8_t * entry,
uint8_t set_mask,
uint8_t clear_mask )

Clear then set attribute bits in a 32-byte FAT directory entry.

Rewrites the entry's DIR_Attr byte as (attr & ~clear_mask) | set_mask: bits in clear_mask are cleared, bits in set_mask are set, every other bit is left as it was. The two masks are applied in that order, so a bit named in both ends up set. This is the one place the attribute byte is patched – the archive-on-write convention (priv_truncate_existing, priv_write_locked) and ra8_fs_set_attr() both route through it, so the read-modify-write cast lives once.

Parameters
[in,out]entry32-byte directory entry to update.
[in]set_maskAttribute bits to set.
[in]clear_maskAttribute bits to clear.
Precondition
entry is non-NULL and points to 32 writable bytes.
Caller has staged the entry in a sector buffer to be written back.
Postcondition
entry[DIR_Attr] == (old & ~clear_mask) | set_mask.
No other byte of the entry is modified.
Note
Trivially thread-safe; not reentrant against the same buffer.
Since
0.1.0

Definition at line 44 of file ra8_fs_fat_file.c.

References k_dir_off_attr.

Referenced by internal_setattr_fat(), and internal_truncate_existing().

◆ priv_fat_get()

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.

On FAT12 a single entry can straddle two sectors, which is why we read one sector at a time and re-read on overflow.

Parameters
[in]mMount providing the FAT type and geometry.
[in]clusterCluster whose FAT entry to read.
[out]out_valueReceives the next-cluster value.
Returns
Error code.
Return values
k_ra8_okEntry read successfully.
k_ra8_err_*Backend error from a sector read.
Precondition
m and out_value are non-NULL.
cluster is within the addressable cluster range.
Postcondition
On success, *out_value holds the FAT entry.
Stack buffers used; module scratch untouched.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 187 of file ra8_fs_fat.c.

References ra8_fs_mount_t::first_fat_lba, internal_fat_entry_byte_offset(), k_cluster_mask_fat32, k_fat12_value_mask, k_ra8_fs_type_exfat, k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, k_ra8_ok, k_shift_byte, k_shift_nibble, priv_bps(), priv_fat_sector_read(), priv_rd16(), priv_rd32(), priv_sec_fat(), priv_sec_fat2(), and ra8_fs_mount_t::type.

Referenced by internal_exchk_mark_fatchain(), internal_exfat_cluster_at(), internal_exfat_dir_survey(), internal_exfat_shrink_chain_tail(), internal_exfat_survey_alloc(), internal_fat_classify(), internal_fat_diff(), internal_fat_mark_chain(), internal_fat_scan_cluster_dir(), internal_fat_trunc_shrink(), internal_skip_clusters(), internal_space_fat_free(), internal_trunc_walk(), internal_walk_grow(), priv_alloc_cluster(), priv_dir_walk_next_sector(), priv_exfat_free_clusters(), priv_exfat_step_cluster(), and priv_free_chain().

◆ priv_fat_set()

ra8_err_t priv_fat_set ( const ra8_fs_mount_t * m,
uint32_t cluster,
uint32_t value )

Write value into the FAT entry for cluster across every FAT copy.

Walks m->num_fats FAT copies and dispatches to the appropriate FAT12/16/32 set helper.

Parameters
[in]mMount providing geometry, backend, and FAT type.
[in]clusterCluster whose FAT entry to update.
[in]valueValue to write.
Returns
Error code.
Return values
k_ra8_okAll FAT copies updated.
k_ra8_err_*Backend or set-helper failure.
Precondition
m is non-NULL with a valid backend and num_fats >= 1.
cluster is within the addressable cluster range.
Postcondition
On success, every FAT copy reflects the new value.
On partial failure, FAT copies may be inconsistent.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 486 of file ra8_fs_fat.c.

References ra8_fs_mount_t::fat_size_sectors, ra8_fs_mount_t::first_fat_lba, internal_exfat_fat_set_one(), internal_fat12_set_one(), internal_fat16_set_one(), internal_fat32_set_one(), internal_fat_entry_byte_offset(), k_ra8_fs_type_exfat, k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, k_ra8_ok, ra8_fs_mount_t::num_fats, priv_bps(), and ra8_fs_mount_t::type.

Referenced by internal_dir_grow(), internal_exfat_dir_link(), internal_exfat_link_cluster(), internal_exfat_materialize_run(), internal_exfat_shrink_chain_tail(), internal_fat_trunc_extend(), internal_fat_trunc_shrink(), internal_walk_grow(), priv_alloc_eoc_cluster(), and priv_free_chain().

◆ priv_fmt_choose_geometry()

ra8_err_t priv_fmt_choose_geometry ( ra8_fs_fmt_geom_t * g,
uint32_t spc_hint )

Pick the cluster size that lands the FAT cluster count in the right band.

Sweeps spc upward through powers of two (1, 2, 4, ... up to k_fmt_spc_max). For FAT32 the count shrinks with larger clusters, so the first spc whose count is in-band (or below k_fmt_fat32_clus_cap) wins. For FAT12/16 a too-large count fails the lower clusters and a too-small count fails the larger ones, so the sweep accepts the first in-band hit. When spc_hint is zero the starting point for FAT32 comes from priv_fmt_fat32_default_spc(); for FAT12/16 it starts at 1. On success the geometry's sectors_per_cluster, fat_size_sectors, and count_of_clusters are populated.

Parameters
[in,out]gGeometry with type, total_sectors, reserved_sectors, root_entries, and root_sectors pre-filled.
[in]spc_hintCaller-pinned cluster size (0 = auto-sweep).
Returns
Error code.
Return values
k_ra8_okGeometry chosen; output fields stored in g.
k_ra8_err_invalid_sizeNo cluster size yields a count in g->type's band.
Precondition
g is non-NULL with the input fields (type, total_sectors, reserved_sectors, root_entries, root_sectors) already set.
spc_hint is 0 or a power of two in the range [1, k_fmt_spc_max].
Postcondition
On k_ra8_ok, g->sectors_per_cluster, g->fat_size_sectors, and g->count_of_clusters are consistent and in-band for g->type.
On k_ra8_err_invalid_size, g is left partially written and must be discarded.
Note
Bounded loop (NASA Rule 2): at most k_fmt_spc_max+1 iterations.
Since
0.1.0

Definition at line 209 of file ra8_fs_fat_fmt.c.

References ra8_fs_fmt_geom_t::bytes_per_sector, ra8_fs_fmt_geom_t::count_of_clusters, ra8_fs_fmt_geom_t::fat_size_sectors, internal_fmt_clusters_for(), internal_fmt_count_in_band(), internal_fmt_fat32_default_spc(), k_fmt_spc_max, k_ra8_err_invalid_size, k_ra8_fs_type_fat32, k_ra8_ok, ra8_fs_fmt_geom_t::sectors_per_cluster, ra8_fs_fmt_geom_t::total_sectors, and ra8_fs_fmt_geom_t::type.

Referenced by internal_format_locked().

◆ priv_fmt_clear_region()

ra8_err_t priv_fmt_clear_region ( const ra8_fs_backend_t * backend,
uint64_t lba,
uint64_t count,
uint32_t bps )

Clear count blocks at lba to zero – bulk-erase if the backend can.

Tries backend->erase_blocks first: on flash media (SD) that erases a region internally in one operation, this avoids streaming tens of MB of zeros (~30 MB of FAT on a 128 GB FAT32 card). The erase path is only taken when the backend guarantees a zero read-back – it signals inability with k_ra8_err_not_supported, on which (or when no erase hook is bound) this falls back to priv_fmt_zero_run. Any other backend error aborts.

Parameters
[in]backendBlock-device backend.
[in]lbaFirst block to clear.
[in]countNumber of blocks to clear.
[in]bpsDevice sector size in bytes (sizes each zero write).
Returns
Error code.
Return values
k_ra8_okThe range now reads back as all-zero bytes.
k_ra8_err_*A backend write/erase failure (other than not_supported).
Precondition
backend is non-NULL with a non-NULL write_block.
count blocks starting at lba lie within the device.
bps is the device's real sector size (used to size each write).
Postcondition
On success [lba, lba+count) reads back as zero.
No metadata is written; caller seeds the FAT afterwards.
Note
Not thread-safe; part of single-threaded format.
MC/DC:
Decision: if ((erase_blocks != nullptr) && (erase_blocks(...) == k_ra8_ok)) (short-circuit AND). Erase is a pure optimization: any non-OK result (no hook, not_supported, a card that erases to ones, or a hardware error) falls through to the proven zero-write – so erase failure is never fatal. Vectors:
  • erase_blocks == NULL -> C1 false (short-circuit) -> zero-run.
  • erase_blocks returns k_ra8_ok -> C1 true, C2 true -> return ok (no zeroing).
  • erase_blocks returns non-ok -> C1 true, C2 false -> zero-run. (NULL,ok) prove C1 independence; (ok,non-ok) prove C2 independence.
Since
0.1.0

Definition at line 473 of file ra8_fs_fat_fmt.c.

References ra8_fs_backend_t::ctx, ra8_fs_backend_t::erase_blocks, internal_fmt_zero_run(), and k_ra8_ok.

Referenced by internal_exfat_write_bitmap(), internal_exfat_write_fat(), internal_exfat_write_root(), and priv_fmt_emit_volume().

◆ priv_fmt_emit_volume()

ra8_err_t priv_fmt_emit_volume ( const ra8_fs_backend_t * backend,
const ra8_fs_fmt_geom_t * g,
const char * label )

Lay down the boot sector, FAT seeds, FSInfo, and the empty root.

The write phase of ra8_fs_format(), split out to keep the public entry under the NASA Rule 4 length budget. Clears the FAT + root region (bulk-erase or zero-write) first, then builds the type-specific BPB and persists it at LBA 0, seeds the FATs, and writes any FAT32 FSInfo + backup. The root region is left zero by the initial clear.

Parameters
[in]backendBlock-device backend.
[in]gResolved geometry.
[in]labelOptional volume label.
Returns
Error code.
Return values
k_ra8_okVolume image fully written.
k_ra8_err_*Backend write failure mid-format.
Precondition
backend, g are non-NULL with geometry resolved.
g->type is FAT12/FAT16/FAT32.
Postcondition
On success the device holds a mountable g->type volume.
On failure the device may be partially written.
Note
Not thread-safe; serialise with mounts on the same backend.
Since
0.1.0

Definition at line 602 of file ra8_fs_fat_fmt.c.

References ra8_fs_fmt_geom_t::bytes_per_sector, ra8_fs_backend_t::ctx, ra8_fs_fmt_geom_t::fat_size_sectors, internal_fmt_build_bpb_f16(), internal_fmt_build_bpb_f32(), internal_fmt_seed_fats(), internal_fmt_write_fsinfo(), k_fmt_num_fats, k_ra8_fs_type_fat32, k_ra8_ok, priv_byte_fill(), priv_fmt_clear_region(), priv_sec_walk(), ra8_fs_fmt_geom_t::reserved_sectors, ra8_fs_fmt_geom_t::root_sectors, ra8_fs_fmt_geom_t::sectors_per_cluster, ra8_fs_fmt_geom_t::type, and ra8_fs_backend_t::write_block.

Referenced by internal_format_locked().

◆ priv_fmt_label_field()

void priv_fmt_label_field ( uint8_t * dst,
const char * label )

Pad an ASCII volume label into an 11-byte BS_VolLab / label field.

Copies label up to its NUL (or 11 characters) then space-fills the remainder, matching the BS_VolLab convention. A NULL or empty label resolves to the FAT specification's unlabelled sentinel "NO NAME " – never zeros and never a bare run of spaces, both of which fsck.fat treats as a corrupt label and strips (#634). Shared by the formatter (ra8_fs_format()) and the runtime label writer (ra8_fs_set_label()), so both lay the field identically.

Parameters
[out]dstDestination 11-byte label field.
[in]labelSource label, or NULL / "" for the unlabelled sentinel.
Returns
Nothing.
Precondition
dst is non-NULL and addresses at least k_fmt_label_len bytes.
label is NUL-terminated when non-NULL.
Postcondition
dst holds the padded 11-byte label (or the "NO NAME " sentinel).
No byte past offset 10 of dst is touched.
Note
Bounded loop (NASA Rule 2): exactly k_fmt_label_len iterations.
Since
0.1.0

Definition at line 272 of file ra8_fs_fat_fmt.c.

References k_fmt_label_len.

Referenced by internal_fat_boot_set_label(), internal_fat_put_vol_id(), internal_fmt_build_bpb_f16(), and internal_fmt_build_bpb_f32().

◆ priv_fmt_reserved_for()

uint32_t priv_fmt_reserved_for ( ra8_fs_type_t type)

Map a requested FAT type to its reserved-sector count.

FAT32 reserves a 32-sector region (boot + FSInfo + backup); FAT12/16 reserve only the single boot sector.

Parameters
[in]typeRequested FAT variant.
Returns
Reserved-sector count for type.
Return values
k_fmt_resv_f32type is FAT32.
k_fmt_resv_f16type is FAT12 or FAT16.
Precondition
type is one of FAT12/FAT16/FAT32.
Caller has rejected exFAT/unknown beforehand.
Postcondition
No state modified.
Result is purely a function of type.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 27 of file ra8_fs_fat_fmt.c.

References k_fmt_resv_f16, k_fmt_resv_f32, and k_ra8_fs_type_fat32.

Referenced by internal_format_locked().

◆ priv_fmt_spc_valid()

bool priv_fmt_spc_valid ( uint8_t spc)

Validate a caller-pinned sectors-per-cluster value.

A zero value defers to the auto-sweep. A non-zero value must be a power of two in the closed range 1..k_fmt_spc_max.

Parameters
[in]spcRequested cluster size.
Returns
Whether spc is acceptable.
Return values
truespc is 0 (auto) or a power of two in 1..128.
falsespc is non-zero and not a valid power of two.
Precondition
None (total function over uint8_t).
Caller treats false as k_ra8_err_invalid_arg.
Postcondition
No state modified.
Result is purely a function of spc.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 589 of file ra8_fs_fat_fmt.c.

References k_fmt_spc_max.

Referenced by internal_format_locked().

◆ priv_free_chain()

ra8_err_t priv_free_chain ( const ra8_fs_mount_t * m,
uint32_t start )

Free an entire cluster chain starting at start.

Walks the chain via priv_fat_get, marking each cluster free. A guard counter bounds the loop against on-disk loops.

Parameters
[in]mMount providing FAT access.
[in]startFirst cluster of the chain.
Returns
Error code.
Return values
k_ra8_okAll clusters freed.
k_ra8_err_protocol_errorLoop detected in chain.
k_ra8_err_*Backend error.
Precondition
m is non-NULL with a valid backend.
start is a valid cluster number or sentinel.
Postcondition
On success, every cluster in the chain has FAT entry = 0.
On failure, FAT may be partially updated.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 331 of file ra8_fs_fat_lfn.c.

References ra8_fs_mount_t::count_of_clusters, k_cluster_first_data, k_cluster_free, k_ra8_err_protocol_error, k_ra8_ok, priv_alloc_hint_lower(), priv_fat_get(), priv_fat_set(), priv_free_count_gave(), and priv_is_eoc().

Referenced by internal_dir_grow(), internal_fat_mkdir(), internal_fat_rmdir(), internal_fat_trunc_shrink(), internal_truncate_existing(), and internal_unlink_locked().

◆ priv_is_eoc()

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.

EOC markers differ across FAT12/16/32.

Parameters
[in]mMount providing the FAT type.
[in]valueFAT entry value to test.
Returns
1 if EOC, 0 otherwise.
Return values
1value indicates end-of-chain.
0value is a normal next-cluster pointer.
Precondition
m is non-NULL.
value was obtained from a FAT entry read.
Postcondition
No state modified.
Result is purely a function of inputs.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 511 of file ra8_fs_fat.c.

References k_cluster_eoc_min_exfat, k_cluster_eoc_min_fat12, k_cluster_eoc_min_fat16, k_cluster_eoc_min_fat32, k_ra8_fs_type_exfat, k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, and ra8_fs_mount_t::type.

Referenced by internal_exchk_mark_fatchain(), internal_exfat_cluster_at(), internal_exfat_dir_survey(), internal_exfat_survey_alloc(), internal_fat_classify_one(), internal_fat_mark_chain(), internal_fat_scan_cluster_dir(), internal_fat_trunc_shrink(), internal_skip_clusters(), internal_trunc_walk(), internal_walk_grow(), priv_dir_walk_next_sector(), priv_exfat_free_clusters(), priv_exfat_step_cluster(), and priv_free_chain().

◆ priv_lfn_add()

void priv_lfn_add ( lfn_state_t * s,
const uint8_t * ent )

Fold one LFN directory entry's 13 UTF-16LE code units into the state.

Reads the sequence number from ent (low 5 bits of LDIR_Ord) to locate the unit group within the assembled name, then copies each of the 13 units at their VFAT byte offsets (LDIR_Name1/2/3) VERBATIM. A zero unit or the padding value (0xFFFF) terminates the group early. The stored checksum is updated from LDIR_Chksum. Out-of-range sequence numbers are silently ignored to tolerate a corrupt chain.

Units above 0x7F used to become ?, which made the reported name one the caller could not hand back to ra8_fs_open() – the file was listed and then unopenable, and two names differing only in an accent collided (#606).

Parameters
[in,out]sReassembly state being accumulated.
[in]ent32-byte raw LFN directory entry (attribute byte == 0x0F).
Returns
Nothing.
Precondition
s is non-NULL and was initialised by priv_lfn_reset().
ent is non-NULL and points to exactly 32 valid bytes.
Postcondition
If the sequence number is in range, s->units and s->checksum reflect the units from this entry.
If the sequence number is out of range, s is unchanged.
Note
Not thread-safe; the caller serialises directory access.
Since
0.1.0

Definition at line 141 of file ra8_fs_fat_lfn.c.

References lfn_state_t::checksum, lfn_state_t::have, k_lfn_chars_per_ent, k_lfn_max_entries, k_lfn_off_checksum, k_lfn_off_seq, k_lfn_seq_order_mask, k_lfn_unicode_pad, k_lfn_write_max, s_lfn_char_off, and lfn_state_t::units.

Referenced by internal_dir_find_long_sector(), internal_fat_dir_scan_sector(), and internal_listdir_visit_sector().

◆ priv_lfn_reset()

void priv_lfn_reset ( lfn_state_t * s)

Reset the LFN reassembly state so a fresh chain can start.

Clears the accumulated unit array, then resets the stored checksum and the "have" flag to zero. Called at the start of a directory walk and whenever a deleted or consumed 8.3 entry breaks an in-progress chain.

Parameters
[in,out]sReassembly state to reset.
Returns
Nothing.
Precondition
s is non-NULL.
s was previously initialised (e.g. via zero-init or a prior reset).
Postcondition
s->units is all zero.
s->have and s->checksum are both zero.
Note
Not thread-safe; the caller serialises directory access.
Since
0.1.0

Definition at line 131 of file ra8_fs_fat_lfn.c.

References lfn_state_t::checksum, lfn_state_t::have, k_lfn_write_max, and lfn_state_t::units.

Referenced by internal_dir_find_long_sector(), internal_fat_dir_scan_sector(), internal_listdir_visit_sector(), and priv_dir_find_long().

◆ priv_lfn_units_for()

const uint16_t * priv_lfn_units_for ( const lfn_state_t * s,
const uint8_t * name83,
uint32_t * out_units )

Code units of the chain that precedes name83, or NULL if none.

Returns the reassembled name only when a chain was accumulated and its checksum matches name83, so a stray chain never aliases an entry. The units are returned rather than text because that is the domain a lookup compares in and the domain the up-case table folds; only the listing path converts, and only at the API boundary.

The length is the run of non-zero units, exactly as the NUL used to end the string: a group that never arrived leaves zeros, and the name stops there instead of running into another chain's characters.

Parameters
[in]sReassembly state carried across the directory walk.
[in]name83The 8.3 entry the chain is claimed to belong to.
[out]out_unitsReceives the unit count (0 when there is no name).
Returns
Pointer to the units, or nullptr.
Return values
s->unitsThe chain is present and binds to name83.
nullptrNo chain, an empty one, or a checksum mismatch.
Precondition
s and out_units are non-NULL; name83 addresses 11 bytes.
s was initialised by priv_lfn_reset() before the walk.
Postcondition
*out_units is written on both outcomes.
s is not modified.
Note
Not thread-safe; the caller serialises directory access.
Since
0.1.0

Definition at line 171 of file ra8_fs_fat_lfn.c.

References lfn_state_t::checksum, lfn_state_t::have, k_lfn_write_max, priv_sfn_checksum(), and lfn_state_t::units.

Referenced by internal_dir_find_long_sector(), internal_fat_dir_scan_sector(), and internal_listdir_visit_sector().

◆ priv_lock_acquire()

void priv_lock_acquire ( void )

Take the library lock, if the caller installed one.

Invokes the installed ra8_fs_lock_t::acquire with its cookie. With no binding installed – the bare-metal default – this is a load and a branch and nothing else, which is why the seam costs the default world nothing. Called only by the public entry-point wrappers: an internal helper taking it a second time would deadlock a non-recursive mutex, and the RA8_EXPECTS_LOCK("ra8_fs_lock") tag on every guarded implementation is what enforces that.

Returns
Nothing.
Precondition
The calling thread does not already hold the lock.
The installed binding (if any) is complete – guaranteed by ra8_fs_set_lock, which rejects a half-filled one.
Postcondition
The lock is held, or no binding is installed.
No library state other than the caller's lock is touched.
Note
Pairs 1:1 with priv_lock_release on every return path.
Since
0.1.0

Definition at line 75 of file ra8_fs_fat_lock.c.

References s_lock, and s_lock_installed.

Referenced by ra8_fs_check(), ra8_fs_close(), ra8_fs_dir_next(), ra8_fs_dir_open(), ra8_fs_format(), ra8_fs_free_space(), ra8_fs_get_label(), ra8_fs_listdir(), ra8_fs_mkdir(), ra8_fs_mount(), ra8_fs_mount_partition(), ra8_fs_open(), ra8_fs_probe(), ra8_fs_read(), ra8_fs_rename(), ra8_fs_rmdir(), ra8_fs_seek(), ra8_fs_set_attr(), ra8_fs_set_label(), ra8_fs_size(), ra8_fs_stat(), ra8_fs_tell(), ra8_fs_truncate(), ra8_fs_unlink(), ra8_fs_unmount(), ra8_fs_utime(), ra8_fs_write(), and ra8_fs_write_file().

◆ priv_lock_release()

void priv_lock_release ( void )

Drop the library lock taken by priv_lock_acquire.

Invokes the installed ra8_fs_lock_t::release with its cookie, or does nothing when no binding is installed. This is the release half the annotation checker looks for when it decides whether a public wrapper discharged the ownership it took.

Returns
Nothing.
Precondition
A matching priv_lock_acquire ran on this thread.
The binding has not changed since that call.
Postcondition
The lock is no longer held.
No library state other than the caller's lock is touched.
Note
Called on the success path and every error path of each wrapper.
Since
0.1.0

Definition at line 84 of file ra8_fs_fat_lock.c.

References s_lock, and s_lock_installed.

Referenced by ra8_fs_check(), ra8_fs_close(), ra8_fs_dir_next(), ra8_fs_dir_open(), ra8_fs_format(), ra8_fs_free_space(), ra8_fs_get_label(), ra8_fs_listdir(), ra8_fs_mkdir(), ra8_fs_mount(), ra8_fs_mount_partition(), ra8_fs_open(), ra8_fs_probe(), ra8_fs_read(), ra8_fs_rename(), ra8_fs_rmdir(), ra8_fs_seek(), ra8_fs_set_attr(), ra8_fs_set_label(), ra8_fs_size(), ra8_fs_stat(), ra8_fs_tell(), ra8_fs_truncate(), ra8_fs_unlink(), ra8_fs_unmount(), ra8_fs_utime(), ra8_fs_write(), and ra8_fs_write_file().

◆ priv_open_locked()

ra8_err_t priv_open_locked ( ra8_fs_mount_t * handle,
const char * path,
ra8_fs_mode_t mode,
ra8_fs_file_t ** out_file )

Open a file by path – the guarded body of ra8_fs_open().

Carries the whole contract documented for ra8_fs_open() in ra8_fs.h; the public symbol is the wrapper that brackets this call with priv_lock_acquire / priv_lock_release. Exposed across translation units because ra8_fs_write_file()'s guarded body has to reach it without taking the lock a second time.

Parameters
[in]handleMount handle.
[in]pathNUL-terminated path.
[in]modeOpen mode.
[out]out_fileReceives the open file handle.
Returns
Error code.
Return values
k_ra8_okFile opened.
k_ra8_err_null_ptrAny pointer argument was NULL.
k_ra8_err_*As documented for ra8_fs_open().
Precondition
The library lock is held (or none is installed).
handle, path, and out_file are non-NULL.
Postcondition
On success *out_file is a valid open handle.
On failure no file slot is marked in use.
Note
Never call this from outside ra8_fs; it is the unlocked half.
Since
0.1.0

Definition at line 455 of file ra8_fs_fat_file.c.

References ra8_fs_mount_t::in_use, internal_create_new(), internal_open_existing(), k_ra8_err_invalid_state, k_ra8_err_not_found, k_ra8_err_null_ptr, k_ra8_fs_dir_entry_bytes, k_ra8_fs_mode_read, k_ra8_fs_type_exfat, k_ra8_ok, priv_dir_lookup_any(), priv_exfat_open(), priv_resolve_parent(), and ra8_fs_mount_t::type.

Referenced by internal_write_file_locked(), and ra8_fs_open().

◆ priv_parse_bpb_into_mount()

ra8_err_t priv_parse_bpb_into_mount ( ra8_fs_mount_t * m)

Parse the BPB layout fields out of g_fs_scratch into m.

Validates the boot signature (0x55AA) and reads the BPB fields out of the boot sector scratch buffer.

Parameters
[in,out]mMount to populate; backend already plugged in.
Returns
Error code.
Return values
k_ra8_okFields parsed successfully.
k_ra8_err_validation_failedBad signature or sanity-check fail.
Precondition
m is non-NULL.
g_fs_scratch holds the boot sector (LBA 0).
Postcondition
On success, the relevant m->* fields are populated.
On failure, m may be partially updated.
Note
Not thread-safe – uses module-level scratch.
Since
0.1.0

Definition at line 171 of file ra8_fs_fat_mount.c.

References ra8_fs_mount_t::bytes_per_sector, ra8_fs_mount_t::fat_size_sectors, g_fs_scratch, k_bpb_off_bytes_per_sec, k_bpb_off_fat_sz_16, k_bpb_off_fat_sz_32, k_bpb_off_num_fats, k_bpb_off_root_clus, k_bpb_off_root_ent_cnt, k_bpb_off_rsvd_sec_cnt, k_bpb_off_sec_per_clus, k_bpb_off_signature_hi, k_bpb_off_signature_lo, k_bpb_off_tot_sec_16, k_bpb_off_tot_sec_32, k_bpb_sig_hi, k_bpb_sig_lo, k_ra8_err_validation_failed, k_ra8_ok, ra8_fs_mount_t::num_fats, priv_rd16(), priv_rd32(), ra8_fs_mount_t::reserved_sectors, ra8_fs_mount_t::root_cluster, ra8_fs_mount_t::root_entries, ra8_fs_mount_t::sectors_per_cluster, and ra8_fs_mount_t::total_sectors.

Referenced by priv_parse_volume().

◆ priv_parse_volume()

ra8_err_t priv_parse_volume ( ra8_fs_mount_t * m)

Parse the volume at the current base: exFAT first, then FAT BPB.

Dispatches to the exFAT parser when the VBR carries the exFAT signature, else to the FAT BPB parser.

Parameters
[in,out]mMount with sector 0 already read into g_fs_scratch.
Returns
Error code from the chosen parser.
Return values
k_ra8_okVolume parsed (FAT or exFAT).
k_ra8_err_*No recognizable volume at this base.
Precondition
m is non-NULL and g_fs_scratch holds the base sector 0.
m->backend is bound.
Postcondition
On success m holds the volume geometry + type.
On failure m is left unmounted.
Note
Not thread-safe.
Since
0.1.0

Definition at line 162 of file ra8_fs_fat_exfat_read.c.

References g_fs_scratch, internal_exfat_is_volume(), internal_exfat_parse(), and priv_parse_bpb_into_mount().

Referenced by internal_read_boot_sector().

◆ 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_read_sector()

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.

Forwards to the mount's backend.read_block callback.

Parameters
[in]mMount whose backend to use.
[in]lbaLogical block address to read.
[out]bufDestination of m->bytes_per_sector bytes.
Returns
Backend-supplied error code.
Return values
k_ra8_okSector read successfully.
k_ra8_err_*Whatever the backend returned.
Precondition
m, m->backend.read_block, and buf are non-NULL.
lba is within the volume's addressable range.
Postcondition
On success, buf holds the sector contents.
On failure, buf content is undefined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 134 of file ra8_fs_fat.c.

References ra8_fs_mount_t::backend, ra8_fs_backend_t::ctx, ra8_fs_mount_t::partition_base_lba, and ra8_fs_backend_t::read_block.

Referenced by internal_close_stamp(), internal_dir_collect_chain(), internal_dir_erase_positions(), internal_dir_is_empty(), internal_exchk_bitmap_pass(), internal_exfat_bitmap_window(), internal_exfat_read_entry(), internal_fat_boot_set_label(), internal_fat_del_entry(), internal_fat_dir_next(), internal_fat_find_free_root(), internal_fat_find_vol_id(), internal_fat_fsinfo(), internal_fat_put_vol_id(), internal_fat_scan_cluster_dir(), internal_fat_scan_fixed_root(), internal_fat_trunc_commit(), internal_fsinfo_locate(), internal_get_label_fat(), internal_gpt_read_geom(), internal_gpt_scan_entries(), internal_read_boot_sector(), internal_read_one_chunk(), internal_setattr_fat(), internal_slot_advance(), internal_space_exfat_free(), internal_trunc_zero_span(), internal_truncate_existing(), internal_utime_fat(), priv_dir_commit(), priv_dir_find(), priv_dir_find_free_run(), priv_dir_find_long(), priv_exfat_bitmap_test(), priv_exfat_bmp_switch(), priv_exfat_next_entry(), priv_exfat_seal_cluster(), priv_exfat_write_dir_set(), priv_fat_sector_read(), priv_fsinfo_flush(), priv_fsinfo_seed(), priv_gpt_locate_partition(), and priv_write_into_sector().

◆ priv_resolve_dir()

ra8_err_t priv_resolve_dir ( const ra8_fs_mount_t * m,
const char * path,
dir_loc_t * out )

Resolve a whole path to the directory it names.

The empty path or "/" resolves to the volume root; otherwise the parent is resolved and the final component is entered as a subdirectory. Used by ra8_fs_listdir to walk any directory.

Parameters
[in]mMount providing geometry and backend.
[in]pathNUL-terminated directory path.
[out]outReceives the resolved directory location.
Returns
Error code.
Return values
k_ra8_okDirectory resolved.
k_ra8_err_invalid_argA component is not a directory / not 8.3.
k_ra8_err_not_foundA component does not exist.
k_ra8_err_*Backend error.
Precondition
m, path, and out are non-NULL.
path is NUL-terminated.
Postcondition
On success out locates the named directory.
On failure out is unspecified.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 357 of file ra8_fs_fat_file.c.

References dir_loc_t::cluster, internal_enter_subdir(), dir_loc_t::is_root, k_ra8_ok, and priv_resolve_parent().

◆ priv_resolve_parent()

ra8_err_t priv_resolve_parent ( const ra8_fs_mount_t * m,
const char * path,
dir_loc_t * out_parent,
const char ** out_leaf )

Resolve all-but-the-last path component to a parent directory.

Splits path on /, descending through each intermediate component (which must be an existing subdirectory) and returning the final component as out_leaf. A flat name (no embedded /) yields the root as the parent and the whole name as the leaf – the legacy root-only behaviour. The walk is bounded by k_path_max_depth.

Parameters
[in]mMount providing geometry and backend.
[in]pathNUL-terminated path (leading slashes ignored).
[out]out_parentReceives the resolved parent directory location.
[out]out_leafReceives a pointer into path at the final component.
Returns
Error code.
Return values
k_ra8_okParent resolved; out_leaf set.
k_ra8_err_invalid_argA component is not 8.3, or the path is too deep.
k_ra8_err_not_foundAn intermediate component does not exist.
k_ra8_err_*Backend error.
Precondition
m, path, out_parent, and out_leaf are non-NULL.
path is NUL-terminated.
Postcondition
On success out_parent locates the leaf's parent directory.
On failure the out parameters are unspecified.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 319 of file ra8_fs_fat_file.c.

References internal_enter_subdir(), k_path_max_depth, k_ra8_err_invalid_arg, and k_ra8_ok.

Referenced by internal_fat_mkdir(), internal_rename_prepare(), internal_rmdir_locate(), internal_setattr_fat(), internal_stat_fat(), internal_unlink_locate(), internal_utime_fat(), priv_open_locked(), and priv_resolve_dir().

◆ priv_strlen()

uint32_t priv_strlen ( const char * s)

Length of a NUL-terminated string.

Counts bytes up to the NUL terminator.

Parameters
[in]sNUL-terminated string.
Returns
Character count before the terminator.
Return values
0..UINT32_MAXString length.
Precondition
s is non-NULL.
s is NUL-terminated.
Postcondition
No state modified.
s is unmodified.
Note
Pure function.
Since
0.1.0

Definition at line 27 of file ra8_fs_fat_exfat_read.c.

Referenced by internal_exfat_rename_prepare(), internal_exfat_rmdir_locate(), internal_set_label_locked(), priv_exfat_lookup(), priv_exfat_resolve_dir(), and priv_exfat_unlink().

◆ priv_to_upper()

char priv_to_upper ( char c)

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

Locale-independent ASCII upcase.

Parameters
[in]cInput character.
Returns
Upper-case form of c if it was lower-case ASCII, else c.
Return values
'A'..'Z'Upper-cased input.
cOtherwise unchanged.
Precondition
None.
Caller wants ASCII-only handling.
Postcondition
No state modified.
Result is purely a function of c.
Note
Pure function; trivially thread-safe.
Since
0.1.0

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().

◆ priv_write_into_sector()

ra8_err_t priv_write_into_sector ( const ra8_fs_mount_t * m,
uint64_t lba,
uint32_t off_in_sector,
const uint8_t * src,
uint32_t put )

Merge put bytes into one sector at lba, at off_in_sector.

Read-modify-write of a single sector. Every partial-sector update in this adapter goes through it, so a write that does not start or end on a sector boundary cannot destroy the neighbouring bytes – which, inside a cluster, belong to the same file, and at a cluster edge may belong to another.

Parameters
[in]mMount providing the backend.
[in]lbaVolume-relative sector to update.
[in]off_in_sectorByte offset within the sector.
[in]srcSource bytes.
[in]putNumber of bytes to write.
Returns
Error code.
Return values
k_ra8_okSector updated.
k_ra8_err_*Backend read or write failure.
Precondition
m and src are non-NULL.
off_in_sector + put <= m->bytes_per_sector.
Postcondition
On success the sector reflects the merged content.
On failure the sector content is implementation-defined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Merge put bytes into one sector at lba, at off_in_sector.

Definition at line 341 of file ra8_fs_fat_fileio.c.

References k_ra8_ok, priv_byte_copy(), priv_read_sector(), priv_sec_io(), and priv_write_sector().

Referenced by internal_exfat_close_gap(), internal_write_stream(), and priv_exfat_write_stream().

◆ priv_write_sector()

ra8_err_t priv_write_sector ( const ra8_fs_mount_t * m,
uint64_t lba,
const uint8_t * buf )

Write a single sector from a caller-provided buffer.

Forwards to the mount's backend.write_block callback.

Parameters
[in]mMount whose backend to use.
[in]lbaLogical block address to write.
[in]bufSource of m->bytes_per_sector bytes.
Returns
Backend-supplied error code.
Return values
k_ra8_okSector written successfully.
k_ra8_err_*Whatever the backend returned.
Precondition
m, m->backend.write_block, and buf are non-NULL.
lba is within the volume's addressable range.
Postcondition
On success, the underlying backend has the new sector contents.
On failure, backend state is implementation-defined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 140 of file ra8_fs_fat.c.

References ra8_fs_mount_t::backend, ra8_fs_backend_t::ctx, ra8_fs_mount_t::partition_base_lba, and ra8_fs_backend_t::write_block.

Referenced by internal_close_stamp(), internal_dir_cluster_init(), internal_dir_erase_positions(), internal_dir_grow(), internal_exfat_fat_set_one(), internal_fat12_store(), internal_fat16_set_one(), internal_fat32_set_one(), internal_fat_boot_set_label(), internal_fat_del_entry(), internal_fat_put_vol_id(), internal_fat_trunc_commit(), internal_setattr_fat(), internal_slot_advance(), internal_trunc_zero_span(), internal_truncate_existing(), internal_utime_fat(), priv_dir_commit(), priv_exfat_bitmap_clear(), priv_exfat_bitmap_mark(), priv_exfat_bmp_switch(), priv_exfat_seal_cluster(), priv_exfat_write_dir_set(), priv_exfat_zero_cluster(), priv_fsinfo_flush(), and priv_write_into_sector().