ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_label.c
Go to the documentation of this file.
1
35
36#include <stddef.h>
37#include <stdint.h>
38
39#include "ra8_attributes.h"
40#include "ra8_fs.h"
41#include "ra8_fs_fat_internal.h"
42#include "ra8_fs_meta.h"
43
67{
68 return (m->type == k_ra8_fs_type_fat32) ? (uint32_t)k_fmt_off_f32_label
69 : (uint32_t)k_fmt_off_f16_label;
70}
71
96static void internal_label_from_raw(const uint8_t* raw11, char* out, uint32_t out_len)
97{
98 static const uint8_t k_no_name[k_fmt_label_len] =
99 {'N', 'O', ' ', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' '};
100 if (priv_byte_equal(raw11, k_no_name, (uint32_t)k_fmt_label_len) != 0U) {
101 out[0] = '\0';
102 return;
103 }
104 /* BS_VolLab and the ATTR_VOLUME_ID name are space-padded by the FAT spec (and
105 * by ::priv_fmt_label_field), so trailing spaces are the only padding to trim. */
106 uint32_t n = (uint32_t)k_fmt_label_len;
107 while (n > 0U) {
108 if (raw11[n - 1U] != (uint8_t)' ') {
109 break;
110 }
111 n--;
112 }
113 uint32_t w = 0U;
114 for (uint32_t i = 0U; i < n; i++) {
115 if ((w + 1U) >= out_len) {
116 break;
117 }
118 out[w] = (char)raw11[i];
119 w++;
120 }
121 out[w] = '\0';
122}
123
153 uint64_t* out_lba,
154 uint32_t* out_off,
155 uint8_t* out_entry)
156{
157 const dir_loc_t loc = {.is_root = 1U, .cluster = 0U};
158 dir_walk_t w = {};
159 priv_dir_walk_init_loc(m, &loc, &w);
160 uint8_t eod = 0U;
161 uint8_t* const buf = priv_sec_walk();
162 while (eod == 0U) {
163 ra8_err_t err = priv_read_sector(m, w.cur_lba, buf);
164 if (err != k_ra8_ok) {
165 return err;
166 }
167 for (uint32_t e = 0U; e < priv_dir_eps(m); e++) {
168 const uint32_t off = e * (uint32_t)k_ra8_fs_dir_entry_bytes;
169 const uint8_t name0 = buf[off + (uint32_t)k_dir_off_name];
170 const uint8_t attr = buf[off + (uint32_t)k_dir_off_attr];
171 if (name0 == (uint8_t)k_dir_marker_free_perm) {
172 return k_ra8_err_not_found;
173 }
174 if (name0 == (uint8_t)k_dir_marker_free_used) {
175 continue;
176 }
177 if (attr == (uint8_t)k_ra8_fs_attr_lfn) {
178 continue;
179 }
180 if ((attr & (uint8_t)k_ra8_fs_attr_volume_id) != 0U) {
181 *out_lba = w.cur_lba;
182 *out_off = off;
183 priv_byte_copy(out_entry, &buf[off], (uint32_t)k_ra8_fs_dir_entry_bytes);
184 return k_ra8_ok;
185 }
186 }
187 err = priv_dir_walk_next_sector(m, &w, &eod);
188 if (err != k_ra8_ok) {
189 return err;
190 }
191 }
192 return k_ra8_err_not_found;
193}
194
221static ra8_err_t
222internal_fat_find_free_root(const ra8_fs_mount_t* m, uint64_t* out_lba, uint32_t* out_off)
223{
224 const dir_loc_t loc = {.is_root = 1U, .cluster = 0U};
225 dir_walk_t w = {};
226 priv_dir_walk_init_loc(m, &loc, &w);
227 uint8_t eod = 0U;
228 uint8_t* const buf = priv_sec_walk();
229 while (eod == 0U) {
230 ra8_err_t err = priv_read_sector(m, w.cur_lba, buf);
231 if (err != k_ra8_ok) {
232 return err;
233 }
234 for (uint32_t e = 0U; e < priv_dir_eps(m); e++) {
235 const uint32_t off = e * (uint32_t)k_ra8_fs_dir_entry_bytes;
236 const uint8_t name0 = buf[off + (uint32_t)k_dir_off_name];
237 if ((name0 == (uint8_t)k_dir_marker_free_perm) ||
238 (name0 == (uint8_t)k_dir_marker_free_used)) {
239 *out_lba = w.cur_lba;
240 *out_off = off;
241 return k_ra8_ok;
242 }
243 }
244 err = priv_dir_walk_next_sector(m, &w, &eod);
245 if (err != k_ra8_ok) {
246 return err;
247 }
248 }
249 return k_ra8_err_no_mem;
250}
251
277static ra8_err_t internal_fat_boot_set_label(const ra8_fs_mount_t* m, const char* label)
278{
279 uint8_t* const boot = priv_sec_walk();
280 const ra8_err_t err = priv_read_sector(m, 0U, boot);
281 if (err != k_ra8_ok) {
282 return err;
283 }
285 return priv_write_sector(m, 0U, boot);
286}
287
312static ra8_err_t internal_fat_del_entry(const ra8_fs_mount_t* m, uint64_t lba, uint32_t off)
313{
314 uint8_t* const sec = priv_sec_walk();
315 const ra8_err_t err = priv_read_sector(m, lba, sec);
316 if (err != k_ra8_ok) {
317 return err;
318 }
319 sec[off + (uint32_t)k_dir_off_name] = (uint8_t)k_dir_marker_free_used;
320 return priv_write_sector(m, lba, sec);
321}
322
352 uint64_t lba,
353 uint32_t off,
354 const char* label,
355 bool fresh)
356{
357 uint8_t* const sec = priv_sec_walk();
358 const ra8_err_t err = priv_read_sector(m, lba, sec);
359 if (err != k_ra8_ok) {
360 return err;
361 }
362 uint8_t* e = &sec[off];
363 if (fresh) {
364 for (uint32_t i = 0U; i < (uint32_t)k_ra8_fs_dir_entry_bytes; i++) {
365 e[i] = 0U;
366 }
367 }
370 if (fresh) {
372 } else {
374 }
375 return priv_write_sector(m, lba, sec);
376}
377
403static ra8_err_t internal_get_label_fat(const ra8_fs_mount_t* m, char* out, uint32_t out_len)
404{
405 uint8_t raw[k_fmt_label_len] = {};
406 uint64_t lba = 0U;
407 uint32_t off = 0U;
408 uint8_t entry[k_ra8_fs_dir_entry_bytes] = {};
409 const ra8_err_t ferr = internal_fat_find_vol_id(m, &lba, &off, entry);
410 if (ferr == k_ra8_ok) {
411 priv_byte_copy(raw, &entry[k_dir_off_name], (uint32_t)k_fmt_label_len);
412 } else if (ferr == k_ra8_err_not_found) {
413 uint8_t* const boot = priv_sec_walk();
414 const ra8_err_t berr = priv_read_sector(m, 0U, boot);
415 if (berr != k_ra8_ok) {
416 return berr;
417 }
419 } else {
420 return ferr;
421 }
422 internal_label_from_raw(raw, out, out_len);
423 return k_ra8_ok;
424}
425
453static ra8_err_t internal_set_label_fat(const ra8_fs_mount_t* m, const char* label)
454{
455 const bool clearing = (label == nullptr) || (label[0] == '\0');
456 const ra8_err_t berr = internal_fat_boot_set_label(m, label);
457 if (berr != k_ra8_ok) {
458 return berr;
459 }
460 uint64_t lba = 0U;
461 uint32_t off = 0U;
462 uint8_t entry[k_ra8_fs_dir_entry_bytes] = {};
463 const ra8_err_t ferr = internal_fat_find_vol_id(m, &lba, &off, entry);
464 if ((ferr != k_ra8_ok) && (ferr != k_ra8_err_not_found)) {
465 return ferr;
466 }
467 if (clearing) {
468 return (ferr == k_ra8_ok) ? internal_fat_del_entry(m, lba, off) : k_ra8_ok;
469 }
470 if (ferr == k_ra8_ok) {
471 return internal_fat_put_vol_id(m, lba, off, label, false);
472 }
473 const ra8_err_t serr = internal_fat_find_free_root(m, &lba, &off);
474 if (serr != k_ra8_ok) {
475 return serr;
476 }
477 return internal_fat_put_vol_id(m, lba, off, label, true);
478}
479
510RA8_EXPECTS_LOCK("ra8_fs_lock")
511static ra8_err_t
512internal_get_label_locked(const ra8_fs_mount_t* handle, char* out, uint32_t out_len)
513{
514 if (handle == nullptr || out == nullptr) {
515 return k_ra8_err_null_ptr;
516 }
517 if (out_len == 0U) {
519 }
520 if (handle->in_use == 0U) {
521 return k_ra8_err_invalid_state;
522 }
523 out[0] = '\0';
524 if (handle->type == k_ra8_fs_type_exfat) {
525 return priv_exfat_get_label(handle, out, out_len);
526 }
527 return internal_get_label_fat(handle, out, out_len);
528}
529
561RA8_EXPECTS_LOCK("ra8_fs_lock")
562static ra8_err_t internal_set_label_locked(const ra8_fs_mount_t* handle, const char* label)
563{
564 if (handle == nullptr) {
565 return k_ra8_err_null_ptr;
566 }
567 if (handle->in_use == 0U) {
568 return k_ra8_err_invalid_state;
569 }
570 if ((label != nullptr) && (priv_strlen(label) > (uint32_t)k_fmt_label_len)) {
572 }
573 if (handle->type == k_ra8_fs_type_exfat) {
574 return priv_exfat_set_label(handle, label);
575 }
576 return internal_set_label_fat(handle, label);
577}
578
579/* =============================================================================
580 * Public entry points -- the lock brackets
581 * =============================================================================
582 */
583
584RA8_OWNS_RESOURCE("ra8_fs_lock")
585ra8_err_t ra8_fs_get_label(const ra8_fs_mount_t* handle, char* out, uint32_t out_len)
586{
588 const ra8_err_t err = internal_get_label_locked(handle, out, out_len);
590 return err;
591}
592
593RA8_OWNS_RESOURCE("ra8_fs_lock")
594ra8_err_t ra8_fs_set_label(const ra8_fs_mount_t* handle, const char* label)
595{
597 const ra8_err_t err = internal_set_label_locked(handle, label);
599 return err;
600}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_OWNS_RESOURCE(kind)
RAII-style resource ownership contract.
#define RA8_EXPECTS_LOCK(name)
The function expects the named thread/IRQ lock to be held on entry.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ 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_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ 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_dir_eps(const ra8_fs_mount_t *m)
Directory entries per sector on one mounted volume.
Definition ra8_fs_fat.c:96
ra8_err_t priv_read_sector(const ra8_fs_mount_t *m, uint64_t lba, uint8_t *buf)
Read a single sector into the module scratch buffer.
Definition ra8_fs_fat.c:134
uint8_t priv_byte_equal(const uint8_t *a, const uint8_t *b, uint32_t n)
Compare two byte buffers for equality (length n).
Definition ra8_fs_fat.c:118
void priv_byte_copy(uint8_t *dst, const uint8_t *src, uint32_t n)
Length-checked byte copy used in place of memcpy().
Definition ra8_fs_fat.c:110
ra8_err_t priv_write_sector(const ra8_fs_mount_t *m, uint64_t lba, const uint8_t *buf)
Write a single sector from a caller-provided buffer.
Definition ra8_fs_fat.c:140
uint8_t * priv_sec_walk(void)
The WALK-role sector buffer (directory scans and entry RMW).
uint32_t priv_strlen(const char *s)
Length of a NUL-terminated string.
void priv_fmt_label_field(uint8_t *dst, const char *label)
Pad an ASCII volume label into an 11-byte BS_VolLab / label field.
Cross-TU shared declarations for the FAT/exFAT ra8_fs adapter.
static ra8_err_t internal_fat_del_entry(const ra8_fs_mount_t *m, uint64_t lba, uint32_t off)
Mark the root directory entry at lba / off deleted.
static uint32_t internal_fat_boot_label_off(const ra8_fs_mount_t *m)
Byte offset of BS_VolLab in this volume's boot sector.
static ra8_err_t internal_get_label_fat(const ra8_fs_mount_t *m, char *out, uint32_t out_len)
Read a FAT volume's label – root ATTR_VOLUME_ID, else BS_VolLab.
static ra8_err_t internal_fat_find_free_root(const ra8_fs_mount_t *m, uint64_t *out_lba, uint32_t *out_off)
Find the first free slot in the root directory.
static ra8_err_t internal_fat_find_vol_id(const ra8_fs_mount_t *m, uint64_t *out_lba, uint32_t *out_off, uint8_t *out_entry)
Find the root directory's ATTR_VOLUME_ID entry.
static ra8_err_t internal_fat_boot_set_label(const ra8_fs_mount_t *m, const char *label)
Write the boot sector's BS_VolLab field.
static ra8_err_t internal_fat_put_vol_id(const ra8_fs_mount_t *m, uint64_t lba, uint32_t off, const char *label, bool fresh)
Write a root-directory ATTR_VOLUME_ID entry at lba / off.
static ra8_err_t internal_get_label_locked(const ra8_fs_mount_t *handle, char *out, uint32_t out_len)
Read the volume label – the guarded body of ra8_fs_get_label().
static ra8_err_t internal_set_label_fat(const ra8_fs_mount_t *m, const char *label)
Set a FAT volume's label – boot sector plus root entry, kept in step.
static ra8_err_t internal_set_label_locked(const ra8_fs_mount_t *handle, const char *label)
Set the volume label – the guarded body of ra8_fs_set_label().
static void internal_label_from_raw(const uint8_t *raw11, char *out, uint32_t out_len)
Decode an 11-byte packed FAT label into a trimmed ASCII string.
void priv_lock_release(void)
Drop the library lock taken by priv_lock_acquire.
void priv_lock_acquire(void)
Take the library lock, if the caller installed one.
void priv_dir_walk_init_loc(const ra8_fs_mount_t *m, const dir_loc_t *loc, dir_walk_t *w)
Initialise a directory walker for an arbitrary directory location.
ra8_err_t priv_dir_walk_next_sector(const ra8_fs_mount_t *m, dir_walk_t *w, uint8_t *out_eod)
Advance the walker to the next sector.
void priv_fat_entry_stamp_write(uint8_t *entry)
Advance a FAT directory entry's modification time and access date.
void priv_fat_entry_stamp_create(uint8_t *entry)
Stamp a fresh FAT directory entry's create, write, and access fields.
@ k_fmt_off_f32_label
FAT32 BS_VolLab (11 bytes).
@ k_fmt_off_f16_label
FAT12/16 BS_VolLab (11 bytes).
@ k_dir_off_attr
MS FAT spec sec 6 "DIR_Attr".
@ k_dir_off_name
MS FAT spec sec 6 "DIR_Name" (11 bytes).
@ k_fmt_label_len
Volume-label field width (bytes).
@ k_dir_marker_free_used
Slot was used, deleted.
@ k_dir_marker_free_perm
End-of-directory.
Volume-level metadata: free space, volume label, and per-entry utime.
ra8_err_t ra8_fs_get_label(const ra8_fs_mount_t *handle, char *out, uint32_t out_len)
Read the volume label of a mounted volume.
ra8_err_t ra8_fs_set_label(const ra8_fs_mount_t *handle, const char *label)
Set (or clear) the volume label of a mounted volume.
@ k_ra8_fs_type_fat32
count_of_clusters >= 65525.
@ k_ra8_fs_type_exfat
exFAT (read + streaming write + format).
@ k_ra8_fs_attr_lfn
Long-file-name marker (we skip).
@ k_ra8_fs_attr_volume_id
MS FAT spec sec 6 "ATTR_VOLUME_ID".
@ k_ra8_fs_dir_entry_bytes
MS FAT spec sec 6 "Directory Entry".
Identifies the directory a lookup/scan should operate in.
Internal cursor used by the directory iterator.
uint64_t cur_lba
Currently loaded LBA.
Cached parse of one mounted FAT volume.
ra8_fs_type_t type
FAT12 / FAT16 / FAT32.