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

FAT12/FAT16/FAT32 low-level primitives for the ra8_fs adapter. 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.c:

Go to the source code of this file.

Functions

uint16_t priv_rd16 (const uint8_t *p)
 Decode a little-endian uint16_t from a byte buffer.
uint32_t priv_rd32 (const uint8_t *p)
 Decode a little-endian uint32_t from a byte buffer.
uint64_t priv_rd64 (const uint8_t *p)
 Decode a little-endian uint64_t from a byte buffer.
void priv_wr16 (uint8_t *p, uint16_t v)
 Encode a little-endian uint16_t into a byte buffer.
void priv_wr32 (uint8_t *p, uint32_t v)
 Encode a little-endian uint32_t into a byte buffer.
void priv_wr64 (uint8_t *p, uint64_t v)
 Encode a uint64_t into a byte buffer, little-endian.
uint32_t priv_bps (const ra8_fs_mount_t *m)
 One mounted volume's sector size in bytes.
uint32_t priv_cluster_bytes (const ra8_fs_mount_t *m)
 One mounted volume's cluster size in bytes.
uint32_t priv_dir_eps (const ra8_fs_mount_t *m)
 Directory entries per sector on one mounted volume.
void priv_byte_fill (uint8_t *dst, uint8_t value, uint32_t n)
 Fill n bytes of dst with value.
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_byte_equal (const uint8_t *a, const uint8_t *b, uint32_t n)
 Compare two byte buffers for equality (length n).
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_write_sector (const ra8_fs_mount_t *m, uint64_t lba, const uint8_t *buf)
 Write a single sector from a caller-provided buffer.
static uint64_t internal_fat_entry_byte_offset (const ra8_fs_mount_t *m, uint32_t cluster)
 Compute the byte offset of cluster's FAT entry for this FAT type.
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.
static ra8_err_t internal_fat12_store (const ra8_fs_mount_t *m, const uint8_t *buf, const uint8_t *buf2, uint64_t sec_num, uint8_t straddle)
 Commit one (or, when straddling, two) FAT12 sectors and refresh the cache.
static ra8_err_t internal_fat12_set_one (const ra8_fs_mount_t *m, uint64_t sec_num, uint32_t sec_off, uint32_t cluster, uint32_t value)
 Write a FAT12 entry, handling sector-straddling 12-bit packing.
static ra8_err_t internal_fat16_set_one (const ra8_fs_mount_t *m, uint64_t sec_num, uint32_t sec_off, uint32_t value)
 Write a FAT16 entry into one sector.
static ra8_err_t internal_fat32_set_one (const ra8_fs_mount_t *m, uint64_t sec_num, uint32_t sec_off, uint32_t value)
 Write a FAT32 entry into one sector (preserves top 4 reserved bits).
static ra8_err_t internal_exfat_fat_set_one (const ra8_fs_mount_t *m, uint64_t sec_num, uint32_t sec_off, uint32_t value)
 Write an exFAT FAT entry – all 32 bits, nothing reserved.
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.
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.
uint32_t priv_eoc_write (const ra8_fs_mount_t *m)
 End-of-chain value to write for this FAT type.
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.
static uint32_t internal_alloc_start (const ra8_fs_mount_t *m, uint32_t hint)
 Normalise a next-free hint into a real cluster number.
ra8_err_t priv_alloc_cluster (const ra8_fs_mount_t *m, uint32_t *out_cluster)
 Free-cluster scan from the next-free hint, wrapping exactly once.

Detailed Description

FAT12/FAT16/FAT32 low-level primitives for the ra8_fs adapter.

Sector-by-sector primitives shared by the rest of the FAT/exFAT adapter: little-endian field access, the backend sector read/write wrappers, and the FAT12/16/32 entry get/set + cluster-allocation layer. The adapter is split across several translation units (see ra8_fs_fat_internal.h); this file holds the bottom layer every other unit builds on. No dynamic memory: one static scratch sector serves every access.

References (every shorthand citation in this file):

  • "MS FAT spec" = Microsoft Corp., "FAT: General Overview of On-Disk Format", v1.03, December 6 2000. Section numbers track that PDF.

NASA Power-of-Ten compliance:

  • Rule 2: every loop is bounded by sector count, cluster count, or a small enum-defined max.
  • Rule 3: zero malloc; all state lives in static arrays.
  • Rule 5: every public entry checks pre/post-conditions.
  • Rule 7: every backend call is checked.
Since
0.1.0

Definition in file ra8_fs_fat.c.

Function Documentation

◆ internal_alloc_start()

uint32_t internal_alloc_start ( const ra8_fs_mount_t * m,
uint32_t hint )
static

Normalise a next-free hint into a real cluster number.

A hint is an optimisation, not a promise: it can sit one past the last cluster after the previous allocation took the final one, and on a FAT32 volume it can arrive from an FSI_Nxt_Free some other implementation wrote. Anything outside [2, 2 + count) restarts the scan at the first data cluster.

Parameters
[in]mMount providing the cluster count.
[in]hintRaw hint from priv_alloc_hint_get.
Returns
A cluster number the scan may start at.
Return values
2..(2+ count_of_clusters - 1) The clamped start cluster.
Precondition
m is non-NULL with count_of_clusters >= 1.
hint came from the allocator state, not from a directory entry.
Postcondition
No state modified.
The result addresses a cluster this volume has.
Note
Pure function; trivially thread-safe.
MC/DC:
Decision: (hint - k_cluster_first_data) >= count_of_clusters (1 condition).
  • hint past the last cluster -> true -> restart at cluster 2.
  • an ordinary in-range hint -> false -> start there. A hint BELOW cluster 2 needs no second condition: the subtraction is unsigned, so it wraps to a value far above any cluster count and the same test catches it. Spelling that out as a second range term would add a condition nothing in the tree can make true – no caller can produce a hint below 2 – and an untestable condition is a permanent MC/DC hole.
Since
0.1.0

Definition at line 582 of file ra8_fs_fat.c.

References ra8_fs_mount_t::count_of_clusters, and k_cluster_first_data.

Referenced by priv_alloc_cluster().

◆ internal_exfat_fat_set_one()

ra8_err_t internal_exfat_fat_set_one ( const ra8_fs_mount_t * m,
uint64_t sec_num,
uint32_t sec_off,
uint32_t value )
static

Write an exFAT FAT entry – all 32 bits, nothing reserved.

The exFAT counterpart of ::priv_fat32_set_one. exFAT has no reserved high nibble (spec sec 4.1), so there is nothing to preserve and the value goes down whole. Routing exFAT through the FAT32 setter would mask the end-of-chain marker to 0x0FFFFFFF, which a host fsck reads as a chain pointing at a cluster the volume does not have.

Parameters
[in]mMount providing backend access.
[in]sec_numSector number containing the entry.
[in]sec_offByte offset within that sector.
[in]valueThe 32-bit entry value to store.
Returns
Error code.
Return values
k_ra8_okEntry updated.
k_ra8_err_*Backend read or write failure.
Precondition
m is non-NULL with a valid backend.
sec_off <= m->bytes_per_sector - 4.
Postcondition
The entry on disk equals value exactly.
On failure, on-disk state is implementation-defined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 466 of file ra8_fs_fat.c.

References k_ra8_ok, priv_fat_sector_read(), priv_fat_sector_wrote(), priv_sec_fat(), priv_wr32(), and priv_write_sector().

Referenced by priv_fat_set().

◆ internal_fat12_set_one()

ra8_err_t internal_fat12_set_one ( const ra8_fs_mount_t * m,
uint64_t sec_num,
uint32_t sec_off,
uint32_t cluster,
uint32_t value )
static

Write a FAT12 entry, handling sector-straddling 12-bit packing.

FAT12 entries are 12 bits and may straddle a sector boundary.

Parameters
[in]mMount providing backend access.
[in]sec_numSector number containing the entry's first byte.
[in]sec_offByte offset within that sector.
[in]clusterCluster number (used to pick low/high nibble).
[in]value12-bit value to write (low 12 bits used).
Returns
Error code.
Return values
k_ra8_okEntry updated.
k_ra8_err_*Backend read/write failure.
Precondition
m is non-NULL with a valid backend.
sec_off < m->bytes_per_sector.
Postcondition
On success, the FAT12 entry on disk reflects the new value.
On failure, on-disk state is implementation-defined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 311 of file ra8_fs_fat.c.

References internal_fat12_store(), k_byte_mask, k_fat12_high_nibble_mask, k_fat12_low_nibble_mask, k_fat12_value_mask, k_ra8_ok, k_shift_byte, k_shift_nibble, priv_bps(), priv_fat_sector_read(), priv_sec_fat(), and priv_sec_fat2().

Referenced by priv_fat_set().

◆ internal_fat12_store()

ra8_err_t internal_fat12_store ( const ra8_fs_mount_t * m,
const uint8_t * buf,
const uint8_t * buf2,
uint64_t sec_num,
uint8_t straddle )
static

Commit one (or, when straddling, two) FAT12 sectors and refresh the cache.

Split out of ::priv_fat12_set_one so that function stays inside the statement budget: the write-back half is self-contained, and both sectors go through priv_fat_sector_wrote so a later read of either is served from memory rather than the device.

Parameters
[in]mMount providing backend access.
[in]bufThe entry's first sector, already patched.
[in]buf2The following sector, meaningful only when straddling.
[in]sec_numSector number of buf.
[in]straddleNon-zero when the entry spans into buf2.
Returns
Error code.
Return values
k_ra8_okEvery affected sector is on disk.
k_ra8_err_*Backend write failure.
Precondition
m, buf and buf2 are non-NULL.
Both buffers hold a whole sector.
Postcondition
On success the on-disk FAT12 entry reflects the new value.
On success the sector cache matches what was written.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 264 of file ra8_fs_fat.c.

References k_ra8_ok, priv_fat_sector_wrote(), and priv_write_sector().

Referenced by internal_fat12_set_one().

◆ internal_fat16_set_one()

ra8_err_t internal_fat16_set_one ( const ra8_fs_mount_t * m,
uint64_t sec_num,
uint32_t sec_off,
uint32_t value )
static

Write a FAT16 entry into one sector.

FAT16 entries never straddle sectors. One read/write cycle updates the entry.

Parameters
[in]mMount providing backend access.
[in]sec_numSector number containing the entry.
[in]sec_offByte offset within that sector.
[in]valueValue to write (low 16 bits used).
Returns
Error code.
Return values
k_ra8_okEntry updated.
k_ra8_err_*Backend read/write failure.
Precondition
m is non-NULL with a valid backend.
sec_off <= m->bytes_per_sector - 2.
Postcondition
On success, the FAT16 entry on disk reflects the new value.
On failure, on-disk state is implementation-defined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 378 of file ra8_fs_fat.c.

References k_ra8_ok, k_word_mask, priv_fat_sector_read(), priv_fat_sector_wrote(), priv_sec_fat(), priv_wr16(), and priv_write_sector().

Referenced by priv_fat_set().

◆ internal_fat32_set_one()

ra8_err_t internal_fat32_set_one ( const ra8_fs_mount_t * m,
uint64_t sec_num,
uint32_t sec_off,
uint32_t value )
static

Write a FAT32 entry into one sector (preserves top 4 reserved bits).

FAT32 entries are 32 bits but only the low 28 bits are cluster data; the high 4 reserved bits must be preserved.

Parameters
[in]mMount providing backend access.
[in]sec_numSector number containing the entry.
[in]sec_offByte offset within that sector.
[in]valueValue to write (low 28 bits used).
Returns
Error code.
Return values
k_ra8_okEntry updated.
k_ra8_err_*Backend read/write failure.
Precondition
m is non-NULL with a valid backend.
sec_off <= m->bytes_per_sector - 4.
Postcondition
Low 28 bits of the entry equal value; high 4 bits preserved.
On failure, on-disk state is implementation-defined.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 420 of file ra8_fs_fat.c.

References k_cluster_mask_fat32, k_ra8_ok, priv_fat_sector_read(), priv_fat_sector_wrote(), priv_rd32(), priv_sec_fat(), priv_wr32(), and priv_write_sector().

Referenced by priv_fat_set().

◆ internal_fat_entry_byte_offset()

uint64_t internal_fat_entry_byte_offset ( const ra8_fs_mount_t * m,
uint32_t cluster )
static

Compute the byte offset of cluster's FAT entry for this FAT type.

FAT12 entries are 1.5 bytes, FAT16 are 2 bytes, FAT32 are 4 bytes. Result is the byte offset within the FAT region.

Parameters
[in]mMount providing the FAT type.
[in]clusterCluster number to look up.
Returns
Byte offset within the FAT region.
Return values
0..UINT32_MAXByte offset.
Precondition
m is non-NULL.
cluster is within the addressable cluster range.
Postcondition
No state modified.
Result is purely a function of inputs.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 172 of file ra8_fs_fat.c.

References k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, and ra8_fs_mount_t::type.

Referenced by priv_fat_get(), and priv_fat_set().

◆ priv_alloc_cluster()

ra8_err_t priv_alloc_cluster ( const ra8_fs_mount_t * m,
uint32_t * out_cluster )

Free-cluster scan from the next-free hint, wrapping exactly once.

Starts at the mount's next-free hint (priv_alloc_hint_get, seeded from FAT32's FSI_Nxt_Free when that validates) and walks forward for at most count_of_clusters steps, wrapping back to cluster 2 once, so the whole volume is still examined before it is declared full. The FAT entries are read through the one-sector cache, which is what makes a scan cost one block read per 128 clusters on FAT32 instead of one per cluster.

On success the hint moves to the cluster after the one taken and the tracked free count drops by one, so the FSInfo writeback has something true to write.

Parameters
[in]mMount providing geometry and backend.
[out]out_clusterOn success, the allocated cluster number.
Returns
Error code.
Return values
k_ra8_okCluster found; *out_cluster set.
k_ra8_err_no_memVolume is full – no free clusters.
k_ra8_err_*Backend read failure.
Precondition
m and out_cluster are non-NULL.
Volume is mounted and geometry is valid.
Postcondition
On success, *out_cluster is in range and free.
On failure, *out_cluster is unspecified.
Note
Caller must mark the cluster as EOC after carving it.
Since
0.1.0

Definition at line 591 of file ra8_fs_fat.c.

References ra8_fs_mount_t::count_of_clusters, internal_alloc_start(), k_cluster_first_data, k_cluster_free, k_ra8_err_no_mem, k_ra8_ok, priv_alloc_hint_get(), priv_alloc_hint_set(), priv_fat_get(), and priv_free_count_took().

Referenced by priv_alloc_eoc_cluster().

◆ priv_bps()

uint32_t priv_bps ( const ra8_fs_mount_t * m)

One mounted volume's sector size in bytes.

The runtime m->bytes_per_sector, returned through one accessor so every arithmetic site reads the same way. A power of two in k_ra8_fs_sector_min..k_ra8_fs_sector_max on any mounted volume.

Parameters
[in]mMounted volume.
Returns
Sector size in bytes.
Return values
512..4096The volume's sector size.
Precondition
m is non-NULL and parsed (bytes_per_sector populated).
The mount validated the size against the backend's block size.
Postcondition
No state modified.
Result is a power of two.
Note
Pure read; trivially thread-safe.
Since
0.1.0

Definition at line 84 of file ra8_fs_fat.c.

References ra8_fs_mount_t::bytes_per_sector.

Referenced by internal_compute_geometry(), internal_dir_cluster_init(), internal_dir_walk_init_root(), internal_exchk_bitmap_pass(), internal_exchk_set(), internal_exfat_bitmap_window(), internal_exfat_read_entry(), internal_exfat_slice_at(), internal_fat12_set_one(), internal_fat_dir_scan_sector(), internal_gpt_scan_entries(), internal_read_one_chunk(), internal_space_exfat_free(), internal_trunc_zero_span(), internal_write_stream(), priv_exfat_bitmap_clear(), priv_exfat_bitmap_mark(), priv_exfat_bitmap_test(), priv_exfat_next_entry(), priv_exfat_seal_cluster(), priv_exfat_write_dir_set(), priv_fat_get(), priv_fat_sector_read(), priv_fat_sector_wrote(), priv_fat_set(), and priv_gpt_locate_partition().

◆ priv_byte_copy()

void priv_byte_copy ( uint8_t * dst,
const uint8_t * src,
uint32_t n )

Length-checked byte copy used in place of memcpy().

Replaces memcpy() so clang-tidy's clang-analyzer-security.insecureAPI checker stays happy. Same effect on -O2 generated code.

Parameters
[out]dstDestination buffer.
[in]srcSource buffer.
[in]nNumber of bytes to copy.
Precondition
dst and src are non-NULL and point to at least n bytes.
dst and src do not overlap.
Postcondition
First n bytes of dst equal first n bytes of src.
No state outside dst is modified.
Note
Bounded loop, NASA Rule 2 compliant.
Since
0.1.0

Definition at line 110 of file ra8_fs_fat.c.

Referenced by internal_dir_find_long_sector(), internal_exchk_set(), internal_exfat_build_rename_set(), internal_exfat_locate_label(), internal_exfat_match_set(), internal_exfat_read_entry(), internal_exfat_take_set(), internal_exfat_try_set(), internal_fat_find_vol_id(), internal_fmt_boot_prologue(), internal_fmt_build_bpb_f16(), internal_fmt_build_bpb_f32(), internal_get_label_fat(), internal_read_one_chunk(), priv_dir_commit(), priv_dir_find(), priv_exfat_next_entry(), priv_exfat_write_dir_set(), priv_exfat_write_upcase(), priv_fat_sector_read(), priv_fat_sector_wrote(), and priv_write_into_sector().

◆ priv_byte_equal()

uint8_t priv_byte_equal ( const uint8_t * a,
const uint8_t * b,
uint32_t n )

Compare two byte buffers for equality (length n).

Returns early on first mismatch. Used in place of memcmp().

Parameters
[in]aFirst buffer.
[in]bSecond buffer.
[in]nNumber of bytes to compare.
Returns
1 on equal, 0 on mismatch.
Return values
1All n bytes equal.
0At least one byte differs.
Precondition
a and b are non-NULL and point to at least n bytes.
Caller has bounds-checked both buffers.
Postcondition
No state modified.
Result is purely a function of inputs.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 118 of file ra8_fs_fat.c.

Referenced by internal_label_from_raw(), and priv_dir_find().

◆ priv_byte_fill()

void priv_byte_fill ( uint8_t * dst,
uint8_t value,
uint32_t n )

Fill n bytes of dst with value.

The store-side sibling of priv_byte_copy, for zeroing an arena-taken sector before constructing content in it (the arena hands back whatever the previous user left, where the old stack buffers arrived zero-initialised).

Parameters
[out]dstDestination buffer.
[in]valueByte value to store.
[in]nNumber of bytes to fill.
Precondition
dst is non-NULL and holds at least n writable bytes.
n was bounds-checked by the caller.
Postcondition
dst[0..n) all equal value.
No other state is modified.
Note
Pure store; trivially thread-safe on distinct buffers.
Since
0.1.0

Definition at line 102 of file ra8_fs_fat.c.

Referenced by internal_dir_cluster_init(), and priv_fmt_emit_volume().

◆ priv_cluster_bytes()

uint32_t priv_cluster_bytes ( const ra8_fs_mount_t * m)

One mounted volume's cluster size in bytes.

sectors_per_cluster * bytes_per_sector. Fits 32 bits on every legal volume: exFAT caps a cluster at 32 MiB, FAT at 64 sectors of 4096 bytes.

Parameters
[in]mMounted volume.
Returns
Cluster size in bytes.
Return values
512..33554432The volume's cluster size.
Precondition
m is non-NULL and parsed (geometry fields populated).
The volume's cluster geometry is legal for its type.
Postcondition
No state modified.
Result is a power of two.
Note
Pure read; trivially thread-safe.
Since
0.1.0

Definition at line 90 of file ra8_fs_fat.c.

References ra8_fs_mount_t::bytes_per_sector, and ra8_fs_mount_t::sectors_per_cluster.

Referenced by internal_exchk_set_clusters(), internal_exchk_system_run(), internal_exfat_build_dir_set(), internal_exfat_slice_at(), internal_exfat_space_in_cluster(), internal_exfat_survey_alloc(), internal_exfat_trunc(), internal_fat_trunc(), internal_read_one_chunk(), internal_space_locked(), internal_write_stream(), priv_exfat_dir_from_set(), priv_exfat_free_clusters(), priv_exfat_grow_dir(), and priv_exfat_next_entry().

◆ priv_cluster_to_lba()

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.

Cluster numbering starts at k_cluster_first_data (= 2).

Parameters
[in]mMount providing geometry.
[in]clusterCluster number (>= k_cluster_first_data).
Returns
Sector LBA of the cluster's first sector.
Return values
0..UINT32_MAXComputed LBA.
Precondition
m is non-NULL with valid geometry.
cluster >= k_cluster_first_data.
Postcondition
No state modified.
Result is purely a function of inputs.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 541 of file ra8_fs_fat.c.

References ra8_fs_mount_t::first_data_lba, k_cluster_first_data, and ra8_fs_mount_t::sectors_per_cluster.

Referenced by internal_dir_cluster_init(), internal_dir_grow(), internal_dir_walk_init_root(), internal_exchk_set(), internal_exfat_dir_alloc(), internal_exfat_read_entry(), internal_exfat_slice_at(), internal_fat_scan_cluster_dir(), internal_read_one_chunk(), internal_space_exfat_free(), internal_trunc_zero_span(), internal_write_stream(), priv_check_exfat(), priv_dir_walk_init_loc(), priv_dir_walk_next_sector(), priv_exfat_bitmap_lba(), priv_exfat_next_entry(), priv_exfat_seal_cluster(), priv_exfat_write_dir_set(), and priv_exfat_zero_cluster().

◆ priv_dir_eps()

uint32_t priv_dir_eps ( const ra8_fs_mount_t * m)

Directory entries per sector on one mounted volume.

bytes_per_sector / 32 – 16 on a 512-byte volume, 128 on 4Kn. Replaces the old compile-time constant, which baked 512 in.

Parameters
[in]mMounted volume.
Returns
32-byte directory entries per sector.
Return values
16..128Entries per sector.
Precondition
m is non-NULL and parsed (bytes_per_sector populated).
bytes_per_sector is a multiple of 32.
Postcondition
No state modified.
Result times 32 equals the sector size.
Note
Pure read; trivially thread-safe.
Since
0.1.0

Definition at line 96 of file ra8_fs_fat.c.

References ra8_fs_mount_t::bytes_per_sector, and k_ra8_fs_dir_entry_bytes.

Referenced by internal_dir_collect_chain(), internal_dir_find_long_sector(), internal_fat_find_free_root(), internal_fat_find_vol_id(), internal_fat_scan_fixed_root(), internal_fat_visit_sector(), internal_listdir_visit_sector(), internal_rmdir_scan_sector(), internal_slot_advance(), priv_dir_find(), and priv_dir_find_free_run().

◆ priv_eoc_write()

uint32_t priv_eoc_write ( const ra8_fs_mount_t * m)

End-of-chain value to write for this FAT type.

Returns the canonical EOC value (0xFFF, 0xFFFF, or 0x0FFFFFFF).

Parameters
[in]mMount providing the FAT type.
Returns
Canonical EOC value for this volume.
Return values
k_cluster_eoc_write_fat12FAT12 EOC.
k_cluster_eoc_write_fat16FAT16 EOC.
k_cluster_eoc_write_fat32FAT32 EOC.
Precondition
m is non-NULL.
m->type has been computed by priv_compute_geometry.
Postcondition
No state modified.
Result is purely a function of m->type.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 526 of file ra8_fs_fat.c.

References k_cluster_eoc_write_exfat, k_cluster_eoc_write_fat12, k_cluster_eoc_write_fat16, k_cluster_eoc_write_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_exfat_dir_link(), internal_exfat_link_cluster(), internal_exfat_shrink_chain_tail(), internal_fat_trunc_shrink(), and priv_alloc_eoc_cluster().

◆ 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_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_rd16()

uint16_t priv_rd16 ( const uint8_t * p)

Decode a little-endian uint16_t from a byte buffer.

Trivial little-endian byte assembler. Avoids memcpy so clang-tidy's strict-alias check stays happy.

Parameters
[in]pPointer to two bytes.
Returns
The decoded value.
Return values
0..UINT16_MAXValue assembled from p[0] and p[1].
Precondition
p is non-NULL and points to at least 2 readable bytes.
Caller has bounds-checked p.
Postcondition
No state modified.
Result equals p[0] | (p[1] << 8).
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 42 of file ra8_fs_fat.c.

References k_shift_byte.

Referenced by internal_exchk_extract_name(), internal_exchk_verify_set(), internal_exfat_gather_name(), internal_fat_fsinfo(), internal_fsinfo_locate(), internal_stat_fat_times(), priv_entry_first_cluster(), priv_exfat_name_chunk_eq(), priv_exfat_upcase_unit(), priv_fat_get(), and priv_parse_bpb_into_mount().

◆ priv_rd32()

uint32_t priv_rd32 ( const uint8_t * p)

Decode a little-endian uint32_t from a byte buffer.

Trivial little-endian byte assembler for 4 bytes.

Parameters
[in]pPointer to four bytes.
Returns
The decoded value.
Return values
0..UINT32_MAXValue assembled from p[0..3].
Precondition
p is non-NULL and points to at least 4 readable bytes.
Caller has bounds-checked p.
Postcondition
No state modified.
Result equals p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24).
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 48 of file ra8_fs_fat.c.

References k_shift_byte, k_shift_three_bytes, and k_shift_two_bytes.

Referenced by internal_entry_to_stat(), internal_exchk_set_clusters(), internal_exchk_system_run(), internal_exfat_enter(), internal_exfat_open_found(), internal_exfat_parse(), internal_exfat_rmdir_locate(), internal_exfat_seed_read(), internal_fat32_set_one(), internal_fat_dir_scan_sector(), internal_fat_fsinfo(), internal_fsinfo_signatures_ok(), internal_gpt_read_geom(), internal_listdir_visit_sector(), internal_mbr_part0_lba(), internal_mbr_select_entry(), internal_open_existing(), internal_stat_exfat(), internal_stat_exfat_times(), priv_exfat_dir_from_set(), priv_exfat_find_bitmap(), priv_exfat_free_clusters(), priv_exfat_upcase_verify(), priv_fat_get(), priv_fsinfo_seed(), priv_parse_bpb_into_mount(), and priv_rd64().

◆ priv_rd64()

uint64_t priv_rd64 ( const uint8_t * p)

Decode a little-endian uint64_t from a byte buffer.

Trivial little-endian byte assembler for 8 bytes: the width of exFAT's DataLength / ValidDataLength and of a GPT entry's LBAs.

Parameters
[in]pPointer to eight bytes.
Returns
The decoded value.
Return values
0..UINT64_MAXValue assembled from p[0..7].
Precondition
p is non-NULL and points to at least 8 readable bytes.
Caller has bounds-checked p.
Postcondition
No state modified.
Result equals the little-endian 64-bit value at p.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 55 of file ra8_fs_fat.c.

References k_shift_word32, and priv_rd32().

Referenced by internal_exchk_set_clusters(), internal_exchk_system_run(), internal_exfat_list_emit(), internal_exfat_open_found(), internal_exfat_parse(), internal_exfat_seed_read(), internal_gpt_entry_first_lba(), internal_gpt_entry_select(), internal_gpt_read_geom(), internal_stat_exfat(), priv_exfat_dir_from_set(), and priv_exfat_free_clusters().

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

void priv_wr16 ( uint8_t * p,
uint16_t v )

Encode a little-endian uint16_t into a byte buffer.

Inverse of priv_rd16. Writes the low byte first.

Parameters
[out]pPointer to two writable bytes.
[in]vValue to encode.
Precondition
p is non-NULL and points to at least 2 writable bytes.
Caller has bounds-checked p.
Postcondition
p[0] and p[1] reflect the little-endian encoding of v.
No other state modified.
Note
Trivially thread-safe; not reentrant against the same buffer.
Since
0.1.0

Definition at line 61 of file ra8_fs_fat.c.

References k_byte_mask, and k_shift_byte.

Referenced by internal_exfat_build_dir_set(), internal_exfat_build_rename_set(), internal_exfat_build_set(), internal_exfat_build_vbr(), internal_exfat_dir_relen(), internal_exfat_write_mbr(), internal_fat16_set_one(), internal_fmt_build_bpb_f16(), internal_fmt_build_bpb_f32(), internal_fmt_seed_fats(), internal_fmt_write_totals(), internal_setattr_exfat(), internal_utime_exfat(), priv_entry_set_cluster_size(), priv_exfat_flush_set(), priv_fat_entry_set_times(), priv_fat_entry_stamp_access(), priv_fat_entry_stamp_create(), priv_fat_entry_stamp_write(), and priv_lfn_fill_slot().

◆ priv_wr32()

void priv_wr32 ( uint8_t * p,
uint32_t v )

Encode a little-endian uint32_t into a byte buffer.

Inverse of priv_rd32. Writes lowest byte first.

Parameters
[out]pPointer to four writable bytes.
[in]vValue to encode.
Precondition
p is non-NULL and points to at least 4 writable bytes.
Caller has bounds-checked p.
Postcondition
p[0..3] reflect the little-endian encoding of v.
No other state modified.
Note
Trivially thread-safe; not reentrant against the same buffer.
Since
0.1.0

Definition at line 68 of file ra8_fs_fat.c.

References k_byte_mask, k_shift_byte, k_shift_three_bytes, and k_shift_two_bytes.

Referenced by internal_exfat_build_dir_set(), internal_exfat_build_vbr(), internal_exfat_fat_set_one(), internal_exfat_free_run(), internal_exfat_patch_stream(), internal_exfat_put32(), internal_exfat_write_boot_tail(), internal_exfat_write_mbr(), internal_exfat_write_root(), internal_fat32_set_one(), internal_fmt_build_bpb_f16(), internal_fmt_build_bpb_f32(), internal_fmt_seed_fats(), internal_fmt_write_fsinfo(), internal_fmt_write_totals(), priv_entry_set_cluster_size(), priv_exfat_file_set_times(), priv_exfat_file_stamp_access(), priv_exfat_file_stamp_create(), priv_exfat_file_stamp_write(), priv_fsinfo_flush(), and priv_wr64().

◆ priv_wr64()

void priv_wr64 ( uint8_t * p,
uint64_t v )

Encode a uint64_t into a byte buffer, little-endian.

The 8-byte companion of priv_wr32, for exFAT's 64-bit DataLength / ValidDataLength fields and the formatter's PartitionOffset / VolumeLength.

Parameters
[out]pPointer to eight writable bytes.
[in]vValue to store.
Precondition
p is non-NULL and points to at least 8 writable bytes.
Caller has bounds-checked p.
Postcondition
p[0..7] hold v little-endian.
No other state modified.
Note
Pure store; trivially thread-safe on distinct buffers.
Since
0.1.0

Definition at line 77 of file ra8_fs_fat.c.

References k_shift_word32, and priv_wr32().

Referenced by internal_exfat_build_vbr(), internal_exfat_dir_relen(), internal_exfat_free_run(), and internal_exfat_patch_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().