DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
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 wal_fs.h
6 * @brief Bind the WAL store's ::WalDev block-device seam to a real fs::FS file (DETWS_ENABLE_WAL, ESP32 only).
7 *
8 * The store in 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 * 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 = wal_fs_dev(&f, 256 * 1024);
18 * WalStore s;
19 * wal_store_mount(&s, &dev) || 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 DETERMINISTICESPASYNCWEBSERVER_WAL_FS_H
28#define DETERMINISTICESPASYNCWEBSERVER_WAL_FS_H
29
30#include "ServerConfig.h"
31
32#if DETWS_ENABLE_WAL && defined(ARDUINO)
33
35#include <FS.h>
36#include <string.h>
37
38namespace detws_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 return 0;
45 return f->read(buf, len);
46}
47inline size_t fs_write(void *ctx, uint64_t off, const uint8_t *buf, size_t len)
48{
49 fs::File *f = (fs::File *)ctx;
50 if (!f->seek((uint32_t)off))
51 return 0;
52 return f->write(buf, len);
53}
54inline bool fs_sync(void *ctx)
55{
56 ((fs::File *)ctx)->flush();
57 return true;
58}
59} // namespace detws_wal_fs_detail
60
61/**
62 * @brief Ensure @p path on @p fsys exists and is at least @p size bytes (created zero-filled if missing/short).
63 * @return true on success. Call once before opening the file for the store.
64 */
65inline bool wal_fs_prealloc(fs::FS &fsys, const char *path, uint64_t size)
66{
67 if (fsys.exists(path))
68 {
69 fs::File ex = fsys.open(path, "r");
70 uint64_t have = ex ? (uint64_t)ex.size() : 0;
71 if (ex)
72 ex.close();
73 if (have >= size)
74 return true;
75 }
76 fs::File f = fsys.open(path, "w"); // create / truncate
77 if (!f)
78 return false;
79 uint8_t z[256];
80 memset(z, 0, sizeof(z));
81 uint64_t left = size;
82 bool ok = true;
83 while (left)
84 {
85 size_t n = left < sizeof(z) ? (size_t)left : sizeof(z);
86 if (f.write(z, n) != n)
87 {
88 ok = false;
89 break;
90 }
91 left -= n;
92 }
93 f.flush();
94 f.close();
95 return ok;
96}
97
98/**
99 * @brief Build a ::WalDev that reads/writes @p f (an open "r+" file) as a @p size-byte block device.
100 * @note @p f must stay open for as long as the returned ::WalDev (and any ::WalStore mounted on it) is used.
101 */
102inline WalDev wal_fs_dev(fs::File *f, uint64_t size)
103{
104 WalDev d;
105 d.read = detws_wal_fs_detail::fs_read;
106 d.write = detws_wal_fs_detail::fs_write;
107 d.sync = detws_wal_fs_detail::fs_sync;
108 d.ctx = f;
109 d.size = size;
110 return d;
111}
112
113#endif // DETWS_ENABLE_WAL && ARDUINO
114#endif // DETERMINISTICESPASYNCWEBSERVER_WAL_FS_H
User-facing configuration for DeterministicESPAsyncWebServer.
Durable write-ahead store: A/B superblock + checkpoint over a block-device seam (DETWS_ENABLE_WAL).