|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
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"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. | |
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.
Definition in file ra8_fs_fat_file.c.
| 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.
|
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).
| [in] | file | Handle being closed, still marked in use. |
| k_ra8_ok | Stamped and flushed, or there was nothing to do. |
| k_ra8_err_* | Backend read/write failure. |
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().
|
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.
| [in,out] | handle | Mount on which to create the file. |
| [in] | parent | Directory in which to create the entry. |
| [in] | leaf | Caller's leaf name, of any supported length. |
| [in] | mode | Open mode to record into the returned handle. |
| [out] | out_file | Receives the populated file handle on success. |
| k_ra8_ok | New file created and opened; out_file populated. |
| k_ra8_err_invalid_arg | leaf cannot be stored under any encoding. |
| k_ra8_err_no_mem | No directory slots, or the file table is full. |
| k_ra8_err_* | Backend read/write error. |
handle is a mounted volume. leaf is the leaf component of the caller's path, without slashes. *out_file is in-use with the directory entry on disk. leaf.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().
|
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.
| [in] | m | Mount providing geometry and backend. |
| [in] | cur | Directory the component is looked up in. |
| [in] | comp | Pointer to the component characters (not NUL-terminated). |
| [in] | len | Number of component characters. |
| [out] | out | Receives the subdirectory location on success. |
| k_ra8_ok | Component resolved to a subdirectory. |
| k_ra8_err_invalid_arg | Component is not 8.3 or is not a directory. |
| k_ra8_err_not_found | No such entry in cur. |
| k_ra8_err_protocol_error | Directory entry has no data cluster. |
| k_ra8_err_* | Backend error. |
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().
|
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.
| [out] | f | File slot to initialise. |
| [in] | handle | Owning mount. |
| [in] | mode | Open mode to record. |
| [in] | free_lba | Sector of the file's directory entry. |
| [in] | free_off | Byte offset of the directory entry within the sector. |
f and handle are non-NULL. free_lba and free_off identify an already-written directory entry slot. 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.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().
|
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.
| [in,out] | handle | Mount on which the file lives. |
| [in] | entry | 32-byte directory entry already on disk. |
| [in] | lba | Sector LBA holding the directory entry. |
| [in] | off | Byte offset of the entry within the sector. |
| [in] | mode | Open mode (read / write / append). |
| [out] | out_file | Receives the populated file handle. |
| k_ra8_ok | File handle ready. |
| k_ra8_err_invalid_arg | entry carries ATTR_DIRECTORY. |
| k_ra8_err_no_mem | File table is full. |
| k_ra8_err_* | Backend error during truncation. |
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().
|
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.
| [in,out] | handle | Mount providing FAT access. |
| [in,out] | f | File state to reset. |
| [in] | lba | Sector LBA holding the directory entry. |
| [in] | off | Byte offset of the entry within the sector. |
| k_ra8_ok | File truncated successfully. |
| k_ra8_err_* | Backend or FAT error. |
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().
| 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.
| [in,out] | file | Handle returned by priv_open_locked / ra8_fs_open(). |
| k_ra8_ok | File closed. |
| k_ra8_err_null_ptr | file was NULL. |
| k_ra8_err_* | The final modification-time stamp or the FSInfo writeback failed; the handle is released anyway. |
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().
| 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).
| [in] | entry | 32-byte directory entry. |
| 0..UINT32_MAX | Cluster number. |
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().
| 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.
| [in,out] | entry | 32-byte directory entry to update. |
| [in] | cluster | New first cluster. |
| [in] | size | New file size in bytes. |
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().
| 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.
| [in,out] | entry | 32-byte directory entry to update. |
| [in] | set_mask | Attribute bits to set. |
| [in] | clear_mask | Attribute bits to clear. |
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().
| 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.
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated path. |
| [in] | mode | Open mode. |
| [out] | out_file | Receives the open file handle. |
| k_ra8_ok | File opened. |
| k_ra8_err_null_ptr | Any pointer argument was NULL. |
| k_ra8_err_* | As documented for ra8_fs_open(). |
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().
| 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.
| [in] | m | Mount providing geometry and backend. |
| [in] | path | NUL-terminated directory path. |
| [out] | out | Receives the resolved directory location. |
| k_ra8_ok | Directory resolved. |
| k_ra8_err_invalid_arg | A component is not a directory / not 8.3. |
| k_ra8_err_not_found | A component does not exist. |
| k_ra8_err_* | Backend error. |
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().
| 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.
| [in] | m | Mount providing geometry and backend. |
| [in] | path | NUL-terminated path (leading slashes ignored). |
| [out] | out_parent | Receives the resolved parent directory location. |
| [out] | out_leaf | Receives a pointer into path at the final component. |
| k_ra8_ok | Parent resolved; out_leaf set. |
| k_ra8_err_invalid_arg | A component is not 8.3, or the path is too deep. |
| k_ra8_err_not_found | An intermediate component does not exist. |
| k_ra8_err_* | Backend error. |
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().
|
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.
| [in,out] | file | Handle from ra8_fs_open(). |
| k_ra8_ok | Closed. |
| k_ra8_err_null_ptr | file 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. |
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().
|
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.
| [in] | handle | Mount handle. |
| [in] | path | Path 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] | mode | k_ra8_fs_mode_read, _write, or _append. |
| [out] | out_file | Populated file handle on success. |
| k_ra8_ok | File opened. |
| k_ra8_err_null_ptr | Any pointer arg is NULL. |
| k_ra8_err_invalid_arg | path 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_found | Read mode and path doesn't exist. |
| k_ra8_err_access_denied | A 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_mem | No free file slot, no directory slot, or the volume has no free cluster. |
| k_ra8_err_no_data | Write mode failed to allocate cluster. |
| k_ra8_err_not_supported | An exFAT entry set larger than this adapter rewrites (a name over 64 chars written by another implementation). |
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().