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

FAT open / close path and directory resolution. 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_file.c:

Go to the source code of this file.

Enumerations

enum  ra8_fs_path_cap_t : uint32_t { k_path_max_depth = 32U }
 Path-resolution caps (statically bound the component walk). More...

Functions

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.
void priv_fat_entry_apply_attr (uint8_t *entry, uint8_t set_mask, uint8_t clear_mask)
 Clear then set attribute bits in a 32-byte FAT directory entry.
static ra8_err_t internal_truncate_existing (const ra8_fs_mount_t *handle, ra8_fs_file_t *f, uint64_t lba, uint32_t off)
 Truncate an existing file's chain and zero its dir-entry size.
static ra8_err_t internal_open_existing (ra8_fs_mount_t *handle, const uint8_t *entry, uint64_t lba, uint32_t off, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
 Populate a fresh file handle from an existing on-disk dir entry.
static void internal_init_new_file (ra8_fs_file_t *f, ra8_fs_mount_t *handle, ra8_fs_mode_t mode, uint64_t free_lba, uint32_t free_off)
 Populate a freshly allocated file slot for an empty new file.
static ra8_err_t internal_enter_subdir (const ra8_fs_mount_t *m, const dir_loc_t *cur, const char *comp, uint32_t len, dir_loc_t *out)
 Descend into the named directory component within cur.
ra8_err_t priv_resolve_parent (const ra8_fs_mount_t *m, const char *path, dir_loc_t *out_parent, const char **out_leaf)
 Resolve all-but-the-last path component to a parent directory.
ra8_err_t priv_resolve_dir (const ra8_fs_mount_t *m, const char *path, dir_loc_t *out)
 Resolve a whole path to the directory it names.
static ra8_err_t internal_create_new (ra8_fs_mount_t *handle, const dir_loc_t *parent, const char *leaf, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
 Carve a fresh directory entry for leaf and populate a file handle.
ra8_err_t priv_open_locked (ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
 Open a file by path – the guarded body of ra8_fs_open().
static ra8_err_t internal_close_stamp (ra8_fs_file_t *file)
 Stamp the final modification time of a file that was written.
ra8_err_t priv_close_locked (ra8_fs_file_t *file)
 Close an open file – the guarded body of ra8_fs_close().
ra8_err_t ra8_fs_open (ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
 Open or create a file by path, 8.3 or long.
ra8_err_t ra8_fs_close (ra8_fs_file_t *file)
 Close an open file, stamping its final modification time.

Detailed Description

FAT open / close path and directory resolution.

Directory resolution (parent/dir), file creation, and the public open/close entry points for the ra8_fs FAT adapter.

Since
0.1.0

Definition in file ra8_fs_fat_file.c.

Enumeration Type Documentation

◆ ra8_fs_path_cap_t

enum ra8_fs_path_cap_t : uint32_t

Path-resolution caps (statically bound the component walk).

Enumerator
k_path_max_depth 

Max nested directory components per path.

Definition at line 244 of file ra8_fs_fat_file.c.

Function Documentation

◆ internal_close_stamp()

ra8_err_t internal_close_stamp ( ra8_fs_file_t * file)
static

Stamp the final modification time of a file that was written.

The close half of #601. ra8_fs_write() already advances the modification time on every call, which is what protects a file whose writer never gets to close it; this is the stamp that says when the file was FINISHED, which is the one a host displays and a sync tool compares. Also flushes the volume's FSInfo free count, because a file that has just stopped growing is exactly when the count is worth committing (#607).

Parameters
[in]fileHandle being closed, still marked in use.
Returns
Error code.
Return values
k_ra8_okStamped and flushed, or there was nothing to do.
k_ra8_err_*Backend read/write failure.
Precondition
file is non-NULL and file->dirty is 1.
file->dir_entry_lba / dir_entry_idx locate its directory entry.
Postcondition
On success the entry's DIR_WrtTime / DIR_WrtDate name the close.
On success the volume's FSInfo matches the tracked free count.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 520 of file ra8_fs_fat_file.c.

References k_ra8_fs_type_exfat, k_ra8_ok, priv_exfat_flush_set(), priv_fat_entry_stamp_write(), priv_fsinfo_flush(), priv_read_sector(), priv_sec_walk(), priv_write_sector(), and ra8_fs_mount_t::type.

Referenced by priv_close_locked().

◆ internal_create_new()

ra8_err_t internal_create_new ( ra8_fs_mount_t * handle,
const dir_loc_t * parent,
const char * leaf,
ra8_fs_mode_t mode,
ra8_fs_file_t ** out_file )
static

Carve a fresh directory entry for leaf and populate a file handle.

Reserves the directory slots the name needs – one for an 8.3 name, a whole VFAT chain plus a generated ~N alias for anything else – takes a file slot from the static pool, commits an empty archive entry, and initialises the handle to the empty-file state. The reservation runs before anything is written, so a directory with no room leaves the volume untouched. On any failure after the file slot is taken it is left unreleased, which costs nothing: the slot is not in use, so the next allocation attempt finds it again.

Parameters
[in,out]handleMount on which to create the file.
[in]parentDirectory in which to create the entry.
[in]leafCaller's leaf name, of any supported length.
[in]modeOpen mode to record into the returned handle.
[out]out_fileReceives the populated file handle on success.
Returns
Error code.
Return values
k_ra8_okNew file created and opened; out_file populated.
k_ra8_err_invalid_argleaf cannot be stored under any encoding.
k_ra8_err_no_memNo directory slots, or the file table is full.
k_ra8_err_*Backend read/write error.
Precondition
All pointers are non-NULL; handle is a mounted volume.
leaf is the leaf component of the caller's path, without slashes.
Postcondition
On k_ra8_ok, *out_file is in-use with the directory entry on disk.
On failure, no complete directory entry is written for leaf.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 419 of file ra8_fs_fat_file.c.

References internal_init_new_file(), k_dir_off_attr, k_ra8_err_no_mem, k_ra8_fs_attr_archive, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_alloc_file_slot(), priv_dir_commit(), priv_dir_reserve(), priv_entry_set_cluster_size(), and priv_fat_entry_stamp_create().

Referenced by priv_open_locked().

◆ internal_enter_subdir()

ra8_err_t internal_enter_subdir ( const ra8_fs_mount_t * m,
const dir_loc_t * cur,
const char * comp,
uint32_t len,
dir_loc_t * out )
static

Descend into the named directory component within cur.

Packs the len-byte component to an 8.3 name, looks it up in cur, requires the matched entry to carry the directory attribute, and returns its first cluster as a subdirectory location.

Parameters
[in]mMount providing geometry and backend.
[in]curDirectory the component is looked up in.
[in]compPointer to the component characters (not NUL-terminated).
[in]lenNumber of component characters.
[out]outReceives the subdirectory location on success.
Returns
Error code.
Return values
k_ra8_okComponent resolved to a subdirectory.
k_ra8_err_invalid_argComponent is not 8.3 or is not a directory.
k_ra8_err_not_foundNo such entry in cur.
k_ra8_err_protocol_errorDirectory entry has no data cluster.
k_ra8_err_*Backend error.
Precondition
m, cur, comp, and out are non-NULL.
len is the exact component length (no trailing slash).
Postcondition
On success out locates the subdirectory.
On failure out is unmodified.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 278 of file ra8_fs_fat_file.c.

References dir_loc_t::cluster, dir_loc_t::is_root, k_cluster_first_data, k_dir_off_attr, k_lfn_utf8_cap, k_ra8_err_invalid_arg, k_ra8_err_protocol_error, k_ra8_fs_attr_directory, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_dir_lookup_any(), and priv_entry_first_cluster().

Referenced by priv_resolve_dir(), and priv_resolve_parent().

◆ internal_init_new_file()

void internal_init_new_file ( ra8_fs_file_t * f,
ra8_fs_mount_t * handle,
ra8_fs_mode_t mode,
uint64_t free_lba,
uint32_t free_off )
static

Populate a freshly allocated file slot for an empty new file.

Sets every field of f to the empty-file initial state: no clusters, zero size/offset, the dir-entry location, the open mode, and the in-use flag. Extracted from priv_create_new.

Parameters
[out]fFile slot to initialise.
[in]handleOwning mount.
[in]modeOpen mode to record.
[in]free_lbaSector of the file's directory entry.
[in]free_offByte offset of the directory entry within the sector.
Returns
Nothing.
Precondition
f and handle are non-NULL.
free_lba and free_off identify an already-written directory entry slot.
Postcondition
f->in_use is 1 and every cluster, size, offset, and position field is zero.
f->dir_entry_lba and f->dir_entry_idx reflect the on-disk slot location.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 222 of file ra8_fs_fat_file.c.

References ra8_fs_file_t::cur_cluster, ra8_fs_file_t::dir_entry_idx, ra8_fs_file_t::dir_entry_lba, ra8_fs_file_t::dirty, ra8_fs_file_t::first_cluster, ra8_fs_file_t::in_use, ra8_fs_file_t::mode, ra8_fs_file_t::mount, ra8_fs_file_t::no_fat_chain, ra8_fs_file_t::offset, ra8_fs_file_t::size_bytes, ra8_fs_file_t::walk_cache_cluster, and ra8_fs_file_t::walk_cache_idx.

Referenced by internal_create_new().

◆ internal_open_existing()

ra8_err_t internal_open_existing ( ra8_fs_mount_t * handle,
const uint8_t * entry,
uint64_t lba,
uint32_t off,
ra8_fs_mode_t mode,
ra8_fs_file_t ** out_file )
static

Populate a fresh file handle from an existing on-disk dir entry.

Allocates a file slot, copies the entry's first cluster / size into it, sets the requested mode, and applies truncate/append behaviour for write/append modes.

Parameters
[in,out]handleMount on which the file lives.
[in]entry32-byte directory entry already on disk.
[in]lbaSector LBA holding the directory entry.
[in]offByte offset of the entry within the sector.
[in]modeOpen mode (read / write / append).
[out]out_fileReceives the populated file handle.
Returns
Error code.
Return values
k_ra8_okFile handle ready.
k_ra8_err_invalid_argentry carries ATTR_DIRECTORY.
k_ra8_err_no_memFile table is full.
k_ra8_err_*Backend error during truncation.
Precondition
All pointers are non-NULL; mount is in use.
entry came from a successful priv_dir_find for lba/off.
Postcondition
On success, *out_file is in use and configured for mode.
On failure, the file slot is marked free again.
A directory entry is rejected before any slot or chain is touched.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 140 of file ra8_fs_fat_file.c.

References ra8_fs_file_t::cur_cluster, ra8_fs_file_t::dir_entry_idx, ra8_fs_file_t::dir_entry_lba, ra8_fs_file_t::dirty, ra8_fs_file_t::first_cluster, ra8_fs_file_t::in_use, internal_truncate_existing(), k_dir_off_attr, k_dir_off_file_size, k_ra8_err_access_denied, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_fs_attr_directory, k_ra8_fs_attr_read_only, k_ra8_fs_mode_append, k_ra8_fs_mode_read, k_ra8_fs_mode_write, k_ra8_ok, ra8_fs_file_t::mode, ra8_fs_file_t::mount, ra8_fs_file_t::no_fat_chain, ra8_fs_file_t::offset, priv_alloc_file_slot(), priv_entry_first_cluster(), priv_rd32(), ra8_fs_file_t::size_bytes, ra8_fs_file_t::walk_cache_cluster, and ra8_fs_file_t::walk_cache_idx.

Referenced by priv_open_locked().

◆ internal_truncate_existing()

ra8_err_t internal_truncate_existing ( const ra8_fs_mount_t * handle,
ra8_fs_file_t * f,
uint64_t lba,
uint32_t off )
static

Truncate an existing file's chain and zero its dir-entry size.

Frees the cluster chain, resets the in-memory file state, then writes a fresh dir entry with cluster=0 and size=0.

Parameters
[in,out]handleMount providing FAT access.
[in,out]fFile state to reset.
[in]lbaSector LBA holding the directory entry.
[in]offByte offset of the entry within the sector.
Returns
Error code.
Return values
k_ra8_okFile truncated successfully.
k_ra8_err_*Backend or FAT error.
Precondition
All pointers are non-NULL; mount/file are in use.
lba/off identify the file's directory entry.
Postcondition
On success, the file occupies zero clusters and its size is 0.
On failure, on-disk state may be partially updated.
Note
Thread-safety inherited from the backend.
Since
0.1.0

Definition at line 75 of file ra8_fs_fat_file.c.

References ra8_fs_file_t::cur_cluster, ra8_fs_file_t::first_cluster, k_cluster_first_data, k_ra8_fs_attr_archive, k_ra8_ok, ra8_fs_file_t::offset, priv_entry_set_cluster_size(), priv_fat_entry_apply_attr(), priv_fat_entry_stamp_write(), priv_free_chain(), priv_read_sector(), priv_sec_walk(), priv_write_sector(), ra8_fs_file_t::size_bytes, ra8_fs_file_t::walk_cache_cluster, and ra8_fs_file_t::walk_cache_idx.

Referenced by internal_open_existing().

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

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

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

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

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

Definition at line 44 of file ra8_fs_fat_file.c.

References k_dir_off_attr.

Referenced by internal_setattr_fat(), and internal_truncate_existing().

◆ priv_open_locked()

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

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

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

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

Definition at line 455 of file ra8_fs_fat_file.c.

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

Referenced by internal_write_file_locked(), and ra8_fs_open().

◆ priv_resolve_dir()

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

Resolve a whole path to the directory it names.

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

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

Definition at line 357 of file ra8_fs_fat_file.c.

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

◆ priv_resolve_parent()

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

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

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

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

Definition at line 319 of file ra8_fs_fat_file.c.

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

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

◆ ra8_fs_close()

ra8_err_t ra8_fs_close ( ra8_fs_file_t * file)
nodiscard

Close an open file, stamping its final modification time.

File contents are never buffered – ra8_fs_write() has already put every byte on the volume – so what closing does is metadata. A handle that was written through gets DIR_WrtTime / DIR_WrtDate set to the moment of the close (the time a host shows as "modified" and a sync tool compares), and the volume's FAT32 FSInfo free count is committed. A handle opened read-only, or write-opened and never written, touches nothing.

Parameters
[in,out]fileHandle from ra8_fs_open().
Return values
k_ra8_okClosed.
k_ra8_err_null_ptrfile is NULL.
k_ra8_err_*The timestamp or FSInfo write failed. The handle is released anyway – a close that could be refused would leak the slot.
Postcondition
The file slot is free for reuse whatever the metadata write did.
Since
0.1.0

Definition at line 578 of file ra8_fs_fat_file.c.

References priv_close_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_close().

Referenced by demo_read_test_file(), demo_read_verify(), eoh_provision_or_halt(), etoc_provision_one(), fileops_expect_absent(), fileops_read_back(), fs_fmt_create_and_verify(), fs_fmt_rename_and_verify(), imp_read_cache(), internal_close(), internal_compute_source_key(), internal_demo_read_once(), internal_file_exists(), internal_mkfontimg_verify(), internal_mkfontimg_write(), internal_native_close(), internal_pc_font_or_halt(), internal_pc_read_cache(), internal_ra8_io_roundtrip_read_verify(), internal_ra8_io_roundtrip_write_subdir(), internal_ra8_vfs_compress_load_blob(), internal_ra8_vfs_compress_store_blob(), internal_read_font(), internal_read_stamp(), internal_read_whole_file(), internal_stream_book(), internal_stream_open(), internal_swap_vfs_read_verify(), internal_swap_vfs_write(), internal_verify_book(), internal_verify_book_reopen(), ra8_fs_close(), ra8_io_roundtrip_read_verify(), ra8_io_roundtrip_subdir_file(), rabook_import_compile_adapter(), sd_demo_read_payload(), sd_demo_write_payload(), sdhi_demo_read_and_verify(), sdhi_demo_write_payload(), and sh_sd_book_close().

◆ ra8_fs_open()

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

Open or create a file by path, 8.3 or long.

A path that resolves to a DIRECTORY is rejected in every mode. In write mode that rejection is load-bearing: the truncate step would free the cluster chain holding the directory's contents and leave every file inside it unreachable. In read mode it prevents handing back the zero-byte handle a directory's DIR_FileSize of 0 would otherwise describe.

All three modes work on every filesystem this adapter mounts, exFAT included (#602). An exFAT write grows the file one cluster at a time out of the allocation bitmap, so the size a caller can create is bounded by the volume's free space rather than by RAM, and a fragmented volume is written the way the format intends: the entry set keeps NoFatChain while the run stays contiguous and drops it – materialising a real FAT chain over the clusters already allocated – the first time the next cluster is not the successor of the last.

Parameters
[in]handleMount handle.
[in]pathPath from the volume root, e.g. "HELLO.TXT" or "/Reading List/Chapter One.txt". Any component may be a long name of up to 247 characters.
[in]modek_ra8_fs_mode_read, _write, or _append.
[out]out_filePopulated file handle on success.
Return values
k_ra8_okFile opened.
k_ra8_err_null_ptrAny pointer arg is NULL.
k_ra8_err_invalid_argpath names a directory (any mode), or a new name is empty, holds a character no name may carry, or is longer than the volume allows – 247 characters on FAT, 64 on exFAT.
k_ra8_err_not_foundRead mode and path doesn't exist.
k_ra8_err_access_deniedA writing mode (_write / _append) on a file whose read-only attribute is set; a read open of the same file succeeds.
k_ra8_err_no_memNo free file slot, no directory slot, or the volume has no free cluster.
k_ra8_err_no_dataWrite mode failed to allocate cluster.
k_ra8_err_not_supportedAn exFAT entry set larger than this adapter rewrites (a name over 64 chars written by another implementation).
Precondition
handle->in_use == 1.
Postcondition
On success, out_file->in_use == 1 and offset is at file start (read/write) or end (append).
On k_ra8_err_invalid_arg the volume is unchanged.
Note
Write mode TRUNCATES in place on both filesystems: the name keeps its directory entry (and its creation stamp) and only the contents go.
The read-only attribute is honored HERE, at open time (like POSIX/DOS): a handle already opened for writing keeps writing even if the file is marked read-only afterwards via ra8_fs_set_attr(). A content write also sets the archive attribute.
See also
ra8_fs_rmdir() The verb for removing a directory.
ra8_fs_set_attr() Sets / clears the read-only attribute this honors.
Since
0.1.0

Definition at line 569 of file ra8_fs_fat_file.c.

References priv_lock_acquire(), priv_lock_release(), priv_open_locked(), and ra8_fs_open().

Referenced by demo_read_test_file(), demo_read_verify(), eoh_provision_or_halt(), etoc_provision_one(), fileops_expect_absent(), fileops_read_back(), fs_fmt_create_and_verify(), fs_fmt_rename_and_verify(), imp_read_cache(), internal_compute_source_key(), internal_file_exists(), internal_mkfontimg_verify(), internal_mkfontimg_write(), internal_native_open(), internal_open_or_provision(), internal_pc_font_or_halt(), internal_pc_read_cache(), internal_read_stamp(), internal_read_whole_file(), internal_stream_book(), internal_stream_open(), internal_verify_book_reopen(), ra8_fs_open(), sd_demo_read_payload(), sd_demo_write_payload(), and sh_sd_book_open().