ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_exfat_openw.c
Go to the documentation of this file.
1
37
38#include <stddef.h>
39#include <stdint.h>
40
41#include "ra8_attributes.h"
42#include "ra8_fs.h"
43#include "ra8_fs_fat_internal.h"
44
73 const exfat_setpos_t* head,
74 uint32_t count,
75 ra8_fs_mode_t mode)
76{
77 file->mount = m;
78 file->first_cluster = 0U;
79 file->cur_cluster = 0U;
80 file->walk_cache_idx = 0U;
81 file->walk_cache_cluster = 0U;
82 file->size_bytes = 0U;
83 file->offset = 0U;
84 file->dir_entry_lba = 0U;
85 file->dir_entry_idx = 0U;
86 file->valid_bytes = 0U;
87 file->entry_set_cluster = head->cluster;
88 file->entry_set_index = head->index;
89 file->entry_set_count = count;
90 file->alloc_clusters = 0U;
91 file->tail_cluster = 0U;
92 file->mode = mode;
93 file->in_use = 1U;
94 file->no_fat_chain = 1U;
95 file->dirty = 0U;
96}
97
135{
136 const ra8_fs_mount_t* m = file->mount;
137 const uint32_t cbytes = priv_cluster_bytes(m);
138 if ((file->first_cluster < (uint32_t)k_cluster_first_data) || (file->size_bytes == 0U)) {
139 file->first_cluster = 0U;
140 file->alloc_clusters = 0U;
141 file->tail_cluster = 0U;
142 file->no_fat_chain = 1U;
143 return k_ra8_ok;
144 }
145 if (file->no_fat_chain != 0U) {
146 file->alloc_clusters = (uint32_t)((file->size_bytes + cbytes - 1U) / cbytes);
147 file->tail_cluster = file->first_cluster + file->alloc_clusters - 1U;
148 return k_ra8_ok;
149 }
150 uint32_t clus = file->first_cluster;
151 uint32_t owned = 1U;
152 for (uint32_t guard = 0U; guard < m->count_of_clusters; guard++) {
153 uint32_t next = 0U;
154 const ra8_err_t e = priv_fat_get(m, clus, &next);
155 if (e != k_ra8_ok) {
156 return e;
157 }
158 if (priv_is_eoc(m, next) != 0U) {
159 break;
160 }
161 if (next < (uint32_t)k_cluster_first_data) {
163 }
164 clus = next;
165 owned++;
166 }
167 file->alloc_clusters = owned;
168 file->tail_cluster = clus;
169 return k_ra8_ok;
170}
171
196static ra8_err_t internal_exfat_truncate(ra8_fs_file_t* file, const uint8_t* strm)
197{
198 const ra8_err_t e = priv_exfat_free_clusters(file->mount, strm);
199 if (e != k_ra8_ok) {
200 return e;
201 }
202 file->first_cluster = 0U;
203 file->cur_cluster = 0U;
204 file->walk_cache_idx = 0U;
205 file->walk_cache_cluster = 0U;
206 file->size_bytes = 0U;
207 file->valid_bytes = 0U;
208 file->offset = 0U;
209 file->alloc_clusters = 0U;
210 file->tail_cluster = 0U;
211 file->no_fat_chain = 1U;
212 return priv_exfat_flush_set(file);
213}
214
254{
255 if (count < (uint32_t)k_exfat_set_min_entries) {
257 }
258 if (count > (uint32_t)k_exfat_set_writable) {
260 }
261 return k_ra8_ok;
262}
263
301 ra8_fs_mode_t mode,
302 const exfat_setpos_t* head,
303 uint32_t count,
304 const uint8_t* file_e,
305 const uint8_t* strm,
306 ra8_fs_file_t** out_file)
307{
308 if ((file_e[k_exfat_off_file_attr] & (uint8_t)k_exfat_attr_directory) != 0U) {
310 }
311 /* Honor the read-only attribute (#681): both writing modes mutate the file, so
312 * a host-marked read-only file is refused before a slot is claimed or a cluster
313 * freed. A read open never reaches here (priv_exfat_open dispatches it away). */
314 if ((file_e[k_exfat_off_file_attr] & (uint8_t)k_exfat_attr_read_only) != 0U) {
316 }
318 if (e != k_ra8_ok) {
319 return e;
320 }
322 if (f == nullptr) {
323 return k_ra8_err_no_mem;
324 }
325 internal_exfat_seed_handle(f, handle, head, count, mode);
329 f->no_fat_chain =
330 ((strm[k_exfat_strm_off_flags] & (uint8_t)k_exfat_secflag_no_fat) != 0U) ? 1U : 0U;
331 /* exFAT spec sec 7.4.5 makes ValidDataLength a PREFIX of DataLength, and the
332 * handle's invariant says so too. Another implementation can still leave the
333 * pair inverted, and taking it at face value would have the flush write the
334 * inversion back -- so it is clamped on the way in, where it costs one
335 * comparison, rather than believed. */
336 if (f->valid_bytes > f->size_bytes) {
337 f->valid_bytes = f->size_bytes;
338 }
339 if (mode == k_ra8_fs_mode_write) {
340 e = internal_exfat_truncate(f, strm);
341 } else {
345 f->offset = f->size_bytes;
346 }
347 if (e != k_ra8_ok) {
348 f->in_use = 0U;
349 f->mount = nullptr;
350 return e;
351 }
352 *out_file = f;
353 return k_ra8_ok;
354}
355
388 const exfat_dir_t* dir,
389 const uint16_t* name,
390 uint32_t nlen,
391 ra8_fs_mode_t mode,
392 ra8_fs_file_t** out_file)
393{
395 if (f == nullptr) {
396 return k_ra8_err_no_mem;
397 }
398 exfat_setpos_t head = {};
399 uint32_t count = 0U;
400 const ra8_err_t e = priv_exfat_link(handle, dir, name, nlen, &head, &count);
401 if (e != k_ra8_ok) {
402 f->in_use = 0U;
403 f->mount = nullptr;
404 return e;
405 }
406 internal_exfat_seed_handle(f, handle, &head, count, mode);
407 *out_file = f;
408 return k_ra8_ok;
409}
410
411/* `priv_exfat_open_write()`: see header for the documented contract. */
413 const char* path,
414 ra8_fs_mode_t mode,
415 ra8_fs_file_t** out_file)
416{
417 /* Resolve the directory the name lives in, rather than treating the whole
418 * path as one root-level name (#605). Leading slashes fall out of the walk,
419 * which is what used to make "/name" resolve (#93); "/logs/name" now lands in
420 * "/logs" instead of creating a file literally called "logs/name" that no
421 * matcher could ever find again. */
422 exfat_dir_t parent = {};
423 const char* leaf = nullptr;
424 const ra8_err_t pe = priv_exfat_resolve_parent(handle, path, &parent, &leaf);
425 if (pe != k_ra8_ok) {
426 return pe;
427 }
428 /* The name becomes code units once, here, and every on-disk length below
429 * counts those rather than the caller's bytes. The cap is a UNIT cap, so a
430 * UTF-8 argument three times as long is still perfectly legal (#606). */
431 uint16_t name[k_exfat_name_cap] = {};
432 uint32_t nlen = 0U;
433 const ra8_err_t ne = priv_exfat_name_to_units(handle, leaf, name, &nlen);
434 if (ne == k_ra8_err_no_mem) {
435 return k_ra8_err_invalid_arg; /* over the name cap: an argument, not a full disk */
436 }
437 if (ne != k_ra8_ok) {
438 return ne;
439 }
440 if (nlen == 0U) {
442 }
444 uint32_t count = 0U;
445 uint8_t file_e[k_exfat_entry_bytes] = {};
446 uint8_t strm[k_exfat_entry_bytes] = {};
447 const ra8_err_t e = priv_exfat_find_set(handle,
448 &parent,
449 leaf,
450 pos,
451 (uint32_t)k_exfat_set_max_entries,
452 &count,
453 file_e,
454 strm);
455 if (e == k_ra8_ok) {
456 return internal_exfat_open_found(handle, mode, &pos[0], count, file_e, strm, out_file);
457 }
458 if (e != k_ra8_err_not_found) {
459 return e;
460 }
461 return internal_exfat_open_created(handle, &parent, name, nlen, mode, out_file);
462}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_access_denied
Operation refused because the target is protected against it.
Definition ra8_err.h:276
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
uint32_t priv_rd32(const uint8_t *p)
Decode a little-endian uint32_t from a byte buffer.
Definition ra8_fs_fat.c:48
ra8_err_t priv_fat_get(const ra8_fs_mount_t *m, uint32_t cluster, uint32_t *out_value)
Fetch the FAT entry for cluster, returning the next-cluster value.
Definition ra8_fs_fat.c:187
uint8_t priv_is_eoc(const ra8_fs_mount_t *m, uint32_t value)
Test whether value is an end-of-chain marker for this FAT type.
Definition ra8_fs_fat.c:511
uint64_t priv_rd64(const uint8_t *p)
Decode a little-endian uint64_t from a byte buffer.
Definition ra8_fs_fat.c:55
uint32_t priv_cluster_bytes(const ra8_fs_mount_t *m)
One mounted volume's cluster size in bytes.
Definition ra8_fs_fat.c:90
ra8_err_t priv_exfat_resolve_parent(const ra8_fs_mount_t *m, const char *path, exfat_dir_t *out_parent, const char **out_leaf)
Resolve every component of path but the last.
ra8_err_t priv_exfat_free_clusters(const ra8_fs_mount_t *m, const uint8_t *strm)
Implementation of priv_exfat_free_clusters() – run or chain, bitmap only.
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)
Implementation of priv_exfat_find_set() – one aligned walk of a directory.
static void internal_exfat_seed_handle(ra8_fs_file_t *file, ra8_fs_mount_t *m, const exfat_setpos_t *head, uint32_t count, ra8_fs_mode_t mode)
Zero every field of a freshly claimed handle and bind it to its set.
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.
static ra8_err_t internal_exfat_truncate(ra8_fs_file_t *file, const uint8_t *strm)
Release a file's clusters and rewrite its entry set empty, in place.
static ra8_err_t internal_exfat_writable_set(uint32_t count)
Reject an entry set this adapter cannot correctly rewrite.
static ra8_err_t internal_exfat_survey_alloc(ra8_fs_file_t *file)
Count a file's clusters and find its tail.
static ra8_err_t internal_exfat_open_found(ra8_fs_mount_t *handle, ra8_fs_mode_t mode, const exfat_setpos_t *head, uint32_t count, const uint8_t *file_e, const uint8_t *strm, ra8_fs_file_t **out_file)
Open an existing name for writing: truncate it, or park at its end.
static ra8_err_t internal_exfat_open_created(ra8_fs_mount_t *handle, const exfat_dir_t *dir, const uint16_t *name, uint32_t nlen, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
Create a name that does not exist and open the empty file it names.
ra8_err_t priv_exfat_name_to_units(const ra8_fs_mount_t *m, const char *path, uint16_t *out, uint32_t *out_units)
Convert a caller's exFAT name to code units, refusing what will not fold.
ra8_err_t priv_exfat_flush_set(ra8_fs_file_t *file)
Rewrite a file's entry set from the handle, checksum last.
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.
Cross-TU shared declarations for the FAT/exFAT ra8_fs adapter.
ra8_fs_file_t * priv_alloc_file_slot(void)
Allocate a free entry from the file table; returns NULL if full.
@ k_exfat_strm_off_dlen
Stream-ext DataLength (low 32 used).
@ k_exfat_strm_off_clus
Stream-ext FirstCluster.
@ k_exfat_strm_off_flags
Stream-ext GeneralSecondaryFlags.
@ k_exfat_secflag_no_fat
GeneralSecondaryFlags: NoFatChain.
@ k_exfat_entry_bytes
Directory entry size.
@ k_exfat_off_strm_valid
Stream entry: ValidDataLength (8 B).
@ k_exfat_off_file_attr
File entry: FileAttributes (2 bytes).
@ k_exfat_attr_read_only
FileAttributes: read-only.
@ k_exfat_attr_directory
FileAttributes: directory.
@ k_exfat_name_cap
Longest name we store, in UTF-16 units.
@ k_exfat_set_min_entries
The smallest legal set: File+Stream+Name.
@ k_exfat_set_max_entries
1 File + 1 Stream + 17 Name entries.
@ k_exfat_set_writable
1 File + 1 Stream + 5 Name (64 chars).
@ k_cluster_first_data
Cluster numbers start at 2.
ra8_fs_mode_t
File-open modes accepted by ra8_fs_open().
@ k_ra8_fs_mode_write
Truncate (or create) for writing.
Identifies the exFAT directory a lookup, scan or link operates in.
Directory position (cluster + entry index) of one 32-byte entry.
uint32_t index
Entry index within that cluster (0-based).
uint32_t cluster
Directory cluster holding the entry.
Open-file state.
uint64_t size_bytes
File size (DIR_FileSize / DataLength).
uint64_t valid_bytes
exFAT ValidDataLength (bytes written).
uint64_t offset
Current read/write offset.
uint32_t first_cluster
Head of the file's cluster chain.
uint8_t in_use
0 = slot free, 1 = open.
uint32_t walk_cache_cluster
Cluster at walk_cache_idx; < 2 = no cache.
uint8_t no_fat_chain
exFAT contiguous file (no FAT walk).
uint32_t cur_cluster
Cluster the offset currently points into.
ra8_fs_mount_t * mount
Owning mount point.
Cached parse of one mounted FAT volume.
uint32_t count_of_clusters
Per MS spec: data_sectors / SPC.