|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
The exFAT streaming-write mechanism: entry-set positions and its helpers. More...
#include <stdint.h>#include "ra8_attributes.h"#include "ra8_fs.h"#include "ra8_fs_fat_types_internal.h"Go to the source code of this file.
Functions | |
| ra8_err_t | priv_exfat_bitmap_test (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t clus, uint8_t *out_free) |
| Read one allocation-bitmap bit: is this cluster free? | |
| ra8_err_t | priv_exfat_bitmap_scan (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t need, uint32_t *out_clus) |
| Find a contiguous free run, starting from the mount's next-free hint. | |
| ra8_err_t | priv_exfat_bitmap_mark (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t clus, uint32_t count) |
| Mark a contiguous cluster run as allocated in the bitmap. | |
| ra8_err_t | priv_exfat_grow_dir (const ra8_fs_mount_t *m, exfat_dir_t *dir) |
| Append one zeroed cluster to a directory, keeping its entry set true. | |
| ra8_err_t | priv_exfat_find_set (const ra8_fs_mount_t *m, const exfat_dir_t *dir, const char *path, exfat_setpos_t *pos, uint32_t max_pos, uint32_t *out_count, uint8_t *file_copy, uint8_t *strm_copy) |
| Locate a file's full directory-entry set with per-entry positions. | |
| ra8_err_t | priv_exfat_free_clusters (const ra8_fs_mount_t *m, const uint8_t *strm) |
| Free the cluster run / chain referenced by a Stream entry. | |
| 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) |
| Lay down a fresh File/Stream/Name entry set and report where it went. | |
| ra8_err_t | priv_exfat_open_write (ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file) |
| Open an exFAT file for writing: create, truncate, or position to append. | |
| ra8_err_t | priv_exfat_write_stream (ra8_fs_file_t *file, const uint8_t *buf, uint32_t len) |
| Stream bytes into an exFAT file, growing its allocation as needed. | |
| ra8_err_t | priv_exfat_ensure_clusters (ra8_fs_file_t *file, uint32_t need) |
Grow a file's allocation until it owns at least need clusters. | |
| ra8_err_t | priv_exfat_flush_set (ra8_fs_file_t *file) |
| Rewrite a file's entry set from the handle, checksum last. | |
The exFAT streaming-write mechanism: entry-set positions and its helpers.
exFAT streaming write (#602) is one self-contained mechanism with its own vocabulary, so it gets its own themed sub-header rather than being scattered alphabetically across ra8_fs_fat_protos_a_internal.h and its _b twin – the same reasoning that gave the timestamp and allocator mechanisms theirs. Everything the grow/flush engine needs is declared here, whichever translation unit defines it:
It is pulled in by the ra8_fs_fat_internal.h umbrella and by nothing outside this module.
References (every shorthand citation in this file):
Definition in file ra8_fs_fat_exfat_stream_internal.h.
| ra8_err_t priv_exfat_bitmap_mark | ( | const ra8_fs_mount_t * | m, |
| uint64_t | bmp_lba, | ||
| uint32_t | clus, | ||
| uint32_t | count ) |
Mark a contiguous cluster run as allocated in the bitmap.
Sets one bit per cluster, batching read-modify-write per bitmap sector. Per exFAT spec sec 7.1 the bitmap alone is authoritative for allocation state, so this – not a FAT edit – is what makes a cluster owned.
| [in] | m | Mounted exFAT volume. |
| [in] | bmp_lba | First LBA (volume-relative) of the bitmap. |
| [in] | clus | First cluster of the run. |
| [in] | count | Number of clusters to mark used. |
| k_ra8_ok | All bits set + written. |
| k_ra8_err_* | Backend read/write failure. |
m is non-NULL; the run is within the bitmap. count >= 1. count bits for the run read as 1. 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 ) |
Find a contiguous free run, starting from the mount's next-free hint.
Walks the bitmap from the hint and, only if that finds nothing, repeats from cluster index 0 – a full rescan rather than a wrap-around of the remainder, because a free run may STRADDLE the hint and a window that stopped there would report a full disk the volume does not have.
| [in] | m | Mounted exFAT volume. |
| [in] | bmp_lba | First LBA (volume-relative) of the bitmap. |
| [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 anywhere (volume full / too fragmented). |
| k_ra8_err_* | Backend read failure. |
m and out_clus are non-NULL; need >= 1. 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 ) |
Read one allocation-bitmap bit: is this cluster free?
The probe the contiguity-preserving allocator runs before anything else. Keeping a run contiguous is worth one sector read, because a file that stays contiguous keeps NoFatChain and therefore keeps the read path's O(1) cluster arithmetic.
| [in] | m | Mounted exFAT volume. |
| [in] | bmp_lba | First LBA (volume-relative) of the bitmap. |
| [in] | clus | Cluster number to test. |
| [out] | out_free | Receives 1 when the cluster is free, else 0. |
| k_ra8_ok | The bit was read; *out_free is 0 or 1. |
| k_ra8_err_* | Backend read failure. |
m and out_free are non-NULL; m->type is exFAT. clus is inside [2, 2 + count_of_clusters). 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_ensure_clusters | ( | ra8_fs_file_t * | file, |
| uint32_t | need ) |
Grow a file's allocation until it owns at least need clusters.
Takes clusters one at a time from the allocation bitmap, preferring the tail's successor so a run that can stay contiguous keeps its NoFatChain fast path, and materialising a real FAT chain over the run the moment it cannot. The streaming write path drives it to reach the cluster an offset lands in; the truncate path (#680) drives it to pre-size a file, which is why it lives in the header rather than staying private to the stream.
| [in,out] | file | File to grow; alloc_clusters, tail_cluster, first_cluster and no_fat_chain are updated in place. |
| [in] | need | Clusters the file must own on return (>= 1 to have effect). |
| k_ra8_ok | The file owns need clusters or more. |
| k_ra8_err_no_mem | The volume ran out before reaching need. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
file is non-NULL, in use, and its mount is an exFAT volume. file.Definition at line 277 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_grow_one(), and k_ra8_ok.
Referenced by internal_exfat_slice_at(), and internal_exfat_trunc().
| ra8_err_t priv_exfat_find_set | ( | const ra8_fs_mount_t * | m, |
| const exfat_dir_t * | dir, | ||
| const char * | path, | ||
| exfat_setpos_t * | pos, | ||
| uint32_t | max_pos, | ||
| uint32_t * | out_count, | ||
| uint8_t * | file_copy, | ||
| uint8_t * | strm_copy ) |
Locate a file's full directory-entry set with per-entry positions.
Walks the root directory like priv_exfat_find but records the (cluster, index) of every entry in the matched set – the File entry plus all its secondaries – so callers can rewrite them in place. Non-matching sets are skipped entry-by-entry, which keeps the cursor aligned.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory to search. |
| [in] | path | Target leaf name (ASCII); leading '/' stripped. |
| [out] | pos | Receives the positions (File entry first). |
| [in] | max_pos | Capacity of pos. |
| [out] | out_count | Receives the entry count (1 + SecondaryCount). |
| [out] | file_copy | Receives the 32-byte File entry. |
| [out] | strm_copy | Receives the 32-byte Stream-extension entry. |
| k_ra8_ok | Set found; outputs populated. |
| k_ra8_err_not_found | No matching set in dir. |
| k_ra8_err_no_mem | The set has more entries than max_pos. |
| k_ra8_err_protocol_error | No EOD marker appeared before the scan bound. |
| k_ra8_err_* | Backend read failure. |
dir locates an existing directory on this volume. pos holds *out_count valid positions. dir names (#605).Locate a file's full directory-entry set with per-entry positions.
Definition at line 194 of file ra8_fs_fat_exfat_mutate.c.
References exfat_cursor_t::cluster, exfat_cursor_t::entry_in_cluster, internal_exfat_try_set(), k_exfat_entry_bytes, k_exfat_entry_eod, k_exfat_entry_file, k_exfat_name_cap, k_exfat_scan_limit, k_ra8_err_not_found, k_ra8_err_protocol_error, k_ra8_ok, priv_exfat_cursor_init(), priv_exfat_needle_units(), priv_exfat_next_entry(), and exfat_cursor_t::scanned.
Referenced by internal_exfat_enter(), internal_exfat_rmdir_locate(), internal_setattr_exfat(), internal_stat_exfat(), internal_utime_exfat(), priv_exfat_open_write(), priv_exfat_rename(), and priv_exfat_unlink_at().
| ra8_err_t priv_exfat_flush_set | ( | ra8_fs_file_t * | file | ) |
Rewrite a file's entry set from the handle, checksum last.
Reads the set back through a cursor from the recorded head, patches the File entry's modification stamps and the Stream entry's flags, FirstCluster, ValidDataLength and DataLength, accumulates the SetChecksum over the PATCHED bytes, and only then writes the two entries down. Order matters: the checksum covers every byte the patch touched, so computing it before the patch produces a set a host fsck rejects.
| [in,out] | file | Open exFAT handle whose entry set is to be committed. |
| k_ra8_ok | The on-disk set describes the handle exactly. |
| k_ra8_err_* | Backend read/write failure. |
file is non-NULL, in use, and its mount is an exFAT volume. Definition at line 909 of file ra8_fs_fat_exfat_stream.c.
References exfat_setpos_t::cluster, exfat_setpos_t::index, internal_exfat_gather_set(), internal_exfat_patch_stream(), k_exfat_attr_archive, k_exfat_entry_bytes, k_exfat_max_set_bytes, k_exfat_off_file_attr, k_exfat_off_file_csum, k_ra8_ok, priv_exfat_file_stamp_write(), priv_exfat_set_checksum(), priv_exfat_write_dir_set(), and priv_wr16().
Referenced by internal_close_stamp(), internal_exfat_trunc(), internal_exfat_truncate(), and internal_write_locked().
| ra8_err_t priv_exfat_free_clusters | ( | const ra8_fs_mount_t * | m, |
| const uint8_t * | strm ) |
Free the cluster run / chain referenced by a Stream entry.
Contiguous (NoFatChain) files free ceil(DataLength / cluster bytes) bitmap bits from the first cluster; FAT-chained files walk the FAT and free each visited cluster. Per exFAT spec sec 7.1 the bitmap alone is authoritative, so the FAT entries themselves are left untouched.
| [in] | m | Mounted exFAT volume. |
| [in] | strm | The file's 32-byte Stream-extension entry. |
| k_ra8_ok | Clusters freed (or the file had none). |
| k_ra8_err_protocol_error | FAT chain exhausted the volume bound without EOC. |
| k_ra8_err_* | Bitmap or backend failure. |
m and strm are non-NULL. Free the cluster run / chain referenced by a Stream entry.
Definition at line 279 of file ra8_fs_fat_exfat_mutate.c.
References ra8_fs_mount_t::count_of_clusters, k_cluster_first_data, k_exfat_secflag_no_fat, k_exfat_strm_off_clus, k_exfat_strm_off_dlen, k_exfat_strm_off_flags, k_ra8_err_protocol_error, k_ra8_ok, priv_cluster_bytes(), priv_exfat_bitmap_clear(), priv_exfat_bitmap_lba(), priv_fat_get(), priv_is_eoc(), priv_rd32(), and priv_rd64().
Referenced by internal_exfat_free_run(), internal_exfat_truncate(), priv_exfat_rmdir(), and priv_exfat_unlink_at().
| ra8_err_t priv_exfat_grow_dir | ( | const ra8_fs_mount_t * | m, |
| exfat_dir_t * | dir ) |
Append one zeroed cluster to a directory, keeping its entry set true.
The directory counterpart of the file grow path, reusing its contiguous/NoFatChain->FAT-chain machinery (#677). Surveys the directory's run, prefers the tail's successor to stay contiguous, ZEROES the new cluster before linking it (a directory cluster reads as its own contents, so a half-built one must never be reachable), links it – converting the run to a real FAT chain if contiguity is broken – and rewrites the directory's own Stream entry so a later mount sees the larger run. The volume ROOT carries no such entry set (self_cluster 0) and only has its FAT chain extended.
| [in] | m | Mounted exFAT volume. |
| [in,out] | dir | Directory to grow; its contig_end is updated to reflect the new run (0 once it has become a FAT chain). |
| k_ra8_ok | The directory owns one more zeroed cluster. |
| k_ra8_err_no_mem | The volume has no free cluster. |
| k_ra8_err_not_supported | The directory's own set is larger than this adapter can rewrite. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
m and dir are non-NULL; m->type is exFAT. dir reaches the new cluster and it reads empty. Definition at line 566 of file ra8_fs_fat_exfat_stream.c.
References exfat_dir_t::cluster, exfat_dir_t::contig_end, internal_exfat_dir_append(), internal_exfat_dir_relen(), internal_exfat_dir_survey(), k_cluster_first_data, k_ra8_ok, priv_cluster_bytes(), and exfat_dir_t::self_cluster.
Referenced by priv_exfat_find_dir_space().
| 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 ) |
Lay down a fresh File/Stream/Name entry set and report where it went.
Finds a run of free directory slots, builds the set (typed entries, name hash, creation stamps, SetChecksum) and writes it. The caller gets the head position and the entry count back so a streaming writer can keep rewriting the same set as the file grows, instead of searching the directory again on every flush.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory the set is linked into. |
| [in] | name | Leaf name as UTF-16 code units (no leading '/'). |
| [in] | nlen | Name length in UTF-16 UNITS (1..k_exfat_name_cap), which is what NameLength counts (#606). |
| [out] | out_head | Receives the File entry's (cluster, index). |
| [out] | out_count | Receives the entry count (1 + SecondaryCount). |
| k_ra8_ok | Entry set written; outputs populated. |
| k_ra8_err_no_mem | No run of free directory slots big enough. |
| k_ra8_err_* | Backend read/write failure. |
m, dir, name, out_head and out_count are non-NULL. nlen is the unit count priv_exfat_name_to_units() produced, >= 1. dir holds a zero-length entry set for that name. 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().
| ra8_err_t priv_exfat_open_write | ( | ra8_fs_mount_t * | handle, |
| const char * | path, | ||
| ra8_fs_mode_t | mode, | ||
| ra8_fs_file_t ** | out_file ) |
Open an exFAT file for writing: create, truncate, or position to append.
The exFAT half of ra8_fs_open for the two writing modes. It locates the name's entry set, refuses a directory (a truncate would free the clusters holding its contents), and then either truncates the file in place – keeping its entry, and therefore its creation stamp – or seeks to DataLength for an append. A name that does not exist is created as a zero-length entry set, so the handle is usable before a single byte has been written.
| [in,out] | handle | Mounted exFAT volume. |
| [in] | path | Flat root-level name (ASCII); leading '/' stripped. |
| [in] | mode | k_ra8_fs_mode_write or k_ra8_fs_mode_append. |
| [out] | out_file | Receives the open handle. |
| k_ra8_ok | File open and positioned for mode. |
| k_ra8_err_invalid_arg | Empty or over-long name, or path is a directory. |
| k_ra8_err_no_mem | File table full, or no free directory slot. |
| k_ra8_err_not_supported | The existing entry set is larger than this adapter can rewrite. |
| k_ra8_err_* | Backend read/write failure. |
handle, path and out_file are non-NULL; the mount is in use. mode is a writing mode; read opens never reach here. Definition at line 412 of file ra8_fs_fat_exfat_openw.c.
References internal_exfat_open_created(), internal_exfat_open_found(), k_exfat_entry_bytes, k_exfat_name_cap, k_exfat_set_max_entries, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_err_not_found, k_ra8_ok, priv_exfat_find_set(), priv_exfat_name_to_units(), and priv_exfat_resolve_parent().
Referenced by priv_exfat_open().
| ra8_err_t priv_exfat_write_stream | ( | ra8_fs_file_t * | file, |
| const uint8_t * | buf, | ||
| uint32_t | len ) |
Stream bytes into an exFAT file, growing its allocation as needed.
The engine behind ra8_fs_write on an exFAT mount. It closes any gap between ValidDataLength and the write offset with real zeros first (the format expresses "not yet written" only as a PREFIX length, so a hole in the middle cannot be recorded and must not be left), then writes sector slice by sector slice, taking one more cluster from the allocation bitmap whenever the offset crosses into a cluster the file does not own yet.
| [in,out] | file | Open exFAT handle in a writing mode. |
| [in] | buf | Source bytes. |
| [in] | len | Number of bytes to write (> 0). |
| k_ra8_ok | All len bytes are on the volume. |
| k_ra8_err_no_mem | The volume has no free cluster left. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
file and buf are non-NULL; the handle is in use and writable. len and valid_bytes covers it. Definition at line 770 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_close_gap(), internal_exfat_slice_at(), k_ra8_ok, and priv_write_into_sector().