7#include "esp_vfs_fat.h"
8#include "esp_partition.h"
9#include "wear_levelling.h"
22static const char*
TAG =
"PLG_STO";
43 for (
int d = 0; d < FF_VOLUMES; ++d) {
44 snprintf(path,
sizeof(path),
"%d:/system", d);
45 if (f_stat(path, &fno) == FR_OK)
return d;
56 if (drive < 0)
return;
58 snprintf(drv,
sizeof(drv),
"%d:", drive);
60 if (f_getlabel(drv, cur,
nullptr) == FR_OK && std::strcmp(cur,
VOLUME_LABEL) == 0) {
64 snprintf(lbl,
sizeof(lbl),
"%d:%s", drive,
VOLUME_LABEL);
65 if (f_setlabel(lbl) == FR_OK) {
76 const esp_vfs_fat_mount_config_t cfg = {
77 .format_if_mount_failed =
true,
79 .allocation_unit_size = CONFIG_WL_SECTOR_SIZE,
80 .disk_status_check_enable =
false,
84 esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(
87 LOG_E(
TAG,
"mount failed: 0x%x", err);
95#if FEATURE_PLUGIN_SYSTEM_LOCK
114static bool ends_with(
const char* s,
size_t s_len,
const char* suffix,
size_t suf_len)
116 return s_len > suf_len && std::strcmp(s + s_len - suf_len, suffix) == 0;
121 std::vector<std::string> ids;
129 while (
struct dirent* ent = readdir(dir)) {
130 const char*
name = ent->d_name;
131 size_t len = std::strlen(
name);
134 id.assign(
name, len - 4);
136 id.assign(
name, len - 5);
140 if (std::find(ids.begin(), ids.end(),
id) != ids.end())
continue;
144 if (stat(meta.c_str(), &st) == 0 && (st.st_mode & S_IFREG)) {
145 ids.push_back(std::move(
id));
155#if FEATURE_PLUGIN_AOT
158 if (stat(aot.c_str(), &st) == 0 && (st.st_mode & S_IFREG)) {
167 return std::string(
SYSTEM_DIR) +
"/" +
id +
".wasm";
172 return std::string(
SYSTEM_DIR) +
"/" +
id +
".aot";
177 return std::string(
SYSTEM_DIR) +
"/" +
id +
".meta";
182 return std::string(
SYSTEM_DIR) +
"/" +
id +
".lang";
187 return std::string(
SYSTEM_DIR) +
"/" +
id +
".disabled";
194 return stat(path.c_str(), &st) == 0 && (st.st_mode & S_IFREG);
202 return std::remove(path.c_str()) == 0 || errno == ENOENT;
206 if (!fp)
return false;
207 static constexpr char kMarker[] =
"disabled\n";
208 return std::fwrite(kMarker, 1,
sizeof(kMarker) - 1, fp.get()) ==
sizeof(kMarker) - 1;
214 return esp_vfs_fat_info(
MOUNT_POINT, &total_bytes, &free_bytes) == ESP_OK;
220 return static_cast<uint16_t
>(wl_sector_size(
s_wl_handle));
232 const uint16_t bs =
static_cast<uint16_t
>(wl_sector_size(
s_wl_handle));
234 const uint64_t addr =
static_cast<uint64_t
>(lba) * bs + offset;
235 return wl_read(
s_wl_handle,
static_cast<size_t>(addr), buf, len) == ESP_OK;
241 const uint16_t bs =
static_cast<uint16_t
>(wl_sector_size(
s_wl_handle));
245 const uint64_t addr =
static_cast<uint64_t
>(lba) * bs;
246 if (wl_erase_range(
s_wl_handle,
static_cast<size_t>(addr), len) != ESP_OK)
return false;
247 return wl_write(
s_wl_handle,
static_cast<size_t>(addr), buf, len) == ESP_OK;
255 LOG_I(
TAG,
"MSC host %s", active ?
"attached" :
"detached");
281 static constexpr BYTE kAttr = AM_RDO | AM_HID | AM_SYS;
282 static constexpr BYTE kMask = AM_RDO | AM_HID | AM_SYS;
286 LOG_W(
TAG,
"protectSystemDir: system folder not found for chmod");
292 snprintf(dirPath,
sizeof(dirPath),
"%d:/system", drive);
293 f_chmod(dirPath, AM_HID | AM_SYS, AM_RDO | AM_HID | AM_SYS);
300 while (
struct dirent* ent = readdir(dir)) {
301 if (ent->d_name[0] ==
'.')
continue;
302 snprintf(filePath,
sizeof(filePath),
"%d:/system/%s", drive, ent->d_name);
303 f_chmod(filePath, kAttr, kMask);
306 LOG_I(
TAG,
"protectSystemDir: marked system folder on drive %d", drive);
Mounts the FAT-FS partition that holds plugin .wasm + .meta files.
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]
Shared RAII wrappers for firmware resources.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
#define LOG_I(tag, fmt,...)
#define LOG_E(tag, fmt,...)
static bool blockWrite(uint32_t lba, uint32_t offset, const void *buf, uint32_t len)
Erases and writes raw bytes to the wear-levelling logical space.
static bool mount()
Mount the plugins partition. Auto-formats if empty.
static const char * basePath()
Returns the VFS path prefix, e.g. "/vfat".
static uint16_t blockSize()
Logical sector size of the vfat volume in bytes (MSC block size).
static std::string langPath(const std::string &id)
Returns the full VFS path of <id>.lang (translation overlay).
static void unmount()
Unmount the plugins partition (rarely used; mostly tests).
static std::string aotPath(const std::string &id)
Returns the full VFS path of <id>.aot.
static bool stats(uint64_t &free_bytes, uint64_t &total_bytes)
Returns the free and total bytes on the plugins partition.
static bool blockRead(uint32_t lba, uint32_t offset, void *buf, uint32_t len)
Reads raw bytes from the wear-levelling logical space.
static bool isDisabled(const std::string &id)
True when the plugin has a persistent disabled marker.
static bool setDisabled(const std::string &id, bool disabled)
Create or remove the persistent disabled marker for a plugin.
static std::string disabledPath(const std::string &id)
Returns the full VFS path of <id>.disabled.
static void setHostActive(bool active)
Marks whether a USB host currently holds the volume over MSC.
static void protectSystemDir()
Applies advisory read-only + hidden + system FAT attributes to the system folder so standard host fil...
static std::vector< std::string > listPluginIds()
Discover all installed plugin ids. A plugin is recognised by the presence of both <id>....
static uint64_t blockTotalBytes()
Total accessible size of the vfat volume in bytes.
static bool hostActive()
Reports whether a USB host currently holds the volume over MSC.
static std::string wasmPath(const std::string &id)
Returns the full VFS path of <id>.wasm.
static void remountIfPending()
Performs a deferred remount scheduled by setHostActive(false).
static std::string metaPath(const std::string &id)
Returns the full VFS path of <id>.meta.
static std::string binaryPath(const std::string &id)
Returns the path that should be loaded for <id>: <id>.aot if it exists on disk, otherwise <id>....
FilePtr openFile(const char *path, const char *mode) noexcept
Open a FILE* and wrap it in a FilePtr.
static const char * SYSTEM_DIR
static void ensure_volume_label()
static bool s_remount_pending
static const char * MOUNT_POINT
static bool ends_with(const char *s, size_t s_len, const char *suffix, size_t suf_len)
static wl_handle_t s_wl_handle
static const char * PARTITION_LABEL
static const char * VOLUME_LABEL
static bool s_host_active
static bool usb_msc_should_remount(bool prev, bool cur)
Whether a host-active transition should trigger a badge remount.
static bool usb_msc_range_ok(uint64_t total_bytes, uint16_t block_size, uint32_t lba, uint32_t offset, uint32_t len, bool is_write)
Validates an MSC block access against the volume geometry.