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

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

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

Go to the source code of this file.

Functions

void priv_83_to_str (const uint8_t *in11, uint8_t ntres, char *out13)
 Unpack on-disk 11-byte 8.3 name into NUL-terminated "NAME.EXT".
ra8_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.
ra8_err_t priv_alloc_eoc_cluster (const ra8_fs_mount_t *m, uint32_t *out_c)
 Allocate a fresh cluster, mark it EOC, and return its number.
ra8_fs_file_tpriv_alloc_file_slot (void)
 Allocate a free entry from the file table; returns NULL if full.
char priv_ascii_upper (char c)
 Uppercase an ASCII character (others returned unchanged).
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_close_locked (ra8_fs_file_t *file)
 Close an open file – the guarded body of ra8_fs_close().
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.
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.
ra8_err_t priv_dir_find_long (const ra8_fs_mount_t *m, const dir_loc_t *loc, const char *want, uint64_t *out_lba, uint32_t *out_entry_off, uint8_t out_entry[k_ra8_fs_dir_entry_bytes])
 Find a directory entry by its VFAT long name (case-insensitive).
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.
uint32_t priv_entry_first_cluster (const uint8_t *entry)
 Read the first cluster from a 32-byte directory entry.
void priv_entry_set_cluster_size (uint8_t *entry, uint32_t cluster, uint32_t size)
 Patch first-cluster + size back into a 32-byte directory entry.
uint32_t priv_eoc_write (const ra8_fs_mount_t *m)
 End-of-chain value to write for this FAT type.
ra8_err_t priv_exfat_bmp_switch (const ra8_fs_mount_t *m, uint64_t lba, uint64_t *loaded, uint8_t *sec)
 Flush the cached bitmap sector and load lba if it changed.
uint32_t priv_exfat_csum32 (uint32_t cs, const uint8_t *buf, uint32_t len)
 exFAT 32-bit rotate-right-add checksum (boot region + up-case table).
ra8_err_t priv_exfat_find (const ra8_fs_mount_t *m, const exfat_dir_t *dir, const char *path, uint8_t *out_strm, uint8_t *out_attr)
 Find a name in ONE exFAT directory.
ra8_err_t priv_exfat_find_bitmap (const ra8_fs_mount_t *m, uint32_t *out_clus, uint32_t *out_len)
 Locate the allocation-bitmap entry in the exFAT root directory.
ra8_err_t priv_exfat_format (const ra8_fs_backend_t *backend, uint64_t total_sectors, uint32_t bps, const char *label)
 Format the backend as a PC-standard partitioned exFAT volume (#102).
ra8_err_t priv_exfat_listdir (const ra8_fs_mount_t *m, const exfat_dir_t *dir, ra8_fs_listdir_cb_t cb, void *ctx)
 Enumerate ONE directory of an exFAT volume.
ra8_err_t priv_exfat_dir_next (const ra8_fs_mount_t *m, exfat_cursor_t *cur, ra8_fs_dirent_t *out, bool *out_entry)
 Copy the next visible exFAT directory entry from an existing cursor.
uint8_t priv_exfat_name_chunk_eq (const uint8_t *entry, const uint16_t *name, uint32_t pos, uint32_t nlen)
 Compare one file-name entry's 15 UTF-16 units against a needle.
uint16_t priv_exfat_name_hash (const uint16_t *name, uint32_t nlen)
 Compute the exFAT NameHash for a name in UTF-16 code units.
ra8_err_t priv_exfat_name_to_units (const ra8_fs_mount_t *m, const char *path, uint16_t *out, uint32_t *out_units)
 Convert a caller's exFAT name to code units, refusing what will not fold.
ra8_err_t priv_exfat_needle_units (const ra8_fs_mount_t *m, const char *name, uint16_t *out, uint32_t *out_units, ra8_err_t too_long)
 Convert a leaf name to code units, mapping over-long to too_long.
ra8_err_t priv_exfat_next_entry (const ra8_fs_mount_t *m, exfat_cursor_t *cur, uint8_t *out)
 Fetch the next 32-byte directory entry, following the cluster chain.
ra8_err_t priv_exfat_open (ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
 Open a file (read-only) on a mounted exFAT volume.
ra8_err_t priv_exfat_rename (const ra8_fs_mount_t *m, const char *old_path, const char *new_path)
 Rename a root-level file on an exFAT volume, at any storable length.
uint16_t priv_exfat_set_checksum (const uint8_t *set, uint32_t bytes)
 Compute the SetChecksum over a built directory entry set.
ra8_err_t priv_exfat_unlink (const ra8_fs_mount_t *m, const char *path)
 Delete a file on an exFAT volume, at any depth.
uint16_t priv_exfat_upcase_unit (uint16_t unit)
 Fold a UTF-16 code unit through the canonical exFAT up-case table.
uint32_t priv_exfat_upcase_checksum (void)
 Rotate-add checksum of the up-case table this build embeds.
void priv_exfat_upcase_verify (ra8_fs_mount_t *m)
 Decide whether this build's fold matches the mounted volume's table.

Detailed Description

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

The first 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_83_to_str() through priv_exfat_upcase_verify(); the remaining helpers live in ra8_fs_fat_protos_b_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_a_internal.h.

Function Documentation

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

ra8_err_t priv_alloc_eoc_cluster ( const ra8_fs_mount_t * m,
uint32_t * out_c )

Allocate a fresh cluster, mark it EOC, and return its number.

Combines priv_alloc_cluster with a priv_fat_set to the canonical EOC value. Used by the write path when the file chain needs to grow.

Parameters
[in]mMount providing FAT access.
[out]out_cReceives the allocated cluster.
Returns
Error code.
Return values
k_ra8_okCluster allocated and marked EOC.
k_ra8_err_*Backend or FAT error.
Precondition
m and out_c are non-NULL.
Volume has free clusters.
Postcondition
On success, *out_c is in range and FAT entry = EOC.
On failure, FAT may have been partially updated.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 278 of file ra8_fs_fat_fileio.c.

References k_ra8_ok, priv_alloc_cluster(), priv_eoc_write(), and priv_fat_set().

Referenced by internal_dir_grow(), internal_fat_mkdir(), internal_fat_trunc_extend(), internal_walk_grow(), and internal_write_position().

◆ priv_alloc_file_slot()

ra8_fs_file_t * priv_alloc_file_slot ( void )

Allocate a free entry from the file table; returns NULL if full.

Linear scan of s_files for an entry with in_use == 0.

Returns
Pointer to a free file slot, or NULL if all are busy.
Return values
non-NULLPointer to a ra8_fs_file_t with in_use == 0.
NULLFile table is full.
Precondition
Module is initialized.
Caller serialises open/close operations.
Postcondition
No state modified.
Returned pointer remains valid for the program lifetime.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 118 of file ra8_fs_fat_mount.c.

References k_ra8_fs_max_files, and s_files.

Referenced by internal_create_new(), internal_exfat_open_created(), internal_exfat_open_found(), internal_open_existing(), and priv_exfat_open().

◆ priv_ascii_upper()

char priv_ascii_upper ( char c)

Uppercase an ASCII character (others returned unchanged).

Maps a-z to A-Z; any other byte is returned unchanged.

Parameters
[in]cInput character.
Returns
Uppercased character.
Return values
cThe (possibly) uppercased value.
Precondition
None.
c is a byte value.
Postcondition
No state modified.
Result depends only on c.
Note
Avoids compound conditions (MC/DC).
Since
0.1.0

Definition at line 37 of file ra8_fs_fat_exfat_read.c.

Referenced by priv_exfat_upcase_unit().

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

ra8_err_t priv_close_locked ( ra8_fs_file_t * file)

Close an open file – the guarded body of ra8_fs_close().

Carries the whole contract documented for ra8_fs_close() 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,out]fileHandle returned by priv_open_locked / ra8_fs_open().
Returns
Error code.
Return values
k_ra8_okFile closed.
k_ra8_err_null_ptrfile was NULL.
k_ra8_err_*The final modification-time stamp or the FSInfo writeback failed; the handle is released anyway.
Precondition
The library lock is held (or none is installed).
All pending writes have already been issued.
Postcondition
The file slot is marked free for reuse, whatever the metadata write did.
file->mount is reset to NULL.
Note
Never call this from outside ra8_fs; it is the unlocked half.
MC/DC:
The metadata write is guarded by a four-condition conjunction: the handle is dirty, the handle is in use, it has a mount, and that mount is in use. Its five vectors are driven by test_close_stamps_final_mtime and test_close_guards_an_unusable_handle in tests/storage/src/test_ra8_fs_timestamps.c, which cite it as libs/ra8_fs/src/ra8_fs_fat_file.c@priv_close_locked.
Since
0.1.0

Definition at line 543 of file ra8_fs_fat_file.c.

References internal_close_stamp(), k_ra8_err_null_ptr, and k_ra8_ok.

Referenced by internal_write_file_locked(), and ra8_fs_close().

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

ra8_err_t priv_dir_find_long ( const ra8_fs_mount_t * m,
const dir_loc_t * loc,
const char * want,
uint64_t * out_lba,
uint32_t * out_entry_off,
uint8_t out_entry[k_ra8_fs_dir_entry_bytes] )

Find a directory entry by its VFAT long name (case-insensitive).

Walks the directory described by loc sector by sector, calling priv_dir_find_long_sector() on each one. LFN chains are carried across sector boundaries via an lfn_state_t accumulator. A leading '/' in want is stripped before matching. Returns on the first name that matches want via priv_name_ieq(), or reports not-found when the end-of-directory marker is reached without a hit. Used as the fallback by ra8_fs_open() when the 8.3 short-name lookup misses, so that files with names longer than 8.3 (e.g. ".epub" four-char extensions) are accessible by their real long name.

Parameters
[in]mMount providing geometry and backend.
[in]locDirectory to search (root or a subdirectory).
[in]wantRequested name (a leading '/' is ignored).
[out]out_lbaSector containing the matched 8.3 entry.
[out]out_entry_offByte offset within the sector.
[out]out_entry32 bytes of the matched 8.3 directory entry.
Returns
Error code.
Return values
k_ra8_okLong name matched; out parameters populated.
k_ra8_err_not_foundNo entry's long name equals want.
k_ra8_err_*Backend read error propagated from priv_read_sector().
Precondition
All pointer parameters are non-NULL.
want is a NUL-terminated ASCII string.
Postcondition
On k_ra8_ok, out parameters identify the on-disk 8.3 entry for want.
On failure, the out parameters are left in an unspecified state.
Note
Not thread-safe; the caller serialises directory access.
Since
0.1.0

Definition at line 275 of file ra8_fs_fat_lfn.c.

References dir_walk_t::cur_lba, internal_dir_find_long_sector(), k_lfn_scan_eod, k_lfn_scan_found, k_lfn_write_max, k_ra8_err_no_mem, k_ra8_err_not_found, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_dir_walk_init_loc(), priv_dir_walk_next_sector(), priv_lfn_reset(), priv_read_sector(), priv_sec_walk(), and priv_utf8_to_utf16().

Referenced by 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_entry_first_cluster()

uint32_t priv_entry_first_cluster ( const uint8_t * entry)

Read the first cluster from a 32-byte directory entry.

Combines the high and low cluster halves into a single 32-bit value (FAT32 layout; high half is 0 on FAT12/16).

Parameters
[in]entry32-byte directory entry.
Returns
First cluster of the file.
Return values
0..UINT32_MAXCluster number.
Precondition
entry is non-NULL and points to 32 readable bytes.
Caller has already filtered LFN / deleted entries.
Postcondition
No state modified.
Result is purely a function of inputs.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 27 of file ra8_fs_fat_file.c.

References k_dir_off_fst_clus_hi, k_dir_off_fst_clus_lo, k_shift_two_bytes, and priv_rd16().

Referenced by internal_enter_subdir(), internal_entry_to_stat(), internal_fat_entry(), internal_open_existing(), internal_rmdir_locate(), and internal_unlink_locate().

◆ priv_entry_set_cluster_size()

void priv_entry_set_cluster_size ( uint8_t * entry,
uint32_t cluster,
uint32_t size )

Patch first-cluster + size back into a 32-byte directory entry.

Inverse of priv_entry_first_cluster; also writes file size.

Parameters
[in,out]entry32-byte directory entry to update.
[in]clusterNew first cluster.
[in]sizeNew file size in bytes.
Precondition
entry is non-NULL and points to 32 writable bytes.
Caller has staged the entry in a sector buffer that will be written back to disk.
Postcondition
entry reflects the new first-cluster and size fields.
No other state modified.
Note
Trivially thread-safe; not reentrant against the same buffer.
Since
0.1.0

Definition at line 35 of file ra8_fs_fat_file.c.

References k_dir_off_file_size, k_dir_off_fst_clus_hi, k_dir_off_fst_clus_lo, k_shift_two_bytes, k_word_mask, priv_wr16(), and priv_wr32().

Referenced by internal_create_new(), internal_fat_mkdir(), internal_fat_trunc_commit(), internal_pack_dot_entry(), and internal_truncate_existing().

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

ra8_err_t priv_exfat_bmp_switch ( const ra8_fs_mount_t * m,
uint64_t lba,
uint64_t * loaded,
uint8_t * sec )

Flush the cached bitmap sector and load lba if it changed.

Writes the dirty cached sector before reading the newly requested one.

Parameters
[in]mMounted exFAT volume.
[in]lbaBitmap sector wanted next.
[in,out]loadedCurrently-cached LBA (UINT32_MAX if none).
[in,out]secCached sector buffer.
Returns
Error code.
Return values
k_ra8_oksec now holds lba.
k_ra8_err_*Backend read/write failure.
Precondition
All pointers are non-NULL.
sec matches loaded on entry.
Postcondition
sec holds lba; the previous sector was written if dirty.
loaded == lba.
Note
Keeps the caller's loop nesting shallow.
Since
0.1.0

Definition at line 192 of file ra8_fs_fat_exfat_write.c.

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

Referenced by priv_exfat_bitmap_clear(), and priv_exfat_bitmap_mark().

◆ priv_exfat_csum32()

uint32_t priv_exfat_csum32 ( uint32_t cs,
const uint8_t * buf,
uint32_t len )

exFAT 32-bit rotate-right-add checksum (boot region + up-case table).

Folds len bytes of buf into the running checksum cs with cs = ror1(cs) + byte per the Microsoft exFAT spec (sections 3.4 and 8.2.2). Shared by the boot-region checksum (which folds surrounding byte ranges to skip the three volatile bytes) and the up-case-table checksum.

Parameters
[in]csRunning checksum (0 to start).
[in]bufBytes to fold in.
[in]lenNumber of bytes to fold.
Returns
Updated checksum.
Return values
0..UINT32_MAXThe rotate-add fold of cs over buf[0..len-1].
Precondition
buf holds at least len bytes.
len is the exact byte count of the span to fold.
Postcondition
No state is modified; the function is pure.
Return value depends only on cs, buf, and len.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 50 of file ra8_fs_fat_exfat_fmt.c.

References k_exfat_fmt_csum_hibit.

Referenced by internal_exfat_write_boot(), internal_exfat_write_boot_tail(), priv_exfat_upcase_checksum(), and priv_exfat_write_upcase().

◆ priv_exfat_dir_next()

ra8_err_t priv_exfat_dir_next ( const ra8_fs_mount_t * m,
exfat_cursor_t * cur,
ra8_fs_dirent_t * out,
bool * out_entry )

Copy the next visible exFAT directory entry from an existing cursor.

Advances the cursor and copies one stable name, attribute mask, and size.

Parameters
[in]mMounted exFAT volume.
[in,out]curIndependent caller-owned directory cursor state.
[out]outStable copied entry value.
[out]out_entryTrue for one copied entry; false at clean end.
Returns
Media, corruption, bound, or clean-end status.
Return values
k_ra8_okOne entry was copied or clean end was reached.
k_ra8_err_*Media, entry-set, name, or cursor-bound failure.
Precondition
Required pointers are non-NULL and cur was initialized for m.
The caller holds the filesystem serialization required by m.
Postcondition
The cursor advances monotonically and no callback is invoked.
Clean end leaves out_entry false without exposing sector scratch.
Note
The caller owns filesystem serialization around this operation.
Since
0.1.0

Definition at line 786 of file ra8_fs_fat_exfat_mutate.c.

References internal_exfat_list_emit(), k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_entry_file, k_exfat_scan_limit, k_ra8_err_invalid_size, k_ra8_err_not_found, k_ra8_ok, priv_exfat_next_entry(), and exfat_cursor_t::scanned.

Referenced by priv_exfat_listdir(), and ra8_fs_dir_next().

◆ priv_exfat_find()

ra8_err_t priv_exfat_find ( const ra8_fs_mount_t * m,
const exfat_dir_t * dir,
const char * path,
uint8_t * out_strm,
uint8_t * out_attr )

Find a name in ONE exFAT directory.

Streams dir's entries, matching each File entry set against path; stops at end-of-directory, the end of the directory's run, or the scan bound. This is a single-directory lookup, not a path resolver – pass a leaf name and the directory it should be in, or use priv_exfat_lookup, which resolves a whole path and then calls this (#605).

Parameters
[in]mMounted exFAT volume.
[in]dirDirectory to search.
[in]pathTarget leaf name, UTF-8; leading slashes are skipped.
[out]out_strmReceives the matched 32-byte Stream-extension entry – first cluster, both lengths and the secondary flags, so a caller decodes the fields it needs rather than every caller paying for another out-parameter.
[out]out_attrLow byte of the File entry's FileAttributes, which is where k_exfat_attr_directory lives. Callers that act on the entry MUST consult it: a directory answers this lookup exactly like a file, and treating one as a file frees its cluster chain (#604).
Returns
Error code.
Return values
k_ra8_okEntry found; outputs populated.
k_ra8_err_not_foundNo matching entry in dir.
k_ra8_err_*Backend read failure.
Precondition
All pointers are non-NULL; m->type is exFAT.
dir locates an existing directory on this volume.
Postcondition
On success out_strm mirrors the on-disk Stream entry.
Scan is bounded by k_exfat_scan_limit entries.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 371 of file ra8_fs_fat_exfat_read.c.

References internal_exfat_match_set(), k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_entry_file, k_exfat_name_cap, k_exfat_off_file_attr, k_exfat_scan_limit, k_ra8_err_no_mem, k_ra8_err_not_found, k_ra8_ok, priv_exfat_cursor_init(), priv_exfat_name_to_units(), priv_exfat_next_entry(), and exfat_cursor_t::scanned.

Referenced by internal_exfat_mkdir_check(), priv_exfat_lookup(), and priv_exfat_rename().

◆ priv_exfat_find_bitmap()

ra8_err_t priv_exfat_find_bitmap ( const ra8_fs_mount_t * m,
uint32_t * out_clus,
uint32_t * out_len )

Locate the allocation-bitmap entry in the exFAT root directory.

Streams the root directory for the 0x81 entry and returns its data run.

Parameters
[in]mMounted exFAT volume.
[out]out_clusFirst cluster of the allocation bitmap.
[out]out_lenBitmap length in bytes.
Returns
Error code.
Return values
k_ra8_okBitmap located.
k_ra8_err_not_foundNo allocation-bitmap entry.
k_ra8_err_*Backend read failure.
Precondition
All pointers are non-NULL; m->type is exFAT.
m->root_cluster is valid.
Postcondition
On success the bitmap location is returned.
No volume state modified.
Note
Reads only the directory chain.
Since
0.1.0

Definition at line 81 of file ra8_fs_fat_exfat_write.c.

References k_exfat_entry_bitmap, k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_scan_limit, k_exfat_strm_off_clus, k_exfat_strm_off_dlen, k_ra8_err_not_found, k_ra8_ok, priv_exfat_cursor_init(), priv_exfat_dir_root(), priv_exfat_next_entry(), priv_rd32(), and exfat_cursor_t::scanned.

Referenced by internal_exfat_dir_alloc(), internal_space_exfat_free(), priv_check_exfat(), and priv_exfat_bitmap_lba().

◆ priv_exfat_format()

ra8_err_t priv_exfat_format ( const ra8_fs_backend_t * backend,
uint64_t total_sectors,
uint32_t bps,
const char * label )

Format the backend as a PC-standard partitioned exFAT volume (#102).

Writes a DOS/MBR partition table at LBA 0 with a single type-0x07 (exFAT/NTFS) partition aligned at ::k_exfat_fmt_part_lba, then lays a complete exFAT volume INSIDE that partition: main + backup boot regions with boot checksums (VolumeLength = partition length, PartitionOffset = k_exfat_fmt_part_lba), the single FAT (bitmap/up-case/root chains), the allocation bitmap with the system clusters pre-marked, the canonical Microsoft up-case table + its checksum, and the root directory entry set. A PC therefore sees a normal partitioned removable disk and the volume mounts with no repair; ra8_fs_mount follows the MBR back to the partition.

Parameters
[in]backendBlock-device backend.
[in]total_sectorsDevice capacity in device sectors.
[in]bpsDevice sector size in bytes (a power of two, 512..4096, validated by the format entry point).
[in]labelOptional volume label (<= 11 chars), may be NULL.
Returns
Error code.
Return values
k_ra8_okA mountable partitioned exFAT volume was written.
k_ra8_err_invalid_sizePartition too small for an exFAT volume.
k_ra8_err_not_supportedBelow the exFAT minimum plus the 1 MiB partition alignment, past the MBR's 32-bit fields (2 TiB at 512-byte sectors), or system cluster chains exceed FAT sector 0.
k_ra8_err_*Backend write failure.
Precondition
backend and backend->write_block are non-NULL.
total_sectors is the actual device capacity reported by the backend.
Postcondition
On k_ra8_ok, LBA 0 holds an MBR and the partition holds a complete exFAT volume.
On failure, partial writes may have been made; the device should be reformatted.
Note
Not thread-safe; serialize with mounts on the same backend.
Since
0.1.0

Definition at line 798 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::heap_offset, internal_exfat_fmt_place(), internal_exfat_geometry(), internal_exfat_write_bitmap(), internal_exfat_write_boot(), internal_exfat_write_fat(), internal_exfat_write_mbr(), internal_exfat_write_root(), k_exfat_fmt_first_clus, k_ra8_err_not_supported, k_ra8_ok, exfat_geom_t::part_lba, priv_exfat_write_upcase(), exfat_geom_t::root_cluster, exfat_geom_t::spc, and exfat_geom_t::upcase_cluster.

◆ priv_exfat_listdir()

ra8_err_t priv_exfat_listdir ( const ra8_fs_mount_t * m,
const exfat_dir_t * dir,
ra8_fs_listdir_cb_t cb,
void * ctx )

Enumerate ONE directory of an exFAT volume.

Walks dir's entry stream; every in-use File entry set yields one callback with the ASCII name (truncated to the local buffer, NUL-terminated), the low attribute byte, and the size. Deleted entries and non-file sets (bitmap, up-case table, label) are skipped. Subdirectories are reported like any other entry set, with k_exfat_attr_directory set in the attribute byte.

Parameters
[in]mMounted exFAT volume.
[in]dirDirectory to enumerate (priv_exfat_dir_root for the root).
[in]cbCallback invoked once per visible entry set.
[in]ctxCookie forwarded to the callback.
Returns
Error code.
Return values
k_ra8_okEnumeration completed (EOD or end of run reached).
k_ra8_err_*Backend read failure.
Precondition
m, dir and cb are non-NULL; mount is exFAT.
dir locates an existing directory on this volume.
Postcondition
cb ran once per in-use entry set.
No volume state modified.
Note
Names longer than the buffer are truncated (still NUL-terminated).
Since
0.1.0

Definition at line 819 of file ra8_fs_fat_exfat_mutate.c.

References ra8_fs_dirent_t::attr, k_ra8_ok, ra8_fs_dirent_t::name, priv_exfat_cursor_init(), priv_exfat_dir_next(), and ra8_fs_dirent_t::size_bytes.

Referenced by internal_listdir_locked().

◆ priv_exfat_name_chunk_eq()

uint8_t priv_exfat_name_chunk_eq ( const uint8_t * entry,
const uint16_t * name,
uint32_t pos,
uint32_t nlen )

Compare one file-name entry's 15 UTF-16 units against a needle.

Case-insensitive under the canonical up-case table (priv_exfat_upcase_unit), which is the fold the exFAT specification defines name matching against. Positions at/after nlen are treated as already matched (tail padding).

It used to compare the low byte of each unit with an ASCII fold and reject any unit whose high byte was set, so a name outside ASCII never matched at all (#606).

Parameters
[in]entry32-byte file-name (0xC1) entry.
[in]nameTarget name as UTF-16 code units.
[in]posIndex of the first name unit this entry covers.
[in]nlenTotal name length in UTF-16 units.
Returns
1 if this slice matches, else 0.
Return values
1Slice matches.
0At least one folded unit differs.
Precondition
entry and name are non-NULL.
name holds at least nlen units.
Postcondition
No state modified.
Inputs are unmodified.
Note
Pure function.
Since
0.1.0

Definition at line 258 of file ra8_fs_fat_exfat_read.c.

References k_exfat_name_off, k_exfat_name_per_entry, priv_exfat_upcase_unit(), and priv_rd16().

Referenced by internal_exfat_match_set(), and internal_exfat_take_set().

◆ priv_exfat_name_hash()

uint16_t priv_exfat_name_hash ( const uint16_t * name,
uint32_t nlen )

Compute the exFAT NameHash for a name in UTF-16 code units.

Hashes the up-cased UTF-16LE name (low then high byte per unit), up-casing through priv_exfat_upcase_unit – the volume's own table, which is what the specification defines the hash over.

Up-casing with an ASCII-only rule, which is what this did, stored a hash no compliant reader recomputes for any name outside ASCII: the host could see the file listed and then fail to find it, because the hash is the index it probes with (#606).

Parameters
[in]nameFile name as UTF-16 code units.
[in]nlenName length in UTF-16 units.
Returns
16-bit name hash.
Return values
0..0xFFFFThe hash value.
Precondition
name is non-NULL and holds at least nlen units.
The volume's up-case table is the canonical one, or the name is ASCII.
Postcondition
No state modified.
Inputs unmodified.
Note
Pure function.
Since
0.1.0

Definition at line 49 of file ra8_fs_fat_exfat_write.c.

References internal_exfat_csum_add(), k_utf_byte_mask, k_utf_byte_shift, and priv_exfat_upcase_unit().

Referenced by internal_exchk_verify_set(), internal_exfat_build_dir_set(), internal_exfat_build_rename_set(), and internal_exfat_build_set().

◆ priv_exfat_name_to_units()

ra8_err_t priv_exfat_name_to_units ( const ra8_fs_mount_t * m,
const char * path,
uint16_t * out,
uint32_t * out_units )

Convert a caller's exFAT name to code units, refusing what will not fold.

The one place an exFAT path becomes the units every on-disk structure counts in. Two refusals, both loud: a name that is not well-formed UTF-8, and a name outside ASCII on a volume whose up-case table this build cannot reproduce – because the NameHash it would store is one the host disagrees with (see priv_exfat_upcase_verify).

Parameters
[in]mMounted exFAT volume.
[in]pathCaller's name, NUL-terminated UTF-8, no leading slash.
[out]outReceives up to k_exfat_name_cap code units.
[out]out_unitsReceives the unit count.
Returns
Error code.
Return values
k_ra8_okConverted.
k_ra8_err_invalid_argpath is not well-formed UTF-8.
k_ra8_err_no_memOver k_exfat_name_cap units.
k_ra8_err_not_supportedNon-ASCII on a volume with a foreign table.
Precondition
All pointers are non-NULL; out holds k_exfat_name_cap units.
m is a mounted exFAT volume.
Postcondition
On failure *out_units is 0.
No volume state is modified.
Note
Pure apart from the outputs.
Since
0.1.0

Definition at line 274 of file ra8_fs_fat_exfat_read.c.

References ra8_fs_mount_t::exfat_upcase_ok, k_exfat_name_cap, k_ra8_err_not_supported, k_ra8_ok, priv_utf16_all_ascii(), and priv_utf8_to_utf16().

Referenced by internal_exfat_enter(), priv_exfat_find(), priv_exfat_mkdir(), priv_exfat_needle_units(), and priv_exfat_open_write().

◆ priv_exfat_needle_units()

ra8_err_t priv_exfat_needle_units ( const ra8_fs_mount_t * m,
const char * name,
uint16_t * out,
uint32_t * out_units,
ra8_err_t too_long )

Convert a leaf name to code units, mapping over-long to too_long.

The exact wrapper the mutate verbs share: priv_exfat_name_to_units plus the one line that turns its k_ra8_err_no_mem – a name past the cap – into whatever "absent" or "unsupported" code the caller reports. Factored out so find_set, rename and the create paths do not each restate it (#606).

Parameters
[in]mMounted exFAT volume.
[in]nameLeaf name, NUL-terminated UTF-8, no leading slash.
[out]outReceives up to k_exfat_name_cap code units.
[out]out_unitsReceives the unit count.
[in]too_longThe code returned when name exceeds the cap.
Returns
Error code.
Return values
k_ra8_okConverted.
too_longname is longer than k_exfat_name_cap.
k_ra8_err_invalid_argname is not well-formed UTF-8.
k_ra8_err_not_supportedNon-ASCII on a volume with a foreign table.
Precondition
All pointers are non-NULL; out holds k_exfat_name_cap units.
m is a mounted exFAT volume.
Postcondition
On failure the unit count is 0.
No volume state is modified.
Note
Pure apart from the outputs.
Since
0.1.0

Definition at line 298 of file ra8_fs_fat_exfat_read.c.

References k_ra8_err_no_mem, and priv_exfat_name_to_units().

Referenced by priv_exfat_find_set(), and priv_exfat_rename().

◆ priv_exfat_next_entry()

ra8_err_t priv_exfat_next_entry ( const ra8_fs_mount_t * m,
exfat_cursor_t * cur,
uint8_t * out )

Fetch the next 32-byte directory entry, following the cluster chain.

Advances across sectors and (via the FAT) clusters. Reports end-of-directory as k_ra8_err_not_found when the chain reaches EOC.

Parameters
[in]mMounted exFAT volume.
[in,out]curCursor; advanced by one entry on success.
[out]outReceives the 32-byte entry.
Returns
Error code.
Return values
k_ra8_okout holds the next entry.
k_ra8_err_not_foundThe directory chain ended (EOC).
k_ra8_err_*Backend or FAT read failure.
Precondition
m, cur, and out are non-NULL.
cur->cluster is a valid directory cluster.
Postcondition
On success cur points at the following entry.
On failure out is undefined.
Note
Re-reads the sector per entry (simple; dir scans are short).
Since
0.1.0

Definition at line 231 of file ra8_fs_fat_exfat_read.c.

References exfat_cursor_t::cluster, exfat_cursor_t::contig_end, exfat_cursor_t::entry_in_cluster, k_exfat_entry_bytes, k_ra8_ok, priv_bps(), priv_byte_copy(), priv_cluster_bytes(), priv_cluster_to_lba(), priv_exfat_step_cluster(), priv_read_sector(), priv_sec_io(), and exfat_cursor_t::scanned.

Referenced by internal_exchk_scan_dir(), internal_exchk_scan_dir_terminal(), internal_exchk_set(), internal_exfat_dir_is_empty(), internal_exfat_dir_relen(), internal_exfat_gather_name(), internal_exfat_gather_set(), internal_exfat_list_emit(), internal_exfat_locate_label(), internal_exfat_match_set(), internal_exfat_take_set(), internal_setattr_exfat(), internal_utime_exfat(), priv_exfat_dir_next(), priv_exfat_drop_set(), priv_exfat_find(), priv_exfat_find_bitmap(), priv_exfat_find_set(), and priv_exfat_upcase_verify().

◆ priv_exfat_open()

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

Open a file (read-only) on a mounted exFAT volume.

Resolves path in the root directory and populates a read handle; write/append modes are rejected (exFAT is read-only here). A name that resolves to a directory is rejected rather than opened as the empty file its zero DataLength would otherwise describe (#604).

Parameters
[in]handleMounted exFAT volume.
[in]pathFlat root-level file name, UTF-8.
[in]modeOpen mode; only k_ra8_fs_mode_read is supported.
[out]out_fileReceives the open handle.
Returns
Error code.
Return values
k_ra8_okFile opened.
k_ra8_err_not_supportedWrite/append requested (exFAT is read-only).
k_ra8_err_invalid_argpath names a directory, not a file.
k_ra8_err_not_foundNo such file.
k_ra8_err_no_memFile table full.
Precondition
handle, path, out_file are non-NULL; mount is exFAT.
handle is in use.
Postcondition
On success *out_file is an in-use read handle.
On failure no file slot is consumed.
Note
Not thread-safe; callers serialize.
Since
0.1.0

Definition at line 474 of file ra8_fs_fat_exfat_read.c.

References internal_exfat_seed_read(), k_exfat_attr_directory, k_exfat_entry_bytes, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_fs_mode_read, k_ra8_ok, priv_alloc_file_slot(), priv_exfat_lookup(), and priv_exfat_open_write().

Referenced by priv_open_locked().

◆ priv_exfat_rename()

ra8_err_t priv_exfat_rename ( const ra8_fs_mount_t * m,
const char * old_path,
const char * new_path )

Rename a root-level file on an exFAT volume, at any storable length.

Rewrites the whole entry set under the new name: the Stream entry's NameLength + NameHash, a run of one Name entry per fifteen UTF-16 units, the File entry's SecondaryCount, and the recomputed SetChecksum. When the new name keeps the entry count the set is rewritten in place; when it needs more or fewer Name entries the set is relocated to a fresh run of slots (growing the directory if needed) and the old set is then retired, so names up to k_exfat_name_cap units – the same range ra8_fs_write_file() writes – all rename. The data itself never moves: FirstCluster, DataLength and the timestamps ride across untouched.

Parameters
[in]mMounted exFAT volume.
[in]old_pathExisting root-level name.
[in]new_pathReplacement name (must not exist).
Returns
Error code.
Return values
k_ra8_okFile renamed.
k_ra8_err_not_foundold_path does not exist.
k_ra8_err_existsnew_path already resolves.
k_ra8_err_invalid_argnew_path is empty, over the name cap, or not well-formed UTF-8.
k_ra8_err_not_supportedThe paths cross directories, or a non-ASCII name on a volume with a foreign up-case table.
k_ra8_err_no_memThe directory cannot grow to hold a longer set.
Precondition
m and both paths are non-NULL; mount is exFAT.
The file is not open.
Postcondition
new_path resolves to the same data; old_path is gone.
File attributes, size, and clusters are unchanged.
Note
Root-directory namespace only.
Since
0.1.0

Definition at line 593 of file ra8_fs_fat_exfat_mutate.c.

References internal_exfat_build_rename_set(), internal_exfat_place_rename(), internal_exfat_rename_prepare(), k_exfat_attr_read_only, k_exfat_entry_bytes, k_exfat_max_set_bytes, k_exfat_name_cap, k_exfat_off_file_attr, k_exfat_set_max_entries, k_ra8_err_access_denied, k_ra8_err_exists, k_ra8_err_invalid_arg, k_ra8_ok, priv_exfat_find(), priv_exfat_find_set(), and priv_exfat_needle_units().

◆ priv_exfat_set_checksum()

uint16_t priv_exfat_set_checksum ( const uint8_t * set,
uint32_t bytes )

Compute the SetChecksum over a built directory entry set.

Folds every byte except the File entry's checksum field (bytes 2-3).

Parameters
[in]setContiguous entry-set bytes (File + Stream + Name entries).
[in]bytesTotal byte count of the set.
Returns
16-bit SetChecksum.
Return values
0..0xFFFFThe checksum.
Precondition
set is non-NULL and at least bytes long.
bytes is a multiple of the entry size.
Postcondition
No state modified.
set is unmodified.
Note
Pure function.
Since
0.1.0

Definition at line 65 of file ra8_fs_fat_exfat_write.c.

References internal_exfat_csum_add(), and k_exfat_off_file_csum.

Referenced by internal_exchk_verify_set(), internal_exfat_build_dir_set(), internal_exfat_build_rename_set(), internal_exfat_build_set(), internal_exfat_dir_relen(), internal_setattr_exfat(), internal_utime_exfat(), and priv_exfat_flush_set().

◆ priv_exfat_unlink()

ra8_err_t priv_exfat_unlink ( const ra8_fs_mount_t * m,
const char * path )

Delete a file on an exFAT volume, at any depth.

Resolves the path's parent, then hands the leaf to priv_exfat_unlink_at: the entry set is located, every entry's in-use bit (bit 7 of the entry type) is cleared, and the clusters are freed in the allocation bitmap. A set carrying k_exfat_attr_directory is refused: freeing a directory's run would strand every entry inside it (#604).

Parameters
[in]mMounted exFAT volume.
[in]pathFile path, UTF-8, nested or root-level.
Returns
Error code.
Return values
k_ra8_okFile unlinked.
k_ra8_err_invalid_argpath names a directory or the volume root.
k_ra8_err_not_foundNo such file, or a component is missing.
k_ra8_err_*Directory or bitmap write failure.
Precondition
m and path are non-NULL; mount is exFAT.
The file is not open.
Postcondition
The name no longer resolves; its clusters are free.
Other directory entries are untouched.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 383 of file ra8_fs_fat_exfat_mutate.c.

References k_ra8_err_invalid_arg, k_ra8_ok, priv_exfat_resolve_parent(), priv_exfat_unlink_at(), and priv_strlen().

◆ priv_exfat_upcase_checksum()

uint32_t priv_exfat_upcase_checksum ( void )

Rotate-add checksum of the up-case table this build embeds.

The same 32-bit fold priv_exfat_write_upcase records in the volume's up-case directory entry, computed over the in-flash table. Having it as a function rather than a constant is the point: a constant could drift from the bytes it claims to describe, and this cannot.

Returns
Checksum of k_exfat_fmt_upc_std_bytes table bytes.
Return values
0xE619D30DThe canonical Microsoft table, which is what is embedded.
Precondition
None.
The caller compares it against a volume's TableChecksum.
Postcondition
No state modified.
The result is the same on every call.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 471 of file ra8_fs_fat_exfat_upcase.c.

References k_exfat_fmt_upc_std_bytes, priv_exfat_csum32(), and s_exfat_upcase.

Referenced by priv_exfat_upcase_verify().

◆ priv_exfat_upcase_unit()

uint16_t priv_exfat_upcase_unit ( uint16_t unit)

Fold a UTF-16 code unit through the canonical exFAT up-case table.

The exFAT specification defines both NameHash and name comparison over the UP-CASED name, using the table the volume carries. This build embeds and writes the canonical Microsoft table – the one mkfs.exfat and the Windows formatter emit, checksum 0xE619D30D – and this is the reader for it, so the hash stored on create is the hash a host recomputes.

Look-up walks the compressed table rather than expanding it, because the expansion is 128 KiB. The ASCII range short-circuits to priv_ascii_upper, which the table agrees with for every one of those 128 units.

A surrogate unit folds to itself: the table covers the BMP, and a supplementary code point has no simple case mapping inside a single unit.

Parameters
[in]unitUTF-16 code unit to fold.
Returns
The up-cased unit.
Return values
unitNo mapping applies (identity run, or past the table).
otherThe table's mapping for unit.
Precondition
None; every 16-bit value is a legal input.
The caller wants the VOLUME's fold and has checked ra8_fs_mount_t::exfat_upcase_ok, or is folding a FAT long name.
Postcondition
No state modified.
The result depends only on unit and the embedded table.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 435 of file ra8_fs_fat_exfat_upcase.c.

References k_exfat_upc_run_tag, k_exfat_upc_words, k_utf_ascii_max, priv_ascii_upper(), priv_rd16(), and s_exfat_upcase.

Referenced by priv_exfat_name_chunk_eq(), priv_exfat_name_hash(), and priv_utf16_ieq().

◆ priv_exfat_upcase_verify()

void priv_exfat_upcase_verify ( ra8_fs_mount_t * m)

Decide whether this build's fold matches the mounted volume's table.

Walks the root directory for the up-case-table entry (0x82) and compares its TableChecksum against priv_exfat_upcase_checksum(). The answer lands in ra8_fs_mount_t::exfat_upcase_ok and decides one thing: whether a name containing anything outside ASCII may be created, renamed or looked up on this volume at all. An ASCII-only name folds identically under every conforming table, so it is never affected.

Refusing the operation is the point. Hashing a name with a fold the volume does not use stores a NameHash the host disagrees with, and a host that cannot match the hash cannot find a file it can see listed – a disagreement with the on-disk format rather than a limitation of this API (#606).

A missing entry or a read error is treated exactly like a mismatch, so a volume this function could not interrogate degrades to ASCII-only names rather than failing to mount.

Parameters
[in,out]mMount whose exFAT geometry is already populated.
Returns
Nothing.
Precondition
m is non-NULL and its exFAT region geometry is valid.
The backend is bound and partition_base_lba is final.
Postcondition
m->exfat_upcase_ok is 0 or 1 and is never left unwritten.
No volume state is modified.
Note
Not thread-safe; callers serialise mount operations.
Since
0.1.0

Definition at line 133 of file ra8_fs_fat_exfat_read.c.

References ra8_fs_mount_t::exfat_upcase_ok, k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_entry_upcase, k_exfat_scan_limit, k_exfat_upc_off_csum, k_ra8_ok, priv_exfat_next_entry(), priv_exfat_upcase_checksum(), priv_rd32(), ra8_fs_mount_t::root_cluster, and exfat_cursor_t::scanned.

Referenced by internal_exfat_parse().