|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
exFAT allocation-bitmap primitives and directory entry-set construction. 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 uint16_t | internal_exfat_csum_add (uint16_t cs, uint8_t b) |
| One step of exFAT's rotate-right-then-add 16-bit checksum. | |
| uint16_t | priv_exfat_name_hash (const uint16_t *name, uint32_t nlen) |
| Compute the exFAT NameHash for a name in UTF-16 code units. | |
| uint16_t | priv_exfat_set_checksum (const uint8_t *set, uint32_t bytes) |
| Compute the SetChecksum over a built directory entry set. | |
| ra8_err_t | priv_exfat_find_bitmap (const ra8_fs_mount_t *m, uint32_t *out_clus, uint32_t *out_len) |
| Locate the allocation-bitmap entry in the exFAT root directory. | |
| static ra8_err_t | internal_exfat_bitmap_window (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t from, uint32_t need, uint32_t *out_clus) |
| Scan a window of the allocation bitmap for a contiguous free run. | |
| ra8_err_t | priv_exfat_bitmap_scan (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t need, uint32_t *out_clus) |
| Implementation of priv_exfat_bitmap_scan() – hinted pass, then a full rescan. | |
| ra8_err_t | priv_exfat_bmp_switch (const ra8_fs_mount_t *m, uint64_t lba, uint64_t *loaded, uint8_t *sec) |
Flush the cached bitmap sector and load lba if it changed. | |
| ra8_err_t | priv_exfat_bitmap_mark (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t clus, uint32_t count) |
| Implementation of priv_exfat_bitmap_mark() – one read-modify-write per sector. | |
| ra8_err_t | priv_exfat_bitmap_test (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t clus, uint8_t *out_free) |
| Implementation of priv_exfat_bitmap_test() – one sector read, one bit. | |
| static ra8_err_t | internal_exfat_read_entry (const ra8_fs_mount_t *m, uint32_t cluster, uint32_t idx, uint8_t *out) |
| Read one 32-byte directory entry by index within a cluster. | |
| static uint8_t | internal_exfat_slot_free (uint8_t type_byte) |
| True if a directory entry slot is free (end-of-dir or deleted). | |
| static ra8_err_t | internal_exfat_space_in_cluster (const ra8_fs_mount_t *m, uint32_t cluster, uint32_t need, uint32_t *out_idx) |
Scan one directory cluster for need consecutive free entries. | |
| static ra8_err_t | internal_exfat_scan_dir_space (const ra8_fs_mount_t *m, const exfat_dir_t *dir, uint32_t need, uint32_t *out_clus, uint32_t *out_idx) |
Scan a directory's existing clusters for need consecutive free slots. | |
| ra8_err_t | priv_exfat_find_dir_space (const ra8_fs_mount_t *m, const exfat_dir_t *dir, uint32_t need, uint32_t *out_clus, uint32_t *out_idx) |
Find need consecutive free entry slots inside one directory cluster. | |
| static uint32_t | internal_exfat_build_set (uint8_t *set, const uint16_t *name, uint32_t nlen) |
Build a zero-length File + Stream + Name entry set into set. | |
| ra8_err_t | priv_exfat_write_dir_set (const ra8_fs_mount_t *m, uint32_t cluster, uint32_t idx, const uint8_t *set, uint32_t bytes) |
| Write a pre-built entry set into consecutive directory entries. | |
| ra8_err_t | priv_exfat_link (const ra8_fs_mount_t *m, const exfat_dir_t *dir, const uint16_t *name, uint32_t nlen, exfat_setpos_t *out_head, uint32_t *out_count) |
| Implementation of priv_exfat_link() – one directory-slot scan, one set write. | |
exFAT allocation-bitmap primitives and directory entry-set construction.
The two things every exFAT write needs before it can put a byte anywhere: somewhere to put it (the allocation bitmap – locate, probe, scan, mark) and something to name it (the File + Stream + Name directory entry set – build, checksum, place). The streaming engine that drives them lives in ra8_fs_fat_exfat_stream.c.
Definition in file ra8_fs_fat_exfat_write.c.
|
static |
Scan a window of the allocation bitmap for a contiguous free run.
Walks cluster indices [from, m->count_of_clusters) looking for need consecutive clear bits, loading each bitmap sector once. Assumes a contiguous bitmap (true for a freshly formatted volume).
| [in] | m | Mounted exFAT volume. |
| [in] | bmp_lba | First LBA (volume-relative) of the bitmap. |
| [in] | from | Cluster INDEX (0-based) to begin the walk at. |
| [in] | need | Number of contiguous free clusters required. |
| [out] | out_clus | First cluster of the found run. |
| k_ra8_ok | A run of need free clusters was found. |
| k_ra8_err_no_mem | No such run in this window. |
| k_ra8_err_* | Backend read failure. |
m and out_clus are non-NULL; need >= 1. from is a cluster index, not a cluster number. Definition at line 131 of file ra8_fs_fat_exfat_write.c.
References ra8_fs_mount_t::count_of_clusters, k_cluster_first_data, k_exfat_bit_mask, k_exfat_bit_shift, k_ra8_err_no_mem, k_ra8_ok, priv_bps(), priv_read_sector(), and priv_sec_io().
Referenced by priv_exfat_bitmap_scan().
|
static |
Build a zero-length File + Stream + Name entry set into set.
Fills the typed entries, the name hash, the creation stamps and the trailing SetChecksum for a file that owns NO clusters yet: FirstCluster 0, DataLength 0, ValidDataLength 0 and GeneralSecondaryFlags = AllocationPossible with NoFatChain CLEAR. That is what exFAT spec sec 7.4.4 requires of an empty file, and it is the honest starting point for a stream: the first priv_exfat_flush_set after a byte lands rewrites the three fields and sets NoFatChain if the run is still contiguous.
| [out] | set | Buffer (>= k_exfat_max_set_bytes). |
| [in] | name | File 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. |
| >0 | Number of bytes written into set. |
set and name are non-NULL; set is large enough. nlen is the unit count priv_utf8_to_utf16() produced, and >= 1. set holds a complete entry set with a valid SetChecksum. Definition at line 476 of file ra8_fs_fat_exfat_write.c.
References k_exfat_attr_archive, 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_secflag_poss, k_exfat_strm_off_flags, k_exfat_strm_off_nlen, priv_exfat_file_stamp_create(), priv_exfat_name_hash(), priv_exfat_set_checksum(), and priv_wr16().
Referenced by priv_exfat_link().
|
static |
One step of exFAT's rotate-right-then-add 16-bit checksum.
Used for both the directory SetChecksum and the name hash.
| [in] | cs | Running checksum. |
| [in] | b | Next byte. |
| 0..0xFFFF | The folded value. |
cs is the prior running value. Definition at line 42 of file ra8_fs_fat_exfat_write.c.
References k_exfat_csum_hi_bit.
Referenced by priv_exfat_name_hash(), and priv_exfat_set_checksum().
|
static |
Read one 32-byte directory entry by index within a cluster.
Reads the containing sector and copies out the addressed entry.
| [in] | m | Mounted exFAT volume. |
| [in] | cluster | Directory cluster. |
| [in] | idx | Entry index within the cluster. |
| [out] | out | Receives the entry. |
| k_ra8_ok | Entry read. |
| k_ra8_err_* | Backend read failure. |
idx is within the cluster's entry capacity. Definition at line 270 of file ra8_fs_fat_exfat_write.c.
References k_exfat_entry_bytes, k_ra8_ok, priv_bps(), priv_byte_copy(), priv_cluster_to_lba(), priv_read_sector(), and priv_sec_io().
Referenced by internal_exfat_space_in_cluster().
|
static |
Scan a directory's existing clusters for need consecutive free slots.
The inner walk of priv_exfat_find_dir_space, split out so the grow loop that wraps it stays small. Walks dir cluster by cluster and reports k_ra8_err_no_mem when its CURRENT run has no room – it never grows the directory itself; that is the caller's job.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory to search at its current size. |
| [in] | need | Number of consecutive free entries required. |
| [out] | out_clus | Receives the cluster holding the run. |
| [out] | out_idx | Receives the run's first entry index in that cluster. |
| k_ra8_ok | A run was found at the current size. |
| k_ra8_err_no_mem | The directory's current run has no run of need. |
| k_ra8_err_* | Backend read failure. |
need >= 1. Definition at line 390 of file ra8_fs_fat_exfat_write.c.
References exfat_dir_t::cluster, exfat_dir_t::contig_end, internal_exfat_space_in_cluster(), k_exfat_scan_limit, k_ra8_err_no_mem, k_ra8_err_not_found, k_ra8_ok, and priv_exfat_step_cluster().
Referenced by priv_exfat_find_dir_space().
|
static |
True if a directory entry slot is free (end-of-dir or deleted).
A slot is reusable when it is the end-of-directory marker or has bit 7 clear.
| [in] | type_byte | Entry type byte (entry[0]). |
| 1 | Slot is free. |
| 0 | Slot is in use. |
type_byte is entry[0]. type_byte. Definition at line 300 of file ra8_fs_fat_exfat_write.c.
References k_exfat_entry_eod, and k_exfat_inuse_bit.
Referenced by internal_exfat_space_in_cluster().
|
static |
Scan one directory cluster for need consecutive free entries.
Inner half of priv_exfat_find_dir_space, split out so the outer walk stays inside the nesting and statement budgets.
| [in] | m | Mounted exFAT volume. |
| [in] | cluster | Directory cluster to scan. |
| [in] | need | Number of consecutive free entries required. |
| [out] | out_idx | Entry index of the run start within cluster. |
| k_ra8_ok | A run of need free slots starts at *out_idx. |
| k_ra8_err_no_mem | No such run in this cluster. |
| k_ra8_err_* | Backend read failure. |
m and out_idx are non-NULL; need >= 1. cluster belongs to the directory being searched. Definition at line 333 of file ra8_fs_fat_exfat_write.c.
References internal_exfat_read_entry(), internal_exfat_slot_free(), k_exfat_entry_bytes, k_ra8_err_no_mem, k_ra8_ok, and priv_cluster_bytes().
Referenced by internal_exfat_scan_dir_space().
| ra8_err_t priv_exfat_bitmap_mark | ( | const ra8_fs_mount_t * | m, |
| uint64_t | bmp_lba, | ||
| uint32_t | clus, | ||
| uint32_t | count ) |
Implementation of priv_exfat_bitmap_mark() – one read-modify-write per sector.
Mark a contiguous cluster run as allocated in the bitmap.
Definition at line 213 of file ra8_fs_fat_exfat_write.c.
References k_cluster_first_data, k_exfat_bit_mask, k_exfat_bit_shift, k_ra8_ok, priv_bps(), priv_exfat_bmp_switch(), priv_sec_io(), and priv_write_sector().
Referenced by internal_exfat_dir_alloc(), internal_exfat_dir_append(), and internal_exfat_grow_one().
| ra8_err_t priv_exfat_bitmap_scan | ( | const ra8_fs_mount_t * | m, |
| uint64_t | bmp_lba, | ||
| uint32_t | need, | ||
| uint32_t * | out_clus ) |
Implementation of priv_exfat_bitmap_scan() – hinted pass, then a full rescan.
Find a contiguous free run, starting from the mount's next-free hint.
Definition at line 170 of file ra8_fs_fat_exfat_write.c.
References ra8_fs_mount_t::count_of_clusters, internal_exfat_bitmap_window(), k_cluster_first_data, k_ra8_err_no_mem, and priv_alloc_hint_get().
Referenced by internal_exfat_dir_alloc(), and internal_exfat_pick_cluster().
| ra8_err_t priv_exfat_bitmap_test | ( | const ra8_fs_mount_t * | m, |
| uint64_t | bmp_lba, | ||
| uint32_t | clus, | ||
| uint8_t * | out_free ) |
Implementation of priv_exfat_bitmap_test() – one sector read, one bit.
Read one allocation-bitmap bit: is this cluster free?
Definition at line 233 of file ra8_fs_fat_exfat_write.c.
References k_cluster_first_data, k_exfat_bit_mask, k_exfat_bit_shift, k_ra8_ok, priv_bps(), priv_read_sector(), and priv_sec_io().
Referenced by internal_exfat_pick_cluster().
| ra8_err_t priv_exfat_bmp_switch | ( | const ra8_fs_mount_t * | m, |
| uint64_t | lba, | ||
| uint64_t * | loaded, | ||
| uint8_t * | sec ) |
Flush the cached bitmap sector and load lba if it changed.
Writes the dirty cached sector before reading the newly requested one.
| [in] | m | Mounted exFAT volume. |
| [in] | lba | Bitmap sector wanted next. |
| [in,out] | loaded | Currently-cached LBA (UINT32_MAX if none). |
| [in,out] | sec | Cached sector buffer. |
| k_ra8_ok | sec now holds lba. |
| k_ra8_err_* | Backend read/write failure. |
sec matches loaded on entry. sec holds lba; the previous sector was written if dirty. loaded == lba. Definition at line 192 of file ra8_fs_fat_exfat_write.c.
References k_ra8_ok, priv_read_sector(), and priv_write_sector().
Referenced by priv_exfat_bitmap_clear(), and priv_exfat_bitmap_mark().
| ra8_err_t priv_exfat_find_bitmap | ( | const ra8_fs_mount_t * | m, |
| uint32_t * | out_clus, | ||
| uint32_t * | out_len ) |
Locate the allocation-bitmap entry in the exFAT root directory.
Streams the root directory for the 0x81 entry and returns its data run.
| [in] | m | Mounted exFAT volume. |
| [out] | out_clus | First cluster of the allocation bitmap. |
| [out] | out_len | Bitmap length in bytes. |
| k_ra8_ok | Bitmap located. |
| k_ra8_err_not_found | No allocation-bitmap entry. |
| k_ra8_err_* | Backend read failure. |
Definition at line 81 of file ra8_fs_fat_exfat_write.c.
References k_exfat_entry_bitmap, k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_scan_limit, k_exfat_strm_off_clus, k_exfat_strm_off_dlen, k_ra8_err_not_found, k_ra8_ok, priv_exfat_cursor_init(), priv_exfat_dir_root(), priv_exfat_next_entry(), priv_rd32(), and exfat_cursor_t::scanned.
Referenced by internal_exfat_dir_alloc(), internal_space_exfat_free(), priv_check_exfat(), and priv_exfat_bitmap_lba().
| ra8_err_t priv_exfat_find_dir_space | ( | const ra8_fs_mount_t * | m, |
| const exfat_dir_t * | dir, | ||
| uint32_t | need, | ||
| uint32_t * | out_clus, | ||
| uint32_t * | out_idx ) |
Find need consecutive free entry slots inside one directory cluster.
Walks dir cluster by cluster, scanning each for a run of reusable slots – end-of-directory markers and retired entries both qualify. A set is never split across two clusters, so the run must fit inside one. When no existing cluster has room, the directory is GROWN one zeroed cluster at a time (priv_exfat_grow_dir) and rescanned, so k_ra8_err_no_mem now means the VOLUME is full, not merely that the directory was (#677). One grow always yields at least k_exfat_set_writable free slots – a fresh cluster holds far more than any set needs – so the retry is bounded by k_exfat_dir_grow_max.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory to search (its own set location grows it). |
| [in] | need | Number of consecutive free entries required. |
| [out] | out_clus | Receives the cluster holding the run. |
| [out] | out_idx | Receives the run's first entry index in that cluster. |
| k_ra8_ok | A run was found (after growing, if it had to). |
| k_ra8_err_no_mem | The volume has no free cluster to grow into. |
| k_ra8_err_* | Bitmap or backend read/write failure. |
need >= 1. Definition at line 420 of file ra8_fs_fat_exfat_write.c.
References internal_exfat_scan_dir_space(), k_exfat_dir_grow_max, k_ra8_err_no_mem, k_ra8_ok, and priv_exfat_grow_dir().
Referenced by internal_exfat_place_rename(), priv_exfat_link(), and priv_exfat_mkdir().
| ra8_err_t priv_exfat_link | ( | const ra8_fs_mount_t * | m, |
| const exfat_dir_t * | dir, | ||
| const uint16_t * | name, | ||
| uint32_t | nlen, | ||
| exfat_setpos_t * | out_head, | ||
| uint32_t * | out_count ) |
Implementation of priv_exfat_link() – one directory-slot scan, one set write.
Lay down a fresh File/Stream/Name entry set and report where it went.
Definition at line 544 of file ra8_fs_fat_exfat_write.c.
References exfat_setpos_t::cluster, exfat_setpos_t::index, internal_exfat_build_set(), k_exfat_max_set_bytes, k_exfat_name_per_entry, k_ra8_ok, priv_exfat_find_dir_space(), and priv_exfat_write_dir_set().
Referenced by internal_exfat_open_created().
| uint16_t priv_exfat_name_hash | ( | const uint16_t * | name, |
| uint32_t | nlen ) |
Compute the exFAT NameHash for a name in UTF-16 code units.
Hashes the up-cased UTF-16LE name (low then high byte per unit), up-casing through priv_exfat_upcase_unit – the volume's own table, which is what the specification defines the hash over.
Up-casing with an ASCII-only rule, which is what this did, stored a hash no compliant reader recomputes for any name outside ASCII: the host could see the file listed and then fail to find it, because the hash is the index it probes with (#606).
| [in] | name | File name as UTF-16 code units. |
| [in] | nlen | Name length in UTF-16 units. |
| 0..0xFFFF | The hash value. |
name is non-NULL and holds at least nlen units. Definition at line 49 of file ra8_fs_fat_exfat_write.c.
References internal_exfat_csum_add(), k_utf_byte_mask, k_utf_byte_shift, and priv_exfat_upcase_unit().
Referenced by internal_exchk_verify_set(), internal_exfat_build_dir_set(), internal_exfat_build_rename_set(), and internal_exfat_build_set().
| uint16_t priv_exfat_set_checksum | ( | const uint8_t * | set, |
| uint32_t | bytes ) |
Compute the SetChecksum over a built directory entry set.
Folds every byte except the File entry's checksum field (bytes 2-3).
| [in] | set | Contiguous entry-set bytes (File + Stream + Name entries). |
| [in] | bytes | Total byte count of the set. |
| 0..0xFFFF | The checksum. |
set is non-NULL and at least bytes long. bytes is a multiple of the entry size. set is unmodified. Definition at line 65 of file ra8_fs_fat_exfat_write.c.
References internal_exfat_csum_add(), and k_exfat_off_file_csum.
Referenced by internal_exchk_verify_set(), internal_exfat_build_dir_set(), internal_exfat_build_rename_set(), internal_exfat_build_set(), internal_exfat_dir_relen(), internal_setattr_exfat(), internal_utime_exfat(), and priv_exfat_flush_set().
| ra8_err_t priv_exfat_write_dir_set | ( | const ra8_fs_mount_t * | m, |
| uint32_t | cluster, | ||
| uint32_t | idx, | ||
| const uint8_t * | set, | ||
| uint32_t | bytes ) |
Write a pre-built entry set into consecutive directory entries.
Read-modify-writes each entry slot so neighbouring entries are preserved.
| [in] | m | Mounted exFAT volume. |
| [in] | cluster | Directory cluster holding the run. |
| [in] | idx | Entry index of the run start. |
| [in] | set | Built entry-set bytes. |
| [in] | bytes | Total size of the set. |
| k_ra8_ok | Entries written. |
| k_ra8_err_* | Backend read/write failure. |
m and set are non-NULL; the run fits in the cluster. bytes is a multiple of the entry size. Definition at line 517 of file ra8_fs_fat_exfat_write.c.
References k_exfat_entry_bytes, k_ra8_ok, priv_bps(), priv_byte_copy(), priv_cluster_to_lba(), priv_read_sector(), priv_sec_io(), and priv_write_sector().
Referenced by internal_exfat_dir_relen(), internal_exfat_place_rename(), internal_exfat_put_entry(), internal_setattr_exfat(), internal_utime_exfat(), priv_exfat_flush_set(), priv_exfat_link(), priv_exfat_mkdir(), and priv_exfat_set_label().