|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
FAT subdirectory creation and removal (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.
Enumerations | |
| enum | dir_scan_t : uint8_t { k_dir_scan_more = 0U , k_dir_scan_empty = 1U , k_dir_scan_used = 2U } |
| Verdict of scanning one directory sector for occupancy. More... | |
Functions | |
| static void | internal_pack_dot_entry (uint8_t *ent, uint32_t dots, uint32_t cluster) |
| Pack a "." or ".." dot entry into a 32-byte directory slot. | |
| static ra8_err_t | internal_dir_cluster_init (const ra8_fs_mount_t *m, uint32_t new_cluster, uint32_t parent_cluster) |
| Initialise a freshly allocated directory cluster ("." + ".." + zeros). | |
| static ra8_err_t | internal_fat_mkdir (const ra8_fs_mount_t *handle, const char *path) |
| Implementation of internal_fat_mkdir() – create one FAT directory. | |
| static ra8_err_t | internal_mkdir_locked (const ra8_fs_mount_t *handle, const char *path) |
| Create a directory – the guarded body of ra8_fs_mkdir(). | |
| static dir_scan_t | internal_rmdir_scan_sector (const ra8_fs_mount_t *m, const uint8_t *buf) |
| Classify one already-loaded directory sector as empty / occupied / more. | |
| static ra8_err_t | internal_dir_is_empty (const ra8_fs_mount_t *m, uint32_t cluster, uint8_t *out_empty) |
| Decide whether a subdirectory holds any entry other than "." / "..". | |
| static ra8_err_t | internal_rmdir_locate (const ra8_fs_mount_t *handle, const char *path, dir_target_t *out, uint32_t *out_cluster) |
| Resolve a path to a removable subdirectory's entry and first cluster. | |
| static ra8_err_t | internal_fat_rmdir (const ra8_fs_mount_t *handle, const char *path) |
| Implementation of internal_fat_rmdir() – remove one empty FAT directory. | |
| static ra8_err_t | internal_rmdir_locked (const ra8_fs_mount_t *handle, const char *path) |
| Remove an empty directory – the guarded body of ra8_fs_rmdir(). | |
| ra8_err_t | ra8_fs_mkdir (const ra8_fs_mount_t *handle, const char *path) |
Create a directory at path. | |
| ra8_err_t | ra8_fs_rmdir (const ra8_fs_mount_t *handle, const char *path) |
Remove an empty directory at path. | |
FAT subdirectory creation and removal (mkdir / rmdir).
The two verbs that add and take away a directory, kept together because they are inverses over the same on-disk shape: mkdir allocates a cluster, stamps . and .. into it and links an ATTR_DIRECTORY entry, and rmdir undoes exactly that – after proving the directory holds nothing but those two dot entries.
The public entry points at the bottom dispatch: exFAT has neither dot entries nor a parent back-link, so its half lives in ra8_fs_fat_exfat_dir.c (#605) rather than being bent into the FAT shape here.
Split out of ra8_fs_fat_dir.c for the 1000-line file-size cap.
Definition in file ra8_fs_fat_dirmk.c.
| enum dir_scan_t : uint8_t |
Verdict of scanning one directory sector for occupancy.
Three-valued because "this sector held nothing" and "the directory ends here" are different answers: the first means keep walking, the second means stop and report empty.
| Enumerator | |
|---|---|
| k_dir_scan_more | Only skippable slots here; keep walking. |
| k_dir_scan_empty | End-of-directory marker reached. |
| k_dir_scan_used | A real entry was found; not empty. |
Definition at line 252 of file ra8_fs_fat_dirmk.c.
|
static |
Initialise a freshly allocated directory cluster ("." + ".." + zeros).
Writes the self ("."), parent ("..") links into the first sector and zeroes every remaining sector of the cluster so the directory has a clean end-of-directory marker for subsequent entries.
| [in] | m | Mount providing geometry and backend. |
| [in] | new_cluster | The directory's own first cluster. |
| [in] | parent_cluster | Parent's first cluster (0 when the parent is root). |
| k_ra8_ok | Cluster initialised on disk. |
| k_ra8_err_* | Backend write error. |
Definition at line 99 of file ra8_fs_fat_dirmk.c.
References internal_pack_dot_entry(), k_ra8_fs_dir_entry_bytes, k_ra8_ok, k_zero_sector, priv_bps(), priv_byte_fill(), priv_cluster_to_lba(), priv_sec_walk(), priv_write_sector(), and ra8_fs_mount_t::sectors_per_cluster.
Referenced by internal_fat_mkdir().
|
static |
Decide whether a subdirectory holds any entry other than "." / "..".
Walks the directory's cluster chain with the shared dir_walk_t iterator, classifying each sector via priv_rmdir_scan_sector() and stopping at the first definite answer.
| [in] | m | Mount providing geometry and backend. |
| [in] | cluster | The subdirectory's first cluster. |
| [out] | out_empty | Receives 1 when the directory is removable, else 0. |
| k_ra8_ok | Verdict written to *out_empty. |
| k_ra8_err_protocol_error | Cluster-chain cycle detected (corrupt FAT). |
| k_ra8_err_* | Backend read error. |
Definition at line 338 of file ra8_fs_fat_dirmk.c.
References dir_walk_t::cur_lba, internal_rmdir_scan_sector(), k_dir_scan_empty, k_dir_scan_used, k_ra8_ok, priv_dir_walk_init_loc(), priv_dir_walk_next_sector(), priv_read_sector(), and priv_sec_walk().
Referenced by internal_fat_rmdir().
|
static |
Implementation of internal_fat_mkdir() – create one FAT directory.
Resolves the parent, rejects an existing name, finds a free parent slot, allocates and initialises a directory cluster ("." / ".."), then writes the parent's directory entry. On any post-allocation failure the new cluster is freed so the volume is not leaked.
| [in] | handle | Mounted FAT12/16/32 volume. |
| [in] | path | NUL-terminated directory path to create. |
| k_ra8_ok | Directory created. |
| k_ra8_err_invalid_arg | Leaf is not an 8.3 name. |
| k_ra8_err_exists | The name already exists in the parent. |
| k_ra8_err_no_mem | Parent directory full or volume full. |
| k_ra8_err_not_found | An intermediate path component is missing. |
| k_ra8_err_* | Backend / FAT error. |
Definition at line 148 of file ra8_fs_fat_dirmk.c.
References dir_loc_t::cluster, internal_dir_cluster_init(), dir_loc_t::is_root, k_dir_off_attr, k_ra8_err_exists, k_ra8_fs_attr_directory, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_alloc_eoc_cluster(), priv_dir_commit(), priv_dir_lookup_any(), priv_dir_reserve(), priv_entry_set_cluster_size(), priv_fat_entry_stamp_create(), priv_free_chain(), and priv_resolve_parent().
Referenced by internal_mkdir_locked().
|
static |
Implementation of internal_fat_rmdir() – remove one empty FAT directory.
Locates the directory, proves it holds nothing but its own "." and ".." links, frees its cluster chain, then 0xE5-marks its entry in the parent. The emptiness proof runs before anything is freed, so a refused removal changes nothing on disk.
| [in] | handle | Mounted FAT12/16/32 volume. |
| [in] | path | NUL-terminated directory path to remove. |
| k_ra8_ok | Directory removed. |
| k_ra8_err_invalid_arg | Root, not an 8.3 name, or not a directory. |
| k_ra8_err_not_found | No such entry. |
| k_ra8_err_not_empty | The directory still holds entries. |
| k_ra8_err_protocol_error | Corrupt chain or a directory with no cluster. |
| k_ra8_err_* | Backend / FAT error. |
Definition at line 459 of file ra8_fs_fat_dirmk.c.
References dir_target_t::entry, internal_dir_is_empty(), internal_rmdir_locate(), k_dir_off_name, k_ra8_err_not_empty, k_ra8_ok, dir_target_t::lba, dir_target_t::off, dir_target_t::parent, priv_dir_erase_chain(), and priv_free_chain().
Referenced by internal_rmdir_locked().
|
static |
Create a directory – the guarded body of ra8_fs_mkdir().
Validates arguments and the mount, then dispatches to the FAT or the exFAT directory creator (#605).
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated directory path to create. |
| k_ra8_ok | Directory created. |
| k_ra8_err_null_ptr | handle or path was NULL. |
| k_ra8_err_invalid_state | Mount not in use. |
| k_ra8_err_* | See internal_fat_mkdir / priv_exfat_mkdir. |
Definition at line 223 of file ra8_fs_fat_dirmk.c.
References internal_fat_mkdir(), internal_mkdir_locked(), k_ra8_err_null_ptr, and k_ra8_fs_type_exfat.
Referenced by internal_mkdir_locked(), and ra8_fs_mkdir().
|
static |
Pack a "." or ".." dot entry into a 32-byte directory slot.
Writes the FAT self/parent link: a space-padded name of dots dots, the directory attribute, and cluster as the first cluster (size 0). A parent that is the volume root is recorded as cluster 0 per the FAT specification.
| [out] | ent | 32-byte slot to populate (zeroed by this function). |
| [in] | dots | 1 for ".", 2 for "..". |
| [in] | cluster | Self cluster ("."), or parent cluster ("..", 0 if root). |
Definition at line 54 of file ra8_fs_fat_dirmk.c.
References k_dir_name_field_len, k_dir_off_attr, k_ra8_fs_attr_directory, k_ra8_fs_dir_entry_bytes, priv_entry_set_cluster_size(), and priv_fat_entry_stamp_create().
Referenced by internal_dir_cluster_init().
|
static |
Resolve a path to a removable subdirectory's entry and first cluster.
Resolves the parent, refuses the volume root, packs the leaf to 8.3, looks it up, and requires the matched entry to carry k_ra8_fs_attr_directory with a real first cluster. Split out of internal_fat_rmdir so both stay inside the function-size gate.
| [in] | handle | Mounted FAT12/16/32 volume. |
| [in] | path | Directory path to remove. |
| [out] | out | Receives the parent, the entry position and the entry. |
| [out] | out_cluster | The directory's own first cluster. |
| k_ra8_ok | Located; outputs populated. |
| k_ra8_err_invalid_arg | path is the root, is unstorable, or names a file rather than a directory. |
| k_ra8_err_not_found | No such entry. |
| k_ra8_err_protocol_error | The entry claims no data cluster. |
| k_ra8_err_* | Backend error. |
Definition at line 399 of file ra8_fs_fat_dirmk.c.
References dir_target_t::entry, k_cluster_first_data, k_dir_off_attr, k_ra8_err_invalid_arg, k_ra8_err_protocol_error, k_ra8_fs_attr_directory, 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_fat_rmdir().
|
static |
Remove an empty directory – the guarded body of ra8_fs_rmdir().
Validates arguments and the mount, then dispatches to the FAT or the exFAT directory remover (#605). exFAT rmdir landed with exFAT mkdir, in one change: before it, a volume mounted here never contained a directory this driver had made, so the verb had no reachable subject and could only have been exercised against a hand-crafted fixture.
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated directory path to remove. |
| k_ra8_ok | Directory removed. |
| k_ra8_err_null_ptr | handle or path was NULL. |
| k_ra8_err_invalid_state | Mount not in use. |
| k_ra8_err_* | See internal_fat_rmdir / priv_exfat_rmdir. |
Definition at line 513 of file ra8_fs_fat_dirmk.c.
References internal_fat_rmdir(), internal_rmdir_locked(), k_ra8_err_null_ptr, and k_ra8_fs_type_exfat.
Referenced by internal_rmdir_locked(), and ra8_fs_rmdir().
|
static |
Classify one already-loaded directory sector as empty / occupied / more.
A slot does not count as an occupant when it is deleted (0xE5), an attr-0x0F long-name slot, or one of the synthetic "." / ".." dot entries. Long-name slots are skipped rather than counted because ra8_fs_unlink() clears only the 8.3 entry, so a removed file leaves its whole LFN chain behind; counting those remnants would make a genuinely empty directory permanently un-removable. A live LFN chain is always followed by its own 8.3 entry in the same directory, so nothing real is missed by skipping it.
| [in] | m | Mounted volume (supplies the entries-per-sector bound). |
| [in] | buf | Whole-sector buffer holding directory entries. |
| k_dir_scan_used | A non-skippable entry was seen. |
| k_dir_scan_empty | The end-of-directory marker was seen first. |
| k_dir_scan_more | Sector exhausted with only skippable slots. |
Definition at line 288 of file ra8_fs_fat_dirmk.c.
References k_dir_marker_dot, k_dir_marker_free_perm, k_dir_marker_free_used, k_dir_off_attr, k_dir_off_name, k_dir_scan_empty, k_dir_scan_more, k_dir_scan_used, k_ra8_fs_attr_lfn, k_ra8_fs_dir_entry_bytes, and priv_dir_eps().
Referenced by internal_dir_is_empty().
|
nodiscard |
Create a directory at path.
Resolves all-but-the-last path component to an existing parent directory, then creates the final component as a new, empty subdirectory. Nested paths are supported ("/books/scifi"), provided each intermediate component already exists. A partial allocation is rolled back on failure, so the volume is never leaked.
On FAT the new directory is stamped with its "." and ".." links, and a leaf that is not 8.3-representable is stored as a long name, exactly as ra8_fs_open() stores one. On exFAT the new directory is one zeroed cluster – entry type 0x00 is end-of-directory, so that IS an empty directory – and there are no dot entries at all, because exFAT has none.
An existing name is REFUSED with k_ra8_err_exists, whether it is a file or a directory. mkdir is not a create-or-replace verb; ra8_fs_write_file() is the one that replaces.
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated directory path to create. |
| k_ra8_ok | Directory created. |
| k_ra8_err_null_ptr | handle or path was NULL. |
| k_ra8_err_invalid_state | Mount is not in use. |
| k_ra8_err_invalid_arg | The leaf is empty, longer than 247 characters, or holds a character no FAT name may carry. |
| 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 or volume is full. |
path. Definition at line 536 of file ra8_fs_fat_dirmk.c.
References internal_mkdir_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_mkdir().
Referenced by internal_native_mkdir(), internal_populate(), and ra8_fs_mkdir().
|
nodiscard |
Remove an empty directory at path.
The symmetric partner of ra8_fs_mkdir(): resolves all-but-the-last path component to an existing parent, requires the final component to be an existing directory, requires that directory to be empty, then frees its clusters and takes its entry away. Nested paths are supported ("/books/scifi").
The emptiness proof runs before anything is freed, so a refusal costs the volume nothing. Only remnants are discounted – FAT's deleted (0xE5) slots and orphaned long-name entries, exFAT's entries with the in-use bit clear – so a directory another implementation left remnants in is still removable, while anything live makes it k_ra8_err_not_empty. On FAT the directory's own "." and ".." links do not count either; exFAT has none to discount.
The volume root is not removable, and neither is a file: use ra8_fs_unlink() for those.
| [in] | handle | Mount handle. |
| [in] | path | NUL-terminated directory path to remove. |
| k_ra8_ok | Directory removed. |
| k_ra8_err_null_ptr | handle or path was NULL. |
| k_ra8_err_invalid_state | Mount is not in use. |
| k_ra8_err_invalid_arg | path is the root, or names a file rather than a directory. |
| 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 | Corrupt chain, or a directory entry that claims no data cluster. |
path. path no longer resolves and its cluster is free. path cannot be orphaned by this call: that file's directory entry still exists, so the emptiness check refuses the removal first. Definition at line 545 of file ra8_fs_fat_dirmk.c.
References internal_rmdir_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_rmdir().
Referenced by internal_native_rmdir(), and ra8_fs_rmdir().