|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
FAT listdir / unlink / rename directory-entry operations. More...
#include <stddef.h>#include <stdint.h>#include <string.h>#include "ra8_attributes.h"#include "ra8_fs.h"#include "ra8_fs_fat_internal.h"Go to the source code of this file.
Data Structures | |
| struct | ra8_fs_dir_private_t |
| Private state stored inside one public opaque directory cursor. More... | |
Functions | |
| static uint8_t | internal_listdir_visit_sector (const ra8_fs_mount_t *m, const uint8_t *buf, lfn_state_t *lfn, ra8_fs_listdir_cb_t cb, void *ctx) |
| Visit every visible entry in one already-loaded directory sector. | |
| static ra8_err_t | internal_listdir_locked (const ra8_fs_mount_t *handle, const char *path, ra8_fs_listdir_cb_t cb, void *ctx) |
| Enumerate a directory – the guarded body of ra8_fs_listdir(). | |
| static ra8_err_t | internal_fat_dir_advance_sector (ra8_fs_dir_private_t *state) |
| Advance an independent FAT cursor to its next directory sector. | |
| static void | internal_fat_dir_scan_sector (ra8_fs_dir_private_t *state, const uint8_t *sector, ra8_fs_dirent_t *out, bool *out_entry) |
| Scan one already-read sector's remaining entries for one visible entry. | |
| static ra8_err_t | internal_fat_dir_next (ra8_fs_dir_private_t *state, ra8_fs_dirent_t *out, bool *out_entry) |
| Copy one visible FAT entry from an independent cursor. | |
| static ra8_err_t | internal_dir_open_locked (ra8_fs_mount_t *handle, const char *path, ra8_fs_dir_private_t *state) |
| Resolve and initialize one private filesystem cursor. | |
| static ra8_err_t | internal_unlink_locate (const ra8_fs_mount_t *handle, const char *path, dir_target_t *out, uint32_t *out_cluster) |
| Resolve a path to a deletable FILE's entry and first cluster. | |
| static ra8_err_t | internal_unlink_locked (const ra8_fs_mount_t *handle, const char *path) |
| Delete a file – the guarded body of ra8_fs_unlink(). | |
| static ra8_err_t | internal_rename_prepare (const ra8_fs_mount_t *handle, const char *old_path, const char *new_path, dir_loc_t *out_parent, const char **out_old, const char **out_new) |
| Resolve a rename's old/new paths to a shared parent and two leaves. | |
| static ra8_err_t | internal_fat_rename (const ra8_fs_mount_t *handle, const char *old_path, const char *new_path) |
| Rename by writing the new entry first, then taking the old one away. | |
| static ra8_err_t | internal_rename_locked (const ra8_fs_mount_t *handle, const char *old_path, const char *new_path) |
| Rename – the guarded body of ra8_fs_rename(). | |
| ra8_err_t | ra8_fs_listdir (const ra8_fs_mount_t *handle, const char *path, ra8_fs_listdir_cb_t cb, void *ctx) |
| Enumerate directory entries; invoke cb once per visible entry. | |
| ra8_err_t | ra8_fs_dir_open (ra8_fs_mount_t *handle, const char *path, ra8_fs_dir_t *directory) |
| Open a caller-owned directory cursor without holding the filesystem lock. | |
| ra8_err_t | ra8_fs_dir_next (ra8_fs_dir_t *directory, ra8_fs_dirent_t *out, bool *out_entry) |
| Copy the next visible directory entry. | |
| ra8_err_t | ra8_fs_dir_close (ra8_fs_dir_t *directory) |
| Consume one open directory cursor. | |
| ra8_err_t | ra8_fs_unlink (const ra8_fs_mount_t *handle, const char *path) |
| Delete a file: mark its dir entry deleted and free its clusters. | |
| ra8_err_t | ra8_fs_rename (const ra8_fs_mount_t *handle, const char *old_path, const char *new_path) |
| Rename a file within its own directory. | |
FAT listdir / unlink / rename directory-entry operations.
The verbs that read and rewrite entries in a directory that already exists: listing it, deleting a file from it, and renaming one in place, dispatched across FAT and exFAT volumes. unlink refuses a directory – freeing the cluster chain behind one orphans every file inside it (#604); removing a directory is rmdir's job, in ra8_fs_fat_dirmk.c.
Definition in file ra8_fs_fat_dir.c.
|
static |
Resolve and initialize one private filesystem cursor.
Selects FAT or exFAT path resolution from the mounted format and initializes only the matching caller-owned walk state.
| [in,out] | handle | Mounted filesystem. |
| [in] | path | Directory path. |
| [out] | state | Zeroed private cursor state. |
| k_ra8_ok | One format-specific cursor is ready. |
| k_ra8_err_invalid_state | The mount is not active. |
| k_ra8_err_* | Path resolution or media failure. |
state addresses writable private cursor storage. Definition at line 366 of file ra8_fs_fat_dir.c.
References internal_dir_open_locked(), k_ra8_fs_type_exfat, k_ra8_ok, priv_exfat_cursor_init(), and priv_exfat_resolve_dir().
Referenced by internal_dir_open_locked(), and ra8_fs_dir_open().
|
static |
Advance an independent FAT cursor to its next directory sector.
Delegates the format-specific sector walk and records clean end in the stable cursor before returning the walk result.
| [in,out] | state | Open private FAT cursor state. |
| k_ra8_ok | The cursor advanced or reached clean end. |
| k_ra8_err_* | Media, chain, or directory-walk failure. |
state is non-NULL and the filesystem lock is held. state was initialized for a mounted FAT volume. state->finished before this function returns. Definition at line 225 of file ra8_fs_fat_dir.c.
References internal_fat_dir_advance_sector(), priv_dir_walk_next_sector(), and RA8_INTERNAL.
Referenced by internal_fat_dir_advance_sector().
|
static |
Copy one visible FAT entry from an independent cursor.
Walks bounded directory sectors, assembles valid LFN fragments, and copies one stable name/attribute/size value per successful step.
| [in,out] | state | Open private cursor state. |
| [out] | out | Stable copied entry value. |
| [out] | out_entry | True for one copied entry; false at clean end. |
| k_ra8_ok | One entry was copied or clean end was reached. |
| k_ra8_err_* | Sector-walk or media-read failure. |
state was initialized for a mounted FAT volume. out never borrows sector scratch. out_entry false without publishing scratch bytes. Definition at line 320 of file ra8_fs_fat_dir.c.
References internal_fat_dir_next(), internal_fat_dir_scan_sector(), k_ra8_ok, priv_read_sector(), and priv_sec_walk().
Referenced by internal_fat_dir_next(), and ra8_fs_dir_next().
|
static |
Scan one already-read sector's remaining entries for one visible entry.
Advances the entry cursor across free/used/LFN/dot entries, assembling valid LFN fragments, until a visible entry is copied, the directory's end marker is found, or the sector is exhausted.
| [in,out] | state | Open private cursor state. |
| [in] | sector | Bytes of the already-read directory sector. |
| [out] | out | Stable copied entry value. |
| [out] | out_entry | True when one entry was copied into out. |
sector holds priv_bps(state->mount) valid bytes. sector. sector. Definition at line 255 of file ra8_fs_fat_dir.c.
References internal_fat_dir_scan_sector(), k_dir_marker_dot, k_dir_marker_free_used, k_dir_off_attr, k_dir_off_file_size, k_dir_off_name, k_dir_off_ntres, k_lfn_utf8_cap, k_ra8_fs_attr_lfn, k_ra8_fs_short_name_len, k_ra8_ok, memcpy(), priv_83_to_str(), priv_bps(), priv_lfn_add(), priv_lfn_reset(), priv_lfn_units_for(), priv_rd32(), priv_utf16_to_utf8(), RA8_INTERNAL, and strlen().
Referenced by internal_fat_dir_next(), and internal_fat_dir_scan_sector().
|
static |
Rename by writing the new entry first, then taking the old one away.
Rewriting the 11-byte name field in place, which is what this used to do, cannot be right once long names exist: the entry may be the tail of a VFAT chain that still spells the OLD name, and the new name may not fit eleven bytes at all. So the entry is re-filed – the old 32 bytes are carried across verbatim as the template, so the cluster, the size and the attributes survive, and only the name and its DIR_NTRes flags change.
The order is deliberate. Committing the new entry BEFORE erasing the old one means a failure between them leaves the file reachable under both names – untidy, but nothing is lost. The reverse order would put a window in the middle of the operation where the file has no name at all.
| [in] | handle | Mounted FAT12/16/32 volume. |
| [in] | old_path | Existing path. |
| [in] | new_path | Replacement path (must not exist; same directory). |
| k_ra8_ok | Renamed; the old name is gone, the new resolves. |
| k_ra8_err_invalid_arg | The new leaf cannot be stored under any encoding. |
| k_ra8_err_not_found | old_path does not exist. |
| k_ra8_err_exists | new_path already resolves to an entry. |
| k_ra8_err_not_supported | The two paths are in different directories. |
| k_ra8_err_no_mem | The directory has no room for the new entry. |
| k_ra8_err_* | Backend read/write error. |
handle and both path pointers are non-NULL; handle is a mounted FAT volume. old_path nor new_path is currently held open. new_path resolves to the same cluster, size and attributes. old_path no longer resolves and its chain is gone with it.Definition at line 619 of file ra8_fs_fat_dir.c.
References dir_target_t::entry, internal_rename_prepare(), k_dir_off_attr, k_dir_off_name, k_ra8_err_access_denied, k_ra8_err_exists, k_ra8_fs_attr_read_only, k_ra8_fs_dir_entry_bytes, k_ra8_ok, dir_target_t::lba, dir_target_t::off, dir_target_t::parent, priv_dir_commit(), priv_dir_erase_chain(), priv_dir_lookup_any(), priv_dir_reserve(), and priv_fat_entry_stamp_access().
Referenced by internal_rename_locked().
|
static |
Enumerate a directory – the guarded body of ra8_fs_listdir().
Resolves path to a directory – priv_resolve_dir on FAT, priv_exfat_resolve_dir on exFAT – and walks it, invoking cb once per visible entry. Both filesystems take "/" or a nested path. FAT's synthetic "." and ".." entries are not reported; exFAT has none to report.
| [in,out] | handle | Mount handle. |
| [in] | path | Directory path ("/" or a nested path). |
| [in] | cb | Per-entry callback. |
| [in] | ctx | Opaque pointer forwarded to cb. |
| k_ra8_ok | Directory walked successfully. |
| k_ra8_err_null_ptr | Any required pointer was NULL. |
| k_ra8_err_invalid_state | Mount not in use. |
| k_ra8_err_not_found | A path component does not exist. |
| k_ra8_err_invalid_arg | A path component names a file. |
| k_ra8_err_* | Backend error. |
Definition at line 159 of file ra8_fs_fat_dir.c.
References internal_listdir_locked(), k_ra8_err_null_ptr, k_ra8_fs_type_exfat, k_ra8_ok, priv_exfat_listdir(), and priv_exfat_resolve_dir().
Referenced by internal_listdir_locked(), and ra8_fs_listdir().
|
static |
Visit every visible entry in one already-loaded directory sector.
Skips deleted (0xE5) and LFN (attr 0x0F) entries and the synthetic "." / ".." directory entries. Stops on the end-of-directory marker (0x00).
| [in] | m | Mounted volume (supplies the entries-per-sector bound). |
| [in] | buf | Whole-sector buffer holding directory entries. |
| [in,out] | lfn | LFN reassembly state carried across sectors. |
| [in] | cb | Caller-supplied per-entry callback. |
| [in] | ctx | Opaque pointer forwarded to cb. |
| 1 | End-of-directory reached; caller should stop. |
| 0 | Sector exhausted without end-of-directory. |
Definition at line 71 of file ra8_fs_fat_dir.c.
References k_dir_marker_dot, k_dir_marker_free_perm, k_dir_marker_free_used, k_dir_off_attr, k_dir_off_file_size, k_dir_off_name, k_dir_off_ntres, k_lfn_utf8_cap, k_ra8_fs_attr_lfn, k_ra8_fs_dir_entry_bytes, k_ra8_fs_short_name_len, k_ra8_ok, priv_83_to_str(), priv_dir_eps(), priv_lfn_add(), priv_lfn_reset(), priv_lfn_units_for(), priv_rd32(), and priv_utf16_to_utf8().
|
static |
Rename – the guarded body of ra8_fs_rename().
See the public header for the documented contract; dispatches to the FAT re-filing path or the exFAT entry-set rewrite.
| [in] | handle | See header. |
| [in] | old_path | See header. |
| [in] | new_path | See header. |
| k_ra8_ok | File renamed. |
Definition at line 684 of file ra8_fs_fat_dir.c.
References internal_fat_rename(), internal_rename_locked(), k_ra8_err_null_ptr, and k_ra8_fs_type_exfat.
Referenced by internal_rename_locked(), and ra8_fs_rename().
|
static |
Resolve a rename's old/new paths to a shared parent and two leaves.
Resolves both parents and requires them to be the same directory: an in-place rename cannot move an entry between directories. The leaf components are handed back unpacked, because whether either of them is an 8.3 name is no longer the rename's business – the reservation decides that, and both sides may be long names.
| [in] | handle | Mounted FAT volume. |
| [in] | old_path | Existing path. |
| [in] | new_path | Replacement path (same directory). |
| [out] | out_parent | Receives the shared parent directory location. |
| [out] | out_old | Receives a pointer into old_path at its leaf. |
| [out] | out_new | Receives a pointer into new_path at its leaf. |
| k_ra8_ok | Resolved; outputs populated. |
| k_ra8_err_not_supported | The two paths are in different directories. |
| k_ra8_err_* | Resolution / backend error. |
Definition at line 545 of file ra8_fs_fat_dir.c.
References dir_loc_t::cluster, dir_loc_t::is_root, k_ra8_err_not_supported, k_ra8_ok, and priv_resolve_parent().
Referenced by internal_fat_rename().
|
static |
Resolve a path to a deletable FILE's entry and first cluster.
Resolves the parent, packs the leaf to 8.3, looks it up, and requires the matched entry NOT to carry k_ra8_fs_attr_directory. The mirror image of priv_rmdir_locate(): each verb refuses the kind of entry the other owns, and both refuse before anything is freed. Split out of ra8_fs_unlink so it stays inside the function-size gate.
| [in] | handle | Mounted FAT12/16/32 volume. |
| [in] | path | File path to delete. |
| [out] | out | Receives the parent, the entry position and the entry. |
| [out] | out_cluster | The file's first cluster (0 when it has none). |
| k_ra8_ok | Located; outputs populated. |
| k_ra8_err_invalid_arg | path is unstorable, or names a directory. |
| k_ra8_err_not_found | No such entry. |
| k_ra8_err_* | Backend error. |
Definition at line 421 of file ra8_fs_fat_dir.c.
References dir_target_t::entry, k_dir_off_attr, k_ra8_err_access_denied, k_ra8_err_invalid_arg, k_ra8_fs_attr_directory, k_ra8_fs_attr_read_only, k_ra8_ok, dir_target_t::lba, dir_target_t::off, dir_target_t::parent, priv_dir_lookup_any(), priv_entry_first_cluster(), and priv_resolve_parent().
Referenced by internal_unlink_locked().
|
static |
Delete a file – the guarded body of ra8_fs_unlink().
Frees the cluster chain (if any) and marks the dir entry deleted by writing 0xE5 to the first byte of the name field. Refuses a directory: use ra8_fs_rmdir() for those.
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated path; only flat root names supported. |
| k_ra8_ok | File deleted. |
| k_ra8_err_null_ptr | Any pointer was NULL. |
| k_ra8_err_invalid_state | Mount not in use. |
| k_ra8_err_invalid_arg | Path is not a valid 8.3 name, or it names a directory. |
| k_ra8_err_not_found | No such file. |
| k_ra8_err_* | Backend or FAT error. |
Definition at line 485 of file ra8_fs_fat_dir.c.
References internal_unlink_locate(), internal_unlink_locked(), k_cluster_first_data, k_dir_off_name, k_ra8_err_null_ptr, k_ra8_fs_type_exfat, k_ra8_ok, priv_dir_erase_chain(), and priv_free_chain().
Referenced by internal_unlink_locked(), and ra8_fs_unlink().
|
nodiscard |
Consume one open directory cursor.
| [in,out] | directory | Open caller-owned cursor. |
Definition at line 786 of file ra8_fs_fat_dir.c.
References ra8_fs_dir_t::is_open, k_ra8_err_invalid_state, k_ra8_err_null_ptr, and k_ra8_ok.
Referenced by internal_native_dir_close(), and internal_native_listdir().
|
nodiscard |
Copy the next visible directory entry.
| [in,out] | directory | Open caller-owned cursor. |
| [out] | out | Stable entry value owned by the caller. |
| [out] | out_entry | True when out is populated; false at clean EOF. |
out survives later cursor calls. Definition at line 748 of file ra8_fs_fat_dir.c.
References internal_fat_dir_next(), k_ra8_err_invalid_state, k_ra8_err_null_ptr, k_ra8_fs_type_exfat, k_ra8_ok, priv_exfat_dir_next(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_dir_next().
Referenced by internal_native_dir_next(), internal_native_listdir(), and ra8_fs_dir_next().
|
nodiscard |
Open a caller-owned directory cursor without holding the filesystem lock.
Path resolution is locked only for this call. Each later next reacquires and releases the lock, so client metadata and stream operations are valid between entries. Two cursor objects advance independently. The enumerated directory and its ancestors must not be mutated until close; mutation elsewhere is permitted.
| [in,out] | handle | Mounted filesystem. |
| [in] | path | Directory path. |
| [out] | directory | Idle caller-owned cursor. |
| k_ra8_ok | Cursor opened. |
| k_ra8_err_busy | directory is already open. |
handle is mounted. Definition at line 720 of file ra8_fs_fat_dir.c.
References internal_dir_open_locked(), k_ra8_err_null_ptr, k_ra8_ok, memset(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_dir_open().
Referenced by internal_native_dir_open(), internal_native_listdir(), and ra8_fs_dir_open().
|
nodiscard |
Enumerate directory entries; invoke cb once per visible entry.
Every supported filesystem enumerates any directory by path ("/" for the root, "/books" for a subdirectory) – exFAT included since #605. FAT's synthetic "." and ".." entries are not reported; exFAT has none to report. A subdirectory appears in its parent's listing like any other entry, with the directory bit set in the attr argument.
| [in] | handle | Mount handle. |
| [in] | path | Directory path ("/" or a nested path). |
| [in] | cb | Callback (must be non-NULL). |
| [in] | ctx | Cookie forwarded to the callback. |
| k_ra8_ok | Enumeration complete. |
| k_ra8_err_null_ptr | handle/cb NULL. |
| k_ra8_err_not_found | A path component does not exist. |
| k_ra8_err_invalid_arg | A path component names a file. |
Definition at line 711 of file ra8_fs_fat_dir.c.
References internal_listdir_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_listdir().
Referenced by demo_file_ops(), fileops_step_listdir(), fs_fmt_assert_empty_root(), ra8_fs_listdir(), and sh_sd_scan().
|
nodiscard |
Rename a file within its own directory.
FAT12/16/32: re-files the entry under the new name – writing the new entry (with its long-name chain, if the new name needs one) before taking the old one away, so a failure between the two leaves the file reachable under both names rather than under neither. The cluster, the size and the attributes are carried across unchanged. Legacy note: this used to rewrite the 11-byte packed 8.3 name in the existing directory entry. exFAT: patches the Stream entry's NameLength and NameHash, rebuilds the Name entry, and recomputes the SetChecksum – supported when both names fit one Name entry (<= 15 characters), which keeps the entry-set length unchanged. Data clusters never move.
The LAST-ACCESS stamp advances; the modification stamp deliberately does not. A rename changes the name, not the bytes, so moving the modification time would tell every rsync, backup and "pick the newest image" heuristic that the contents changed. Neither format has a metadata-change field, so the access stamp is the honest record that the entry was touched.
| [in] | handle | Mount handle. |
| [in] | old_path | Existing path. |
| [in] | new_path | Replacement path, in the same directory (must not already exist). |
| k_ra8_ok | File renamed. |
| k_ra8_err_null_ptr | Any pointer arg is NULL. |
| k_ra8_err_not_found | old_path does not exist. |
| k_ra8_err_access_denied | old_path's read-only attribute is set. |
| k_ra8_err_exists | new_path already resolves. |
| k_ra8_err_not_supported | exFAT name longer than 15 characters, or the two paths are in different directories. |
| k_ra8_err_invalid_arg | The new leaf holds a character no FAT name may carry, or is longer than 247 characters. |
| k_ra8_err_no_mem | The directory has no room for the new entry. |
new_path resolves to the same data. Definition at line 808 of file ra8_fs_fat_dir.c.
References internal_rename_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_rename().
Referenced by fileops_suite_mutate(), fs_fmt_rename_and_verify(), internal_atomic_replace(), internal_native_rename(), and ra8_fs_rename().
|
nodiscard |
Delete a file: mark its dir entry deleted and free its clusters.
FAT12/16/32: 0xE5-marks the entry – together with the VFAT long-name chain in front of it, if it has one – and frees the FAT chain. exFAT: clears the in-use bit on the whole entry set and frees the clusters in the allocation bitmap (the bitmap is authoritative).
A DIRECTORY is refused on both filesystems. Deleting one this way would free the chain that holds its children while their own entries still claim their clusters, leaving them allocated and unreachable – lost clusters that only a reformat recovers. Use ra8_fs_rmdir().
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated path to the file. |
| k_ra8_ok | File unlinked. |
| k_ra8_err_null_ptr | handle/path NULL. |
| k_ra8_err_invalid_arg | path names a directory. |
| k_ra8_err_access_denied | path's read-only attribute is set. |
| k_ra8_err_not_found | File doesn't exist. |
Definition at line 799 of file ra8_fs_fat_dir.c.
References internal_unlink_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_unlink().
Referenced by demo_file_ops(), fileops_suite_create(), fileops_suite_mutate(), fs_fmt_write_cycle(), internal_atomic_replace(), internal_compile_and_cache(), internal_native_unlink(), internal_write_stamp(), and ra8_fs_unlink().