From 3d135ceca12b6be0c5f47114e2f2b5701fbd0c3d Mon Sep 17 00:00:00 2001 From: drkhsh Date: Sun, 26 Apr 2026 02:15:25 +0200 Subject: [PATCH] Strip trailing slashes from dir-path constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PATH_CONTACTS / PATH_MESSAGES / SD_PATH_CONTACTS / SD_PATH_MESSAGES all ended in '/'. The FATFS layer used by the SD library and LittleFS won't reliably enumerate when given a path ending in slash — opendir returns a valid handle but readdir yields nothing. Direct file reads (SD.open with FILE_READ for a known path) still work, which is why settings/identity persisted but contacts and conversations vanished on reboot. Drop the trailing slash from the constants and add explicit "/" at all concat sites: saveContact, removeContact, conversationDir, sdConversationDir, and the migrateTruncatedDirs path builders. --- src/config/Config.h | 11 +++++++---- src/reticulum/AnnounceManager.cpp | 8 ++++---- src/storage/MessageStore.cpp | 8 ++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/config/Config.h b/src/config/Config.h index e676394..9e1a324 100644 --- a/src/config/Config.h +++ b/src/config/Config.h @@ -30,14 +30,17 @@ #define PATH_IDENTITY_BAK "/identity/identity.key.bak" #define PATH_PATHS "/transport/paths.msgpack" #define PATH_USER_CONFIG "/config/user.json" -#define PATH_CONTACTS "/contacts/" -#define PATH_MESSAGES "/messages/" +// Directory paths intentionally have NO trailing slash — some FATFS/VFS +// readdir paths fail to enumerate when given a path ending in '/'. +// Concat sites must add their own '/' before the basename. +#define PATH_CONTACTS "/contacts" +#define PATH_MESSAGES "/messages" // --- SD Card Paths --- #define SD_PATH_CONFIG_DIR "/ratdeck/config" #define SD_PATH_USER_CONFIG "/ratdeck/config/user.json" -#define SD_PATH_MESSAGES "/ratdeck/messages/" -#define SD_PATH_CONTACTS "/ratdeck/contacts/" +#define SD_PATH_MESSAGES "/ratdeck/messages" +#define SD_PATH_CONTACTS "/ratdeck/contacts" #define SD_PATH_IDENTITY "/ratdeck/identity/identity.key" // --- TCP Client --- diff --git a/src/reticulum/AnnounceManager.cpp b/src/reticulum/AnnounceManager.cpp index ae422bf..65d5663 100644 --- a/src/reticulum/AnnounceManager.cpp +++ b/src/reticulum/AnnounceManager.cpp @@ -349,15 +349,15 @@ void AnnounceManager::saveContact(const DiscoveredNode& node) { serializeJson(doc, json); String filename = hexHash.substr(0, 16).c_str(); filename += ".json"; - if (_sd && _sd->isReady()) { _sd->writeString((String(SD_PATH_CONTACTS) + filename).c_str(), json); } - if (_flash) { _flash->writeString((String(PATH_CONTACTS) + filename).c_str(), json); } + if (_sd && _sd->isReady()) { _sd->writeString((String(SD_PATH_CONTACTS) + "/" + filename).c_str(), json); } + if (_flash) { _flash->writeString((String(PATH_CONTACTS) + "/" + filename).c_str(), json); } } void AnnounceManager::removeContact(const std::string& hexHash) { String filename = hexHash.substr(0, 16).c_str(); filename += ".json"; - if (_sd && _sd->isReady()) { _sd->remove((String(SD_PATH_CONTACTS) + filename).c_str()); } - if (_flash) { _flash->remove((String(PATH_CONTACTS) + filename).c_str()); } + if (_sd && _sd->isReady()) { _sd->remove((String(SD_PATH_CONTACTS) + "/" + filename).c_str()); } + if (_flash) { _flash->remove((String(PATH_CONTACTS) + "/" + filename).c_str()); } } bool AnnounceManager::deleteContact(int nodeIdx) { diff --git a/src/storage/MessageStore.cpp b/src/storage/MessageStore.cpp index f945964..ac96a29 100644 --- a/src/storage/MessageStore.cpp +++ b/src/storage/MessageStore.cpp @@ -146,7 +146,7 @@ void MessageStore::migrateTruncatedDirs() { // Old dirs are exactly 16 hex chars; new ones are 32 if (dirName.length() == 16) { // Read first JSON file inside to get the full hash - String oldDir = String(basePath) + dirName.c_str(); + String oldDir = String(basePath) + "/" + dirName.c_str(); File inner = openFn(oldDir.c_str()); if (inner && inner.isDirectory()) { File jsonFile = inner.openNextFile(); @@ -176,7 +176,7 @@ void MessageStore::migrateTruncatedDirs() { inner.close(); if (!fullHash.empty() && fullHash.substr(0, 16) == dirName) { - String newDir = String(basePath) + fullHash.c_str(); + String newDir = String(basePath) + "/" + fullHash.c_str(); renames.push_back({oldDir, newDir}); } } @@ -738,11 +738,11 @@ int MessageStore::totalUnreadCount() const { } String MessageStore::conversationDir(const std::string& peerHex) const { - return String(PATH_MESSAGES) + peerHex.c_str(); + return String(PATH_MESSAGES) + "/" + peerHex.c_str(); } String MessageStore::sdConversationDir(const std::string& peerHex) const { - return String(SD_PATH_MESSAGES) + peerHex.c_str(); + return String(SD_PATH_MESSAGES) + "/" + peerHex.c_str(); } void MessageStore::enforceFlashLimit(const std::string& peerHex) {