|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
exFAT directories: path resolution, mkdir, rmdir. 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.
Functions | |
| static ra8_err_t | internal_exfat_enter (const ra8_fs_mount_t *m, const exfat_dir_t *cur, const char *comp, uint32_t len, exfat_dir_t *out) |
Descend into the named directory component within cur. | |
| ra8_err_t | priv_exfat_resolve_parent (const ra8_fs_mount_t *m, const char *path, exfat_dir_t *out_parent, const char **out_leaf) |
Resolve every component of path but the last. | |
| ra8_err_t | priv_exfat_resolve_dir (const ra8_fs_mount_t *m, const char *path, exfat_dir_t *out) |
| Resolve a whole path to the directory it names. | |
| ra8_err_t | priv_exfat_lookup (const ra8_fs_mount_t *m, const char *path, uint8_t *out_strm, uint8_t *out_attr) |
| Resolve a path and return the leaf entry set's location fields. | |
| ra8_err_t | priv_exfat_zero_cluster (const ra8_fs_mount_t *m, uint32_t clus) |
| Zero every sector of one cluster. | |
| ra8_err_t | priv_exfat_seal_cluster (const ra8_fs_mount_t *m, uint32_t clus) |
| Replace every end-of-directory marker in a cluster with an unused one. | |
| static uint32_t | internal_exfat_build_dir_set (const ra8_fs_mount_t *m, uint8_t *set, const uint16_t *name, uint32_t nlen, uint32_t first) |
| Build the File + Stream + Name entry set a DIRECTORY needs. | |
| static ra8_err_t | internal_exfat_dir_alloc (const ra8_fs_mount_t *m, uint32_t *out_clus, uint64_t *out_bmp) |
| Allocate and initialise one cluster as an empty exFAT directory. | |
| static ra8_err_t | internal_exfat_mkdir_check (const ra8_fs_mount_t *m, const exfat_dir_t *parent, const char *leaf, uint32_t nlen) |
Decide whether leaf may be created in parent. | |
| ra8_err_t | priv_exfat_mkdir (const ra8_fs_mount_t *m, const char *path) |
Create one exFAT directory at path. | |
| static ra8_err_t | internal_exfat_dir_is_empty (const ra8_fs_mount_t *m, const exfat_dir_t *dir, uint8_t *out_empty) |
| Decide whether an exFAT directory holds any live entry. | |
| static ra8_err_t | internal_exfat_rmdir_locate (const ra8_fs_mount_t *m, const char *path, exfat_setpos_t *pos, uint32_t *out_count, uint8_t *strm, exfat_dir_t *out_dir) |
| Resolve a path to a removable exFAT directory's entry set. | |
| ra8_err_t | priv_exfat_rmdir (const ra8_fs_mount_t *m, const char *path) |
Remove one EMPTY exFAT directory at path. | |
exFAT directories: path resolution, mkdir, rmdir.
Until this file existed, exFAT was a flat namespace here: every scan started at m->root_cluster, so "/logs/a.txt" was not resolved but matched, after slash-stripping, as one root-level name – and mkdir / rmdir declined the volume outright, because a driver with no directory-creation path has no directory to remove either (#605).
Three pieces, in the order a nested path uses them:
The run this file allocates is contiguous and carries NoFatChain, which is why exfat_cursor_t has a run bound: the exFAT specification declares the FAT entries of a NoFatChain run invalid, and the ones left behind here read as 0 – not end-of-chain – so a FAT-following walk would step into cluster 0.
Definition in file ra8_fs_fat_exfat_dir.c.
|
static |
Build the File + Stream + Name entry set a DIRECTORY needs.
The file-side builder in ra8_fs_fat_exfat_write.c makes a zero-length, cluster-less set, because a streaming write starts with nothing and grows (#602). A directory is the opposite: it is born owning exactly one cluster and never grows here, so its set carries the Directory attribute, the cluster, NoFatChain, and a DataLength equal to the ALLOCATION – an exFAT directory's length is its allocation, not a byte count, and the specification requires a directory's ValidDataLength to equal DataLength. Both are written.
| [in] | m | Mounted exFAT volume. |
| [out] | set | Buffer of at least k_exfat_max_set_bytes bytes. |
| [in] | name | Leaf name as UTF-16 code units. |
| [in] | nlen | Name length in UTF-16 UNITS, which is what NameLength counts and what a Name entry holds fifteen of (#606). |
| [in] | first | The directory's own first cluster. |
| >0 | Number of bytes written into set. |
m, set and name are non-NULL; set is large enough. nlen is the unit count priv_exfat_name_to_units() produced, and is within k_exfat_name_cap. set holds a complete entry set with a valid SetChecksum. Definition at line 306 of file ra8_fs_fat_exfat_dir.c.
References k_exfat_attr_directory, k_exfat_entry_bytes, k_exfat_entry_file, k_exfat_entry_name, k_exfat_entry_stream, k_exfat_name_off, k_exfat_name_per_entry, k_exfat_off_file_attr, k_exfat_off_file_csum, k_exfat_off_file_secnt, k_exfat_off_strm_hash, k_exfat_off_strm_valid, k_exfat_secflag_alloc, k_exfat_strm_off_clus, k_exfat_strm_off_dlen, k_exfat_strm_off_flags, k_exfat_strm_off_nlen, priv_cluster_bytes(), priv_exfat_file_stamp_create(), priv_exfat_name_hash(), priv_exfat_set_checksum(), priv_wr16(), and priv_wr32().
Referenced by priv_exfat_mkdir().
|
static |
Allocate and initialise one cluster as an empty exFAT directory.
Scans the allocation bitmap for a single free cluster, zeroes it, and only then marks the bit. That order is deliberate: a failure while zeroing leaves a cluster that is still free, so the volume loses nothing, whereas marking first would leak it.
| [in,out] | m | Mounted exFAT volume. |
| [out] | out_clus | Receives the new directory's cluster. |
| [out] | out_bmp | Receives the bitmap's first LBA (for rollback). |
| k_ra8_ok | Cluster allocated, zeroed and marked used. |
| k_ra8_err_no_mem | The volume has no free cluster. |
| k_ra8_err_* | Bitmap or backend failure. |
m, out_clus and out_bmp are non-NULL; the mount is exFAT. Definition at line 377 of file ra8_fs_fat_exfat_dir.c.
References k_ra8_ok, priv_alloc_hint_set(), priv_cluster_to_lba(), priv_exfat_bitmap_mark(), priv_exfat_bitmap_scan(), priv_exfat_find_bitmap(), and priv_exfat_zero_cluster().
Referenced by priv_exfat_mkdir().
|
static |
Decide whether an exFAT directory holds any live entry.
Walks the directory and stops at the first definite answer. Only two things count as "not an occupant": the end-of-directory marker (0x00), which ends the walk, and an entry whose in-use bit is clear, which is a deleted remnant. Everything else – a File entry, a Stream entry, a Name entry, or any typed entry another implementation left – is an occupant, exactly as the FAT side's ::priv_dir_is_empty treats a live 8.3 entry (#604).
exFAT has no "." / ".." entries, so unlike FAT there is nothing to discount before the count starts: an empty exFAT directory really is an empty cluster.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | The directory under test. |
| [out] | out_empty | Receives 1 when the directory is removable, else 0. |
| k_ra8_ok | Verdict written to *out_empty. |
| k_ra8_err_* | Backend read failure. |
m, dir and out_empty are non-NULL. dir was built from an entry set carrying the directory attribute. Definition at line 555 of file ra8_fs_fat_exfat_dir.c.
References k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_inuse_bit, k_exfat_scan_limit, k_ra8_err_not_found, k_ra8_ok, priv_exfat_cursor_init(), priv_exfat_next_entry(), and exfat_cursor_t::scanned.
Referenced by priv_exfat_rmdir().
|
static |
Descend into the named directory component within cur.
Copies the (non-NUL-terminated) component into a local buffer, looks it up in cur, and requires the matched entry set to carry k_exfat_attr_directory and to name a real heap cluster. The exFAT counterpart of ::priv_enter_subdir.
| [in] | m | Mounted exFAT volume. |
| [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 over-long, or names a FILE. |
| k_ra8_err_not_found | No such entry in cur. |
| k_ra8_err_protocol_error | The entry claims no data cluster. |
| k_ra8_err_* | Backend read failure. |
m, cur, comp and out are non-NULL. len is the exact component length (no trailing slash). out locates the subdirectory. Definition at line 81 of file ra8_fs_fat_exfat_dir.c.
References exfat_setpos_t::cluster, exfat_setpos_t::index, k_cluster_first_data, k_exfat_attr_directory, k_exfat_entry_bytes, k_exfat_name_cap, k_exfat_name_u8_cap, k_exfat_off_file_attr, k_exfat_set_max_entries, k_exfat_strm_off_clus, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_err_protocol_error, k_ra8_ok, priv_exfat_dir_from_set(), priv_exfat_find_set(), priv_exfat_name_to_units(), priv_rd32(), exfat_dir_t::self_cluster, and exfat_dir_t::self_index.
Referenced by priv_exfat_resolve_dir(), and priv_exfat_resolve_parent().
|
static |
Decide whether leaf may be created in parent.
Length first, then the name lookup. Split out of priv_exfat_mkdir so that function stays inside the function-size gate.
| [in] | m | Mounted exFAT volume. |
| [in] | parent | Directory the name would be created in. |
| [in] | leaf | Leaf name, UTF-8 (the existence probe converts it itself). |
| [in] | nlen | Length of leaf in UTF-16 UNITS. |
| k_ra8_ok | The name is free and storable. |
| k_ra8_err_invalid_arg | leaf is empty (the root) or over-long. |
| k_ra8_err_exists | A file or directory already has that name. |
| k_ra8_err_* | Backend read failure. |
m, parent and leaf are non-NULL; the mount is exFAT. nlen is leaf's length in UTF-16 units. parent answers to leaf.Definition at line 431 of file ra8_fs_fat_exfat_dir.c.
References k_exfat_entry_bytes, k_exfat_name_cap, k_ra8_err_exists, k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_ok, and priv_exfat_find().
Referenced by priv_exfat_mkdir().
|
static |
Resolve a path to a removable exFAT directory's entry set.
Resolves the parent, refuses the volume root, locates the leaf's entry set with per-entry positions, and requires it to carry k_exfat_attr_directory and to name a real heap cluster. Split out of priv_exfat_rmdir so both stay inside the function-size gate.
| [in] | m | Mounted exFAT volume. |
| [in] | path | Directory path to remove. |
| [out] | pos | Receives the set's per-entry positions. |
| [out] | out_count | Receives the entry count (1 + SecondaryCount). |
| [out] | strm | Receives the 32-byte Stream-extension entry. |
| [out] | out_dir | Receives the directory's own location. |
| k_ra8_ok | Located; outputs populated. |
| k_ra8_err_invalid_arg | path is the root, or names a FILE. |
| k_ra8_err_not_found | No such entry, or a component is missing. |
| k_ra8_err_protocol_error | The entry claims no data cluster. |
| k_ra8_err_* | Backend read failure. |
pos has k_exfat_set_max_entries slots. Definition at line 615 of file ra8_fs_fat_exfat_dir.c.
References k_cluster_first_data, k_exfat_attr_directory, k_exfat_entry_bytes, k_exfat_off_file_attr, k_exfat_set_max_entries, k_exfat_strm_off_clus, k_ra8_err_invalid_arg, k_ra8_err_protocol_error, k_ra8_ok, priv_exfat_dir_from_set(), priv_exfat_find_set(), priv_exfat_resolve_parent(), priv_rd32(), and priv_strlen().
Referenced by priv_exfat_rmdir().
| ra8_err_t priv_exfat_lookup | ( | const ra8_fs_mount_t * | m, |
| const char * | path, | ||
| uint8_t * | out_strm, | ||
| uint8_t * | out_attr ) |
Resolve a path and return the leaf entry set's location fields.
priv_exfat_resolve_parent followed by priv_exfat_find in the resolved directory – the nested-path replacement for what used to be a flat root-level priv_exfat_find on the whole path.
| [in] | m | Mounted exFAT volume. |
| [in] | path | NUL-terminated path. |
| [out] | out_strm | Receives the matched 32-byte Stream-extension entry. |
| [out] | out_attr | Receives the FileAttributes low byte. |
| k_ra8_ok | Found; outputs populated. |
| k_ra8_err_invalid_arg | path names the volume root, or a component names a file. |
| k_ra8_err_not_found | No such entry. |
| k_ra8_err_* | Backend read failure. |
Definition at line 212 of file ra8_fs_fat_exfat_dir.c.
References k_ra8_err_invalid_arg, k_ra8_ok, priv_exfat_find(), priv_exfat_resolve_parent(), and priv_strlen().
Referenced by priv_exfat_open().
| ra8_err_t priv_exfat_mkdir | ( | const ra8_fs_mount_t * | m, |
| const char * | path ) |
Create one exFAT directory at path.
Resolves the parent, refuses a name that already exists, reserves the parent's entry-slot run, allocates and zeroes one cluster, and links a File + Stream + Name set carrying k_exfat_attr_directory. There are no "." / ".." entries to write – exFAT has none – so an all-zero cluster is already a valid empty directory. On a failure after allocation the cluster is returned to the bitmap, so the volume is never leaked.
| [in] | m | Mounted exFAT volume. |
| [in] | path | NUL-terminated directory path to create. |
| k_ra8_ok | Directory created. |
| k_ra8_err_invalid_arg | The leaf is empty (the root) or over-long. |
| k_ra8_err_exists | The name already exists in the parent. |
| k_ra8_err_not_found | An intermediate component does not exist. |
| k_ra8_err_no_mem | Parent directory full, or volume full. |
| k_ra8_err_* | Bitmap or backend failure. |
m and path are non-NULL; m->type is exFAT. path resolves to an empty directory. Definition at line 464 of file ra8_fs_fat_exfat_dir.c.
References internal_exfat_build_dir_set(), internal_exfat_dir_alloc(), internal_exfat_mkdir_check(), k_exfat_max_set_bytes, k_exfat_name_cap, k_exfat_name_per_entry, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_ok, priv_exfat_bitmap_clear(), priv_exfat_find_dir_space(), priv_exfat_name_to_units(), priv_exfat_resolve_parent(), and priv_exfat_write_dir_set().
| ra8_err_t priv_exfat_resolve_dir | ( | const ra8_fs_mount_t * | m, |
| const char * | path, | ||
| exfat_dir_t * | out ) |
Resolve a whole path to the directory it names.
"" and "/" are the volume root; anything else is resolved to its parent and then descended into. A trailing slash names the same directory as the path without one.
| [in] | m | Mounted exFAT volume. |
| [in] | path | NUL-terminated directory path. |
| [out] | out | Receives the directory location. |
| k_ra8_ok | Resolved; out populated. |
| k_ra8_err_invalid_arg | path names a FILE, or a component does. |
| k_ra8_err_not_found | A component does not exist. |
| k_ra8_err_* | Backend read failure. |
m, path and out are non-NULL; m->type is exFAT. out locates an existing directory. Definition at line 186 of file ra8_fs_fat_exfat_dir.c.
References internal_exfat_enter(), k_ra8_ok, priv_exfat_dir_root(), priv_exfat_resolve_parent(), and priv_strlen().
Referenced by internal_dir_open_locked(), and internal_listdir_locked().
| ra8_err_t priv_exfat_resolve_parent | ( | const ra8_fs_mount_t * | m, |
| const char * | path, | ||
| exfat_dir_t * | out_parent, | ||
| const char ** | out_leaf ) |
Resolve every component of path but the last.
Walks the path component by component from the volume root, descending into each intermediate name and requiring it to be a directory, then hands back that directory plus a pointer INTO path at the leaf. Runs of slashes are skipped, so "/a//b" and "a/b" resolve alike, and a trailing slash yields an empty leaf – which each caller rejects or interprets for itself. The exFAT mirror of priv_resolve_parent, and iterative for the same reason: NASA Power of 10 Rule 1 forbids recursion.
| [in] | m | Mounted exFAT volume. |
| [in] | path | NUL-terminated path. |
| [out] | out_parent | Receives the directory holding the leaf. |
| [out] | out_leaf | Receives a pointer to the leaf within path. |
| k_ra8_ok | Resolved; outputs populated. |
| k_ra8_err_invalid_arg | A component names a FILE, is over-long, or the path is deeper than k_exfat_path_depth. |
| k_ra8_err_not_found | An intermediate component does not exist. |
| k_ra8_err_protocol_error | A directory entry claims no data cluster. |
| k_ra8_err_* | Backend read failure. |
path outlives the returned leaf pointer. path. Definition at line 145 of file ra8_fs_fat_exfat_dir.c.
References internal_exfat_enter(), k_exfat_path_depth, k_ra8_err_invalid_arg, k_ra8_ok, and priv_exfat_dir_root().
Referenced by internal_exfat_rename_prepare(), internal_exfat_rmdir_locate(), internal_stat_exfat(), priv_exfat_lookup(), priv_exfat_mkdir(), priv_exfat_open_write(), priv_exfat_resolve_dir(), and priv_exfat_unlink().
| ra8_err_t priv_exfat_rmdir | ( | const ra8_fs_mount_t * | m, |
| const char * | path ) |
Remove one EMPTY exFAT directory at path.
Locates the entry set, requires it to be a directory, proves the directory holds no live entry, then clears the in-use bit on every entry of the set and frees its clusters in the allocation bitmap. The emptiness proof runs before anything is written, so a refused removal changes nothing on disk.
| [in] | m | Mounted exFAT volume. |
| [in] | path | NUL-terminated directory path to remove. |
| k_ra8_ok | Directory removed. |
| k_ra8_err_invalid_arg | path is the root, or names a FILE. |
| k_ra8_err_not_found | No such entry, or a component is missing. |
| k_ra8_err_not_empty | The directory still holds entries. |
| k_ra8_err_protocol_error | The entry claims no data cluster. |
| k_ra8_err_* | Bitmap or backend failure. |
m and path are non-NULL; m->type is exFAT. path. path no longer resolves and its clusters are free. Definition at line 654 of file ra8_fs_fat_exfat_dir.c.
References internal_exfat_dir_is_empty(), internal_exfat_rmdir_locate(), k_exfat_entry_bytes, k_exfat_set_max_entries, k_ra8_err_not_empty, k_ra8_ok, priv_exfat_drop_set(), and priv_exfat_free_clusters().
| ra8_err_t priv_exfat_seal_cluster | ( | const ra8_fs_mount_t * | m, |
| uint32_t | clus ) |
Replace every end-of-directory marker in a cluster with an unused one.
The subtlety that makes directory growth correct. exFAT spec sec 6.3.1: an entry type of 0x00 is EndOfDirectory, and NO entry past the first one may be anything else – a reader (and fsck.exfat) stops there. This driver never splits an entry set across a cluster, so the cluster that was the directory's tail is left with a run of trailing 0x00 slots, and once a grown cluster holds live entries AFTER it those 0x00 slots are a premature end that hides everything beyond them.
Rewriting each 0x00 in the old tail to a DELETED File type (0x85 with the in-use bit clear) keeps it a legal, skippable "unused" entry – which the walk steps over and the free-slot scan still calls free – while moving the one real EndOfDirectory to the trailing zeros of the freshly appended cluster, where the format requires it to be. Paired with priv_exfat_zero_cluster on the directory grow path (#677).
| [in] | m | Mounted exFAT volume. |
| [in] | clus | Cluster whose end-of-directory markers are to be retired. |
| k_ra8_ok | Every 0x00 slot in the cluster now reads as unused. |
| k_ra8_err_* | Backend read/write failure. |
m is non-NULL; clus is a directory cluster of this volume. clus (this driver's append-only invariant). clus holds no 0x00 slot; the walk continues into the next cluster. Definition at line 245 of file ra8_fs_fat_exfat_dir.c.
References k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_entry_file, k_exfat_inuse_bit, k_ra8_ok, priv_bps(), priv_cluster_to_lba(), priv_read_sector(), priv_sec_io(), priv_write_sector(), and ra8_fs_mount_t::sectors_per_cluster.
Referenced by internal_exfat_dir_append().
| ra8_err_t priv_exfat_zero_cluster | ( | const ra8_fs_mount_t * | m, |
| uint32_t | clus ) |
Zero every sector of one cluster.
An all-zero exFAT directory cluster is a valid EMPTY directory: the first entry's type byte is 0x00, which is the end-of-directory marker. There are no "." / ".." entries to stamp – exFAT has none. Used both to initialise a directory's first cluster (mkdir) and to initialise each cluster growth appends to it (#677).
| [in] | m | Mounted exFAT volume. |
| [in] | clus | Cluster to clear. |
| k_ra8_ok | Every sector of the cluster reads as zero. |
| k_ra8_err_* | Backend write failure. |
m is non-NULL; clus is a heap cluster. Definition at line 232 of file ra8_fs_fat_exfat_dir.c.
References k_ra8_ok, k_zero_sector, priv_cluster_to_lba(), priv_write_sector(), and ra8_fs_mount_t::sectors_per_cluster.
Referenced by internal_exfat_dir_alloc(), and internal_exfat_dir_append().