|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
ra8_fs_truncate: shrink or grow an open file to an arbitrary length. More...
#include <stddef.h>#include <stdint.h>#include "ra8_attributes.h"#include "ra8_fs.h"#include "ra8_fs_fat_internal.h"#include "ra8_fs_meta.h"Go to the source code of this file.
Functions | |
| static uint64_t | internal_trunc_clusters (uint64_t bytes, uint32_t cbytes) |
Clusters needed to hold bytes at cbytes bytes per cluster. | |
| static ra8_err_t | internal_trunc_walk (const ra8_fs_mount_t *m, uint32_t start, uint32_t idx, uint32_t *out) |
Walk idx clusters forward along a chain from start. | |
| static ra8_err_t | internal_trunc_zero_span (const ra8_fs_mount_t *m, uint32_t cluster, uint32_t lo, uint32_t hi) |
| Write real zeros over the byte range [lo, hi) inside one cluster. | |
| static ra8_err_t | internal_fat_trunc_shrink (ra8_fs_file_t *file, uint32_t new_size, uint32_t cbytes) |
Free the cluster tail past new_size on a FAT file. | |
| static ra8_err_t | internal_fat_trunc_extend (ra8_fs_file_t *file, uint32_t tail, uint32_t have, uint32_t new_nclus, uint32_t cbytes) |
Append zeroed clusters to a FAT file until it owns new_nclus. | |
| static ra8_err_t | internal_fat_trunc_grow (ra8_fs_file_t *file, uint32_t new_size, uint32_t cbytes) |
Grow a FAT file to new_size, zero-filling [old_size, new_size). | |
| static ra8_err_t | internal_fat_trunc_commit (ra8_fs_file_t *file) |
| Rewrite a FAT file's directory entry after its length changed. | |
| static ra8_err_t | internal_fat_trunc (ra8_fs_file_t *file, uint32_t new_size) |
Truncate a FAT file to new_size and commit its directory entry. | |
| static ra8_err_t | internal_exfat_free_run (const ra8_fs_mount_t *m, uint32_t first, uint64_t nbytes, uint8_t nofat) |
| Release a cluster run by describing it as a Stream-extension entry. | |
| static ra8_err_t | internal_exfat_shrink_chain_tail (ra8_fs_file_t *file, uint32_t new_nclus, uint32_t cbytes) |
Trim a FAT-chained exFAT file to new_nclus clusters. | |
| static ra8_err_t | internal_exfat_trunc_shrink (ra8_fs_file_t *file, uint64_t new_size, uint32_t cbytes) |
Free an exFAT file's cluster tail past new_size. | |
| static ra8_err_t | internal_exfat_trunc (ra8_fs_file_t *file, uint64_t new_size) |
Truncate an exFAT file to new_size and flush its entry set. | |
| static ra8_err_t | internal_truncate_locked (ra8_fs_file_t *file, uint64_t new_size) |
Truncate the file behind file – the guarded body of ra8_fs_truncate. | |
| ra8_err_t | ra8_fs_truncate (ra8_fs_file_t *file, uint64_t new_size) |
Set an open file's length to new_size, shrinking or growing it. | |
ra8_fs_truncate: shrink or grow an open file to an arbitrary length.
The ftruncate() verb, in both directions, on both filesystems (#680). Until now the only truncation was truncate-to-zero on open(write), and a file could not be given a length between "zero" and "everything a writer streamed into it": ra8_fs_seek() clamps to the current size, so a cursor cannot be placed past EOF to extend, and there was no verb to trim to N > 0 bytes.
The shrink half returns the tail clusters to the volume and lowers the recorded length. The grow half is where the two filesystems differ, and both differences are the format speaking:
References (every shorthand citation in this file):
NASA Power-of-Ten compliance:
Definition in file ra8_fs_fat_truncate.c.
|
static |
Release a cluster run by describing it as a Stream-extension entry.
priv_exfat_free_clusters already frees either a contiguous run or a FAT chain given a file's Stream entry, so the shrink path hands it a Stream entry describing exactly the SUB-run to release: the first cluster, a byte length whose ceiling is the run's cluster count, and the NoFatChain flag that selects contiguous-count vs chain-walk freeing. Nothing on disk is a real entry – it is a 32-byte argument.
| [in] | m | Mounted exFAT volume. |
| [in] | first | First cluster of the run to free. |
| [in] | nbytes | Byte length whose cluster ceiling is the run length (> 0). |
| [in] | nofat | 1 to free a contiguous run, 0 to walk a FAT chain. |
| k_ra8_ok | The run's clusters read as free in the allocation bitmap. |
| k_ra8_err_* | Bitmap or backend failure. |
m is non-NULL; first is a real data cluster; nbytes > 0. nofat is 0 the chain from first terminates at an EOC marker. Definition at line 515 of file ra8_fs_fat_truncate.c.
References k_exfat_entry_bytes, k_exfat_secflag_alloc, k_exfat_secflag_poss, k_exfat_strm_off_clus, k_exfat_strm_off_dlen, k_exfat_strm_off_flags, priv_exfat_free_clusters(), priv_wr32(), and priv_wr64().
Referenced by internal_exfat_shrink_chain_tail(), and internal_exfat_trunc_shrink().
|
static |
Trim a FAT-chained exFAT file to new_nclus clusters.
The chained arm of the shrink, split out so ::priv_exfat_trunc_shrink stays inside the statement budget. Walks to the survivor's new tail, caps it with an end-of-chain marker, and frees the remainder off the allocation bitmap by walking the FAT from the tail's old successor. The freed clusters keep their stale FAT links – the bitmap is exFAT's authority (spec sec 7.1) and nothing follows a free cluster's chain.
| [in,out] | file | Chained file being shrunk; tail_cluster is updated. |
| [in] | new_nclus | Clusters to keep (>= 1, < the current allocation). |
| [in] | cbytes | Bytes per cluster. |
| k_ra8_ok | The survivor ends at a fresh EOC and the tail is freed. |
| k_ra8_err_* | Bitmap, FAT, or backend error. |
file is non-NULL, chained (no_fat_chain == 0), on an exFAT volume. Definition at line 554 of file ra8_fs_fat_truncate.c.
References internal_exfat_free_run(), internal_trunc_walk(), k_ra8_ok, priv_eoc_write(), priv_fat_get(), and priv_fat_set().
Referenced by internal_exfat_trunc_shrink().
|
static |
Truncate an exFAT file to new_size and flush its entry set.
Shrink frees the tail; grow takes clusters from the allocation bitmap (converting a run that outgrows its contiguous space to a FAT chain, exactly as a streaming write does) and raises DataLength alone – ValidDataLength stays at the written prefix, so the read path serves the grown gap as zero without a byte being written for it (exFAT spec sec 7.4.5). Either way the entry set is rewritten so a later mount sees the new length.
| [in,out] | file | Open exFAT file handle. |
| [in] | new_size | Desired length in bytes. |
| k_ra8_ok | The file is new_size bytes and its set matches. |
| k_ra8_err_no_mem | A grow ran out of free clusters. |
| k_ra8_err_* | Bitmap, FAT, or backend error. |
file is non-NULL, in use, and opened for writing on an exFAT volume. Definition at line 676 of file ra8_fs_fat_truncate.c.
References internal_exfat_trunc_shrink(), internal_trunc_clusters(), k_ra8_err_no_mem, k_ra8_ok, priv_cluster_bytes(), priv_exfat_ensure_clusters(), and priv_exfat_flush_set().
|
static |
Free an exFAT file's cluster tail past new_size.
A contiguous run keeps [first, first + new_nclus) and frees the rest by count; a FAT-chained run re-terminates the survivor's tail and walks the freed remainder off the bitmap. Shrinking to zero drops the whole allocation and returns the handle to the empty shape a fresh open(write) produces.
| [in,out] | file | File being shrunk; allocation fields are updated. |
| [in] | new_size | New length in bytes (< size_bytes). |
| [in] | cbytes | Bytes per cluster. |
| k_ra8_ok | The file owns exactly the clusters new_size needs. |
| k_ra8_err_* | Bitmap, FAT, or backend error. |
file is non-NULL, in use, and on an exFAT volume. Definition at line 607 of file ra8_fs_fat_truncate.c.
References internal_exfat_free_run(), internal_exfat_shrink_chain_tail(), internal_trunc_clusters(), and k_ra8_ok.
Referenced by internal_exfat_trunc().
|
static |
Truncate a FAT file to new_size and commit its directory entry.
Dispatches to the shrink or grow branch, resets the read accelerator (a shrink can free the cluster it cached, a grow moves the tail), and rewrites the directory entry once.
| [in,out] | file | Open FAT file handle. |
| [in] | new_size | Desired length in bytes. |
| k_ra8_ok | The file is new_size bytes and its entry matches. |
| k_ra8_err_* | Backend, FAT, or no-memory error. |
file is non-NULL, in use, and opened for writing on a FAT volume. Definition at line 462 of file ra8_fs_fat_truncate.c.
References internal_fat_trunc_commit(), internal_fat_trunc_grow(), internal_fat_trunc_shrink(), k_ra8_ok, and priv_cluster_bytes().
Referenced by internal_truncate_locked().
|
static |
Rewrite a FAT file's directory entry after its length changed.
Patches the entry's first cluster and size, and stamps the write time – a truncate is a content change even when no byte is written, so an mtime that still described the old contents would be a lie (#601). Leaves the handle dirty so close flushes FSInfo.
| [in,out] | file | File whose entry must match its new length. |
| k_ra8_ok | The on-disk entry reports the new first cluster and size. |
| k_ra8_err_* | Backend read/write failure. |
file is non-NULL; dir_entry_lba / dir_entry_idx locate its entry. Definition at line 418 of file ra8_fs_fat_truncate.c.
References k_ra8_ok, priv_entry_set_cluster_size(), priv_fat_entry_stamp_write(), priv_read_sector(), priv_sec_walk(), and priv_write_sector().
Referenced by internal_fat_trunc().
|
static |
Append zeroed clusters to a FAT file until it owns new_nclus.
Allocates the first cluster when the file has none, then links a fresh end-of-chain cluster on at a time, zeroing each as it is created so the grown region reads back as zero. One forward pass, so the cost is linear in the clusters added, not in the file's length.
| [in,out] | file | File being grown; first_cluster is set when empty. |
| [in] | tail | Current tail cluster (ignored when have is 0). |
| [in] | have | Clusters the file already owns. |
| [in] | new_nclus | Clusters the file must own on return. |
| [in] | cbytes | Bytes per cluster. |
| k_ra8_ok | The file owns new_nclus zeroed clusters. |
| k_ra8_err_no_mem | The volume ran out of free clusters. |
| k_ra8_err_* | Backend or FAT error. |
file is non-NULL and on a FAT12/16/32 volume. tail is the current tail. have up reads as zero. new_nclus, itself bounded by the volume.Definition at line 298 of file ra8_fs_fat_truncate.c.
References internal_trunc_zero_span(), k_ra8_ok, priv_alloc_eoc_cluster(), and priv_fat_set().
Referenced by internal_fat_trunc_grow().
|
static |
Grow a FAT file to new_size, zero-filling [old_size, new_size).
Two things must read as zero: the slack of the last old cluster past the old length, and every newly allocated cluster. The slack is cleared first (a read-modify-write that keeps the real file data below it), then the chain is extended from that same cluster so it is walked only once.
| [in,out] | file | File being grown; first_cluster / size_bytes move. |
| [in] | new_size | New length in bytes (> size_bytes). |
| [in] | cbytes | Bytes per cluster. |
| k_ra8_ok | The file is new_size bytes and the gap reads zero. |
| k_ra8_err_no_mem | The volume ran out of free clusters. |
| k_ra8_err_* | Backend or FAT error. |
file is non-NULL, in use, and on a FAT12/16/32 volume. Definition at line 366 of file ra8_fs_fat_truncate.c.
References internal_fat_trunc_extend(), internal_trunc_clusters(), internal_trunc_walk(), internal_trunc_zero_span(), and k_ra8_ok.
Referenced by internal_fat_trunc().
|
static |
Free the cluster tail past new_size on a FAT file.
Below the new cluster count the chain is left alone; at and above it the survivor's tail is re-capped with an end-of-chain marker and the rest is freed. Shrinking to zero drops the whole chain and clears the file's first cluster, so a later grow starts from nothing.
| [in,out] | file | File being shrunk; first_cluster and size_bytes are updated in place. |
| [in] | new_size | New length in bytes (< size_bytes). |
| [in] | cbytes | Bytes per cluster. |
| k_ra8_ok | The file owns exactly the clusters new_size needs. |
| k_ra8_err_* | Backend or FAT error. |
file is non-NULL, in use, and on a FAT12/16/32 volume. Definition at line 230 of file ra8_fs_fat_truncate.c.
References internal_trunc_clusters(), internal_trunc_walk(), k_cluster_first_data, k_ra8_ok, priv_eoc_write(), priv_fat_get(), priv_fat_set(), priv_free_chain(), and priv_is_eoc().
Referenced by internal_fat_trunc().
|
static |
Clusters needed to hold bytes at cbytes bytes per cluster.
Ceiling division, and 0 for a zero-length file – an empty file owns no clusters on either filesystem, so the caller frees the whole allocation rather than keeping one. 64-bit in and out because an exFAT length may exceed 4 GiB (#676); the FAT callers pass lengths already capped at k_ra8_fs_fat_max_file_bytes.
| [in] | bytes | Byte length to size. |
| [in] | cbytes | Bytes per cluster (a power of two >= 512). |
| 0 | bytes is 0. |
| >0 | ceil(bytes / cbytes). |
cbytes is non-zero. bytes + cbytes does not overflow (true: a 64-bit length is bounded by the volume and the cluster size is at most 32 MiB). Definition at line 82 of file ra8_fs_fat_truncate.c.
Referenced by internal_exfat_trunc(), internal_exfat_trunc_shrink(), internal_fat_trunc_grow(), and internal_fat_trunc_shrink().
|
static |
Walk idx clusters forward along a chain from start.
The shared chain walker for the shrink paths: a FAT file's tail is only reachable by following its FAT links, and an exFAT chained file is the same. A chain that ends before idx is a corrupt file, not a short one, so it is reported rather than clamped.
| [in] | m | Mount providing FAT access. |
| [in] | start | First cluster of the chain. |
| [in] | idx | Clusters to advance (0 returns start). |
| [out] | out | Receives the cluster reached. |
| k_ra8_ok | *out is the cluster at index idx. |
| k_ra8_err_protocol_error | The chain ended before idx. |
| k_ra8_err_* | Backend or FAT error. |
m and out are non-NULL; start is a real data cluster. idx is within the file's real cluster count. idx, itself bounded by the file's length.Definition at line 116 of file ra8_fs_fat_truncate.c.
References k_ra8_err_protocol_error, k_ra8_ok, priv_fat_get(), and priv_is_eoc().
Referenced by internal_exfat_shrink_chain_tail(), internal_fat_trunc_grow(), and internal_fat_trunc_shrink().
|
static |
Write real zeros over the byte range [lo, hi) inside one cluster.
Sector by sector, read-modify-write: every sector the range touches is read, the covered bytes are cleared, and it is written back. That preserves neighbouring bytes on the two edge sectors – the file data below lo in the first, whatever sits above hi in the last – which is exactly what a FAT grow needs when the old length ends mid-sector. Zeroing a whole fresh cluster is the same call with lo == 0 and hi == cluster bytes.
| [in] | m | Mount providing the backend. |
| [in] | cluster | Cluster to zero within. |
| [in] | lo | First byte to clear (offset within the cluster). |
| [in] | hi | One past the last byte to clear. |
| k_ra8_ok | The range reads as zero (or lo >= hi, nothing to do). |
| k_ra8_err_* | Backend read or write failure. |
m is non-NULL; hi is within one cluster. cluster is an allocated data cluster. cluster read as zero. Definition at line 166 of file ra8_fs_fat_truncate.c.
References k_ra8_ok, priv_bps(), priv_cluster_to_lba(), priv_read_sector(), priv_sec_io(), and priv_write_sector().
Referenced by internal_fat_trunc_extend(), and internal_fat_trunc_grow().
|
static |
Truncate the file behind file – the guarded body of ra8_fs_truncate.
Validates the handle, dispatches on the mount's filesystem, and finally pulls the offset down if a shrink left it past the new end (the offset is otherwise left where the caller had it, as ftruncate() promises).
| [in,out] | file | Open file handle in a writing mode. |
| [in] | new_size | Desired length in bytes. |
| k_ra8_ok | Length set. |
| k_ra8_err_null_ptr | file is NULL. |
| k_ra8_err_invalid_state | Not open, or opened read-only. |
| k_ra8_err_no_mem | A grow ran out of free clusters. |
| k_ra8_err_* | Backend, FAT, or bitmap failure. |
file came from ra8_fs_open in write or append mode. Definition at line 742 of file ra8_fs_fat_truncate.c.
References internal_fat_trunc(), internal_truncate_locked(), k_ra8_err_invalid_size, k_ra8_err_null_ptr, k_ra8_fs_fat_max_file_bytes, k_ra8_fs_mode_read, k_ra8_fs_type_exfat, and k_ra8_ok.
Referenced by internal_truncate_locked(), and ra8_fs_truncate().
|
nodiscard |
Set an open file's length to new_size, shrinking or growing it.
The ftruncate() verb in both directions (#680), for a handle open in a writing mode. It is the only way to give a file an arbitrary length: writing extends only where bytes land, and ra8_fs_seek clamps to the current size, so neither can pre-size a file or trim it to N > 0 bytes. A shrink frees the tail clusters and lowers the length; a grow extends the file and the gap [old_size, new_size) reads back as zero – FAT zero-fills the fresh clusters on disk, exFAT raises DataLength while ValidDataLength stays at the written prefix so the format serves the gap as zero (and converts a run that outgrows its contiguous space to a real FAT chain). The offset is left where it was, pulled down only by a shrink that lands below it. Lengths are 64-bit: an exFAT file truncates to any size the volume can hold, past 4 GiB included (#676). On FAT12/16/32 a new_size above k_ra8_fs_fat_max_file_bytes is refused with k_ra8_err_invalid_size – DIR_FileSize is 32-bit, so the format itself cannot express it.
| [in,out] | file | Open handle in k_ra8_fs_mode_write or _append. |
| [in] | new_size | Desired length in bytes. |
| k_ra8_ok | Length set; the entry / directory reflects it. |
| k_ra8_err_null_ptr | file is NULL. |
| k_ra8_err_invalid_state | Not open, or opened read-only. |
| k_ra8_err_invalid_size | FAT volume and new_size exceeds 4 GiB - 1. |
| k_ra8_err_no_mem | A grow ran out of free clusters. |
| k_ra8_err_* | Backend, FAT, or bitmap failure. |
file is a handle from ra8_fs_open() in write or append mode. new_size and a re-read of the gap returns zeros. Definition at line 770 of file ra8_fs_fat_truncate.c.
References internal_truncate_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_truncate().
Referenced by ra8_fs_truncate().