ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
wal_fs.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file pc_wal_fs.h
6 * @brief Bind the WAL store's ::WalDev block-device seam to a real fs::FS file (PC_ENABLE_WAL, ESP32 only).
7 *
8 * The store in pc_wal_store.h does all I/O through three function pointers so its logic stays pure and
9 * host-testable; this header is the thin, device-only adapter that points those pointers at a preallocated
10 * fs::File on any Arduino filesystem - an SD card or LittleFS. Random access uses `File::seek`, and the
11 * durability barrier is `File::flush`.
12 *
13 * Usage:
14 * @code
15 * pc_wal_fs_prealloc(SD, "/wal.bin", 256 * 1024); // once: fixed-size, zero-filled backing file
16 * fs::File f = SD.open("/wal.bin", "r+"); // random read+write, no truncation
17 * WalDev dev = pc_wal_fs_dev(&f, 256 * 1024);
18 * WalStore s;
19 * pc_wal_store_mount(&s, &dev) || pc_wal_store_format(&s, &dev); // recover, or initialize a fresh file
20 * @endcode
21 *
22 * The backing file is preallocated to a fixed size so every store offset lands inside it and `seek`+`write`
23 * overwrites in place (no sparse-file / past-EOF behavior differences between FAT and LittleFS). The fs::File
24 * must outlive any ::WalDev bound to it.
25 */
26
27#ifndef PROTOCORE_WAL_FS_H
28#define PROTOCORE_WAL_FS_H
29
30#include "protocore_config.h"
31
32#if PC_ENABLE_WAL && defined(ARDUINO)
33
35#include <FS.h>
36#include <string.h>
37
38namespace pc_wal_fs_detail
39{
40inline size_t fs_read(void *ctx, uint64_t off, uint8_t *buf, size_t len)
41{
42 fs::File *f = (fs::File *)ctx;
43 if (!f->seek((uint32_t)off))
44 {
45 return 0;
46 }
47 return f->read(buf, len);
48}
49inline size_t fs_write(void *ctx, uint64_t off, const uint8_t *buf, size_t len)
50{
51 fs::File *f = (fs::File *)ctx;
52 if (!f->seek((uint32_t)off))
53 {
54 return 0;
55 }
56 return f->write(buf, len);
57}
58inline bool fs_sync(void *ctx)
59{
60 ((fs::File *)ctx)->flush();
61 return true;
62}
63} // namespace pc_wal_fs_detail
64
65/**
66 * @brief Ensure @p path on @p fsys exists and is at least @p size bytes (created zero-filled if missing/short).
67 * @return true on success. Call once before opening the file for the store.
68 */
69inline bool pc_wal_fs_prealloc(fs::FS &fsys, const char *path, uint64_t size)
70{
71 if (fsys.exists(path))
72 {
73 fs::File ex = fsys.open(path, "r");
74 uint64_t have = ex ? (uint64_t)ex.size() : 0;
75 if (ex)
76 {
77 ex.close();
78 }
79 if (have >= size)
80 {
81 return true;
82 }
83 }
84 fs::File f = fsys.open(path, "w"); // create / truncate
85 if (!f)
86 {
87 return false;
88 }
89 uint8_t z[256];
90 memset(z, 0, sizeof(z));
91 uint64_t left = size;
92 bool ok = true;
93 while (left)
94 {
95 size_t n = left < sizeof(z) ? (size_t)left : sizeof(z);
96 if (f.write(z, n) != n)
97 {
98 ok = false;
99 break;
100 }
101 left -= n;
102 }
103 f.flush();
104 f.close();
105 return ok;
106}
107
108/**
109 * @brief Build a ::WalDev that reads/writes @p f (an open "r+" file) as a @p size-byte block device.
110 * @note @p f must stay open for as long as the returned ::WalDev (and any ::WalStore mounted on it) is used.
111 */
112inline WalDev pc_wal_fs_dev(fs::File *f, uint64_t size)
113{
114 WalDev d;
115 d.read = pc_wal_fs_detail::fs_read;
116 d.write = pc_wal_fs_detail::fs_write;
117 d.sync = pc_wal_fs_detail::fs_sync;
118 d.ctx = f;
119 d.size = size;
120 return d;
121}
122
123#endif // PC_ENABLE_WAL && ARDUINO
124#endif // PROTOCORE_WAL_FS_H
User-facing configuration for ProtoCore.