From d1524fd45bc804ac67dc8a55dbdb47d2c327b03b Mon Sep 17 00:00:00 2001 From: Kaj Schittecat Date: Sun, 18 Oct 2026 14:49:39 +0200 Subject: [PATCH] touch: backup names probe by opening the file (Tanmatsu FFat) #688 picks the first free meshcore-backup-nodate-N with fs->exists(). On the Tanmatsu FFat's exists() reports files that are there as missing (and stat lies on the P4), so without a card every export would pick nodate-1 and overwrite the previous one. Probe with open() instead. Co-Authored-By: Claude Opus 5.5 --- src/ui-touch/UITask.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index b8012fb..d99e63e 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -49332,11 +49332,21 @@ static void backupMakeFilename(char* out, size_t cap, bool probe_storage) { } fs::FS* sd_fs = probe_storage ? backupSdFs() : nullptr; fs::FS* int_fs = backupInternalFs(); + // open() rather than exists(): FFat's exists() says "missing" for files that are + // there on the Tanmatsu (and stat lies on the P4), so without a card every export + // would pick nodate-1 and overwrite the last one. + auto present = [](fs::FS* fs, const char* path) { + if (!fs) return false; + File f = fs->open(path, FILE_READ); + const bool ok = (bool)f; + if (f) f.close(); + return ok; + }; for (unsigned n = 1; ; n++) { snprintf(out, cap, "meshcore-backup-nodate-%u.json", n); if (!probe_storage || n >= 999) return; char path[64]; snprintf(path, sizeof path, "/%s", out); - if (!(sd_fs && sd_fs->exists(path)) && !int_fs->exists(path)) return; + if (!present(sd_fs, path) && !present(int_fs, path)) return; } }