|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
exFAT streaming write: grow the allocation, keep the entry set true. 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_pick_cluster (const ra8_fs_mount_t *m, uint64_t bmp_lba, uint32_t prefer, uint32_t *out) |
| Choose the next cluster to allocate, preferring the tail's successor. | |
| static ra8_err_t | internal_exfat_materialize_run (const ra8_fs_mount_t *m, uint32_t first, uint32_t alloc, uint32_t tail, uint32_t next) |
Write a real FAT chain over a contiguous run, ending at next. | |
| static ra8_err_t | internal_exfat_link_cluster (ra8_fs_file_t *file, uint32_t next) |
| Attach a freshly allocated cluster to the file's allocation. | |
| static ra8_err_t | internal_exfat_grow_one (ra8_fs_file_t *file) |
| Add one cluster to a file's allocation. | |
| 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. | |
| static ra8_err_t | internal_exfat_dir_survey (const ra8_fs_mount_t *m, const exfat_dir_t *dir, uint32_t *out_alloc, uint32_t *out_tail, uint8_t *out_nofat) |
| Survey a directory's current allocation into run coordinates. | |
| static ra8_err_t | internal_exfat_dir_link (const ra8_fs_mount_t *m, uint32_t first, uint32_t alloc, uint32_t tail, uint8_t *nofat, uint32_t next) |
Attach next to a directory's run, converting to a chain if needed. | |
| static ra8_err_t | internal_exfat_dir_relen (const ra8_fs_mount_t *m, const exfat_dir_t *dir, uint64_t new_bytes, uint8_t nofat) |
| Rewrite a grown directory's own Stream entry to describe its new run. | |
| static ra8_err_t | internal_exfat_dir_append (const ra8_fs_mount_t *m, const exfat_dir_t *dir, uint32_t alloc, uint32_t tail, uint8_t *nofat) |
| Allocate one cluster, zero it, link it to the run, seal the old tail. | |
| 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. | |
| static ra8_err_t | internal_exfat_cluster_at (ra8_fs_file_t *file, uint32_t idx, uint32_t *out) |
Resolve the cluster at chain index idx of an already-grown file. | |
| static ra8_err_t | internal_exfat_slice_at (ra8_fs_file_t *file, uint64_t pos, uint64_t *out_lba, uint32_t *out_off, uint32_t *out_room) |
Locate byte position pos on the volume, allocating to reach it. | |
| static ra8_err_t | internal_exfat_close_gap (ra8_fs_file_t *file) |
| Fill [valid_bytes, offset) with real zeros. | |
| 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. | |
| static void | internal_exfat_patch_stream (const ra8_fs_file_t *file, uint8_t *strm) |
| Patch a Stream-extension entry to describe the handle's current state. | |
| static ra8_err_t | internal_exfat_gather_set (const ra8_fs_file_t *file, uint8_t *set, exfat_setpos_t *at_file, exfat_setpos_t *at_stream) |
Read a file's entry set back into set, recording where it lives. | |
| ra8_err_t | priv_exfat_flush_set (ra8_fs_file_t *file) |
| Rewrite a file's entry set from the handle, checksum last. | |
exFAT streaming write: grow the allocation, keep the entry set true.
The engine behind ra8_fs_open(write|append) on an exFAT volume (#602). Three mechanisms live here and nothing else does:
References (every shorthand citation in this file):
NASA Power-of-Ten compliance:
Definition in file ra8_fs_fat_exfat_stream.c.
|
static |
Fill [valid_bytes, offset) with real zeros.
Only ever has work to do when a handle is positioned past the written prefix – an append to a file some other implementation left with ValidDataLength < DataLength. ValidDataLength is a PREFIX length, so the gap cannot be recorded as unwritten once bytes land beyond it; the only honest answer is to write the zeros a reader is entitled to see.
| [in,out] | file | Open exFAT handle in a writing mode. |
| k_ra8_ok | There is no gap left below file->offset. |
| k_ra8_err_no_mem | The volume had no cluster to grow into. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
file is non-NULL and its mount is an exFAT volume. Definition at line 745 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_slice_at(), k_ra8_ok, k_zero_sector, and priv_write_into_sector().
Referenced by priv_exfat_write_stream().
|
static |
Resolve the cluster at chain index idx of an already-grown file.
A contiguous file is arithmetic. A chained one walks the FAT from the forward waypoint the read path already maintains, so a sequential write costs one FAT lookup per cluster rather than one per cluster examined from the head.
| [in,out] | file | File to position within. |
| [in] | idx | Chain index (0 = the file's first cluster). |
| [out] | out | Receives the cluster number at idx. |
| k_ra8_ok | The cluster was resolved. |
| k_ra8_err_invalid_state | The chain ended before idx – the entry set and the FAT disagree. |
| k_ra8_err_* | FAT read failure. |
file and out are non-NULL; alloc_clusters > idx. idx. Definition at line 625 of file ra8_fs_fat_exfat_stream.c.
References k_cluster_first_data, k_ra8_err_invalid_state, k_ra8_ok, priv_fat_get(), and priv_is_eoc().
Referenced by internal_exfat_slice_at().
|
static |
Allocate one cluster, zero it, link it to the run, seal the old tail.
The on-disk half of a directory grow, split out so priv_exfat_grow_dir stays inside the function-size gate. Picks a cluster (preferring the tail's successor to stay contiguous), ZEROES it before anything links it – a directory cluster reads as its own contents, so a half-built one must never be reachable – marks it used, links it (converting the run to a FAT chain if contiguity broke, which clears nofat), and retires the old tail cluster's trailing end-of-directory markers so the walk crosses into the fresh cluster (#677).
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory being grown (its cluster is the run head). |
| [in] | alloc | Cluster count of the run before this call. |
| [in] | tail | Last cluster of the run before this call. |
| [in,out] | nofat | 1 when the run is contiguous; cleared if it converts. |
| k_ra8_ok | The run owns one more zeroed, reachable cluster. |
| k_ra8_err_no_mem | The volume has no free cluster. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
m and dir are non-NULL; [dir->cluster, dir->cluster+alloc) is the run. tail is the run's last cluster and alloc >= 1. Definition at line 533 of file ra8_fs_fat_exfat_stream.c.
References exfat_dir_t::cluster, internal_exfat_dir_link(), internal_exfat_pick_cluster(), k_ra8_ok, priv_alloc_hint_set(), priv_exfat_bitmap_lba(), priv_exfat_bitmap_mark(), priv_exfat_seal_cluster(), and priv_exfat_zero_cluster().
Referenced by priv_exfat_grow_dir().
|
static |
Attach next to a directory's run, converting to a chain if needed.
The directory counterpart of ::priv_exfat_link_cluster, and the home of the NoFatChain-vs-chain decision growth turns on. Three outcomes: the run is contiguous and next continues it (nothing to write – the run stays NoFatChain), the run is contiguous and next does NOT continue it (materialise a real FAT chain over the run, then clear the flag), or the run is already a chain (link the tail on). In every case next is capped with an end-of-chain marker once it is reachable.
| [in] | m | Mounted exFAT volume. |
| [in] | first | First cluster of the directory's run. |
| [in] | alloc | Cluster count of the run (>= 1). |
| [in] | tail | Last cluster of the run. |
| [in,out] | nofat | 1 on entry when the run is contiguous; cleared here when the run is converted to a FAT chain. |
| [in] | next | The newly allocated, already-zeroed cluster to attach. |
| k_ra8_ok | next is reachable from first. |
| k_ra8_err_* | FAT write failure. |
m is non-NULL; [first, first + alloc) is the directory's run. next is marked allocated in the bitmap already. next from first. Definition at line 406 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_materialize_run(), k_ra8_ok, priv_eoc_write(), and priv_fat_set().
Referenced by internal_exfat_dir_append().
|
static |
Rewrite a grown directory's own Stream entry to describe its new run.
Reads the directory's File-entry set back from its parent, patches the Stream entry's GeneralSecondaryFlags, ValidDataLength and DataLength – a directory's ValidDataLength equals its DataLength, and both equal the ALLOCATION – recomputes the SetChecksum over the patched bytes, and writes the set back. The set is guaranteed to sit in one cluster (priv_exfat_find_dir_space never splits one), so it is gathered by a straight cursor walk from the recorded head.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory whose own entry set is rewritten. |
| [in] | new_bytes | The run's new byte length (clusters * cluster bytes). |
| [in] | nofat | 1 when the run is still contiguous, else 0. |
| k_ra8_ok | The Stream entry now describes the run. |
| k_ra8_err_not_supported | The set is larger than this adapter rewrites. |
| k_ra8_err_* | Backend read/write failure. |
m is non-NULL; dir->self_cluster holds this directory's File entry. new_bytes. nofat is 1.Definition at line 462 of file ra8_fs_fat_exfat_stream.c.
References k_exfat_entry_bytes, k_exfat_max_set_bytes, k_exfat_off_file_csum, k_exfat_off_file_secnt, k_exfat_off_strm_valid, k_exfat_secflag_alloc, k_exfat_secflag_poss, k_exfat_set_writable, k_exfat_strm_off_dlen, k_exfat_strm_off_flags, k_ra8_err_not_supported, k_ra8_ok, priv_exfat_next_entry(), priv_exfat_set_checksum(), priv_exfat_write_dir_set(), priv_wr16(), priv_wr64(), exfat_dir_t::self_cluster, and exfat_dir_t::self_index.
Referenced by priv_exfat_grow_dir().
|
static |
Survey a directory's current allocation into run coordinates.
Fills first / alloc / tail / nofat the way an append survey fills a file handle, but from an exfat_dir_t: a contiguous run (contig_end != 0) is pure arithmetic, and a FAT-chained one (the root, or a run some earlier growth already converted) is walked to its tail. A directory always owns at least one cluster, so unlike the file survey there is no owns-nothing case to guard.
| [in] | m | Mounted exFAT volume. |
| [in] | dir | Directory whose allocation is surveyed. |
| [out] | out_alloc | Receives the cluster count of the run. |
| [out] | out_tail | Receives the last cluster of the run. |
| [out] | out_nofat | Receives 1 when the run is contiguous, else 0. |
| k_ra8_ok | The coordinates are populated. |
| k_ra8_err_protocol_error | The FAT chain points below the heap. |
| k_ra8_err_* | FAT read failure. |
Definition at line 335 of file ra8_fs_fat_exfat_stream.c.
References exfat_dir_t::cluster, exfat_dir_t::contig_end, ra8_fs_mount_t::count_of_clusters, k_cluster_first_data, k_ra8_err_protocol_error, k_ra8_ok, priv_fat_get(), and priv_is_eoc().
Referenced by priv_exfat_grow_dir().
|
static |
Read a file's entry set back into set, recording where it lives.
Walks file->entry_set_count entries from the recorded head with the ordinary directory cursor, so a set that straddles a cluster boundary is gathered correctly rather than by flat arithmetic that would run off the end of the first cluster.
| [in] | file | Open exFAT handle carrying the set's coordinates. |
| [out] | set | Receives entry_set_count * 32 bytes. |
| [out] | at_file | Receives the File entry's position. |
| [out] | at_stream | Receives the Stream entry's position. |
| k_ra8_ok | The set is in set and both positions are known. |
| k_ra8_err_* | Backend read failure, or the directory ended mid-set. |
set holds k_exfat_max_set_bytes. set mirrors the on-disk entries byte for byte. Definition at line 883 of file ra8_fs_fat_exfat_stream.c.
References exfat_cursor_t::cluster, exfat_cursor_t::entry_in_cluster, k_exfat_entry_bytes, k_ra8_ok, and priv_exfat_next_entry().
Referenced by priv_exfat_flush_set().
|
static |
Add one cluster to a file's allocation.
Picks a cluster, marks it in the bitmap FIRST and only then links it. That order is deliberate: a failure between the two leaks a cluster, which a later fsck reclaims, whereas the reverse order would leave a file pointing at a cluster the volume still believes is free – and the next allocation would hand it to someone else.
| [in,out] | file | File to grow by one cluster. |
| k_ra8_ok | The file owns one more cluster. |
| k_ra8_err_no_mem | The volume is full. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
file is non-NULL, in use, and its mount is an exFAT volume. Definition at line 242 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_link_cluster(), internal_exfat_pick_cluster(), k_ra8_ok, priv_alloc_hint_set(), priv_exfat_bitmap_lba(), and priv_exfat_bitmap_mark().
Referenced by priv_exfat_ensure_clusters().
|
static |
Attach a freshly allocated cluster to the file's allocation.
Three cases, and the middle one is the whole point of the format's NoFatChain bit: the file has no clusters yet (nothing to link), the new cluster continues the contiguous run (still nothing to link – writing FAT entries here would be writing bytes the spec says nobody may read), or contiguity is broken and the run has to become a real chain.
| [in,out] | file | File being grown; no_fat_chain may be cleared here. |
| [in] | next | The newly allocated cluster. |
| k_ra8_ok | The cluster is reachable from the file's head. |
| k_ra8_err_* | FAT write failure. |
file is non-NULL and its mount is an exFAT volume. next is marked allocated in the bitmap already. next from first_cluster. Definition at line 188 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_materialize_run(), k_ra8_ok, priv_eoc_write(), and priv_fat_set().
Referenced by internal_exfat_grow_one().
|
static |
Write a real FAT chain over a contiguous run, ending at next.
The reusable core of the NoFatChain conversion, on explicit run coordinates rather than a file handle, so both the file streaming path (::priv_exfat_link_cluster) and the directory growth path (::priv_exfat_dir_link, #677) drive the identical logic. Links every already-allocated cluster of the run to its successor – the run is contiguous, so a cluster's successor is the next integer – and the tail to next. The caller writes next's end-of-chain marker and clears the flag afterwards.
| [in] | m | Mounted exFAT volume. |
| [in] | first | First cluster of the contiguous run. |
| [in] | alloc | Cluster count of the run (>= 1). |
| [in] | tail | Last cluster of the run (first + alloc - 1). |
| [in] | next | The newly allocated cluster the tail must point at. |
| k_ra8_ok | The chain now spans the run and reaches next. |
| k_ra8_err_* | FAT write failure; the transition is incomplete. |
m is non-NULL; the run [first, first + alloc) is contiguous. tail is first + alloc - 1. next and every earlier cluster points at its successor. Definition at line 141 of file ra8_fs_fat_exfat_stream.c.
References k_ra8_ok, and priv_fat_set().
Referenced by internal_exfat_dir_link(), and internal_exfat_link_cluster().
|
static |
Patch a Stream-extension entry to describe the handle's current state.
Writes the four fields a stream changes – GeneralSecondaryFlags, FirstCluster, ValidDataLength and DataLength – as the full 64-bit lengths the format defines, so a file past 4 GiB records its real size (#676). NoFatChain is asserted only for a file that actually owns clusters: exFAT spec sec 7.4.4 requires FirstCluster 0 on an empty file, and a flag claiming a contiguous run of nothing is a claim fsck checks.
| [in] | file | File whose state the entry must describe. |
| [in,out] | strm | The 32-byte Stream-extension entry to patch in place. |
file and strm are non-NULL. strm was read back from the volume as part of this file's set. Definition at line 840 of file ra8_fs_fat_exfat_stream.c.
References k_exfat_off_strm_valid, k_exfat_secflag_alloc, k_exfat_secflag_poss, k_exfat_strm_off_clus, k_exfat_strm_off_dlen, k_exfat_strm_off_flags, priv_wr32(), and priv_wr64().
Referenced by priv_exfat_flush_set().
|
static |
Choose the next cluster to allocate, preferring the tail's successor.
Probes prefer first and falls back to the hinted bitmap scan. The probe is one sector read and it is what keeps a sequentially written file contiguous on a volume that has room for it.
| [in] | m | Mounted exFAT volume. |
| [in] | bmp_lba | First LBA (volume-relative) of the allocation bitmap. |
| [in] | prefer | Cluster to take if it is free; 0 asks for any. |
| [out] | out | Receives the chosen cluster number. |
| k_ra8_ok | A free cluster was chosen. |
| k_ra8_err_no_mem | The volume has no free cluster at all. |
| k_ra8_err_* | Backend read failure. |
m and out are non-NULL; m->type is exFAT. bmp_lba came from priv_exfat_bitmap_lba. prefer is one compound decision of two conditions; its vectors live with the tests that drive it, cited as libs/ra8_fs/src/ra8_fs_fat_exfat_stream.c@priv_exfat_pick_cluster.Definition at line 88 of file ra8_fs_fat_exfat_stream.c.
References ra8_fs_mount_t::count_of_clusters, k_cluster_first_data, k_ra8_ok, priv_exfat_bitmap_scan(), and priv_exfat_bitmap_test().
Referenced by internal_exfat_dir_append(), and internal_exfat_grow_one().
|
static |
Locate byte position pos on the volume, allocating to reach it.
The single place both the data loop and the gap-filling loop turn a file offset into a sector plus an offset inside it. It grows the allocation first, so a caller never has to ask whether the cluster it is about to write exists.
| [in,out] | file | Open exFAT handle. |
| [in] | pos | Byte position within the file (64-bit, #676). |
| [out] | out_lba | Receives the volume-relative sector holding pos. |
| [out] | out_off | Receives the byte offset of pos inside it. |
| [out] | out_room | Receives the bytes from pos to the sector's end. |
| k_ra8_ok | The position is backed by an allocated cluster. |
| k_ra8_err_no_mem | The volume had no cluster to grow into. |
| k_ra8_err_* | Bitmap, FAT, or backend failure. |
pos.Definition at line 691 of file ra8_fs_fat_exfat_stream.c.
References internal_exfat_cluster_at(), k_ra8_ok, priv_bps(), priv_cluster_bytes(), priv_cluster_to_lba(), and priv_exfat_ensure_clusters().
Referenced by internal_exfat_close_gap(), and priv_exfat_write_stream().
| 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_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_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_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().