diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index f215be80f..5c46883ee 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -79,23 +79,21 @@ bool copyFile(const char *from, const char *to) bool renameFile(const char *pathFrom, const char *pathTo) { #ifdef FSCom - -#ifdef ARCH_ESP32 - // take SPI Lock - spiLock->lock(); - // rename was fixed for ESP32 IDF LittleFS in April - bool result = FSCom.rename(pathFrom, pathTo); - spiLock->unlock(); - return result; -#else - // copyFile does its own locking. - if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) { - return true; - } else { - return false; - } + bool result = false; + { + concurrency::LockGuard g(spiLock); +#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL) + result = FSCom.rename(pathFrom, pathTo); #endif - + } + if (!result) { + if (copyFile(pathFrom, pathTo)) { + concurrency::LockGuard g(spiLock); + FSCom.remove(pathFrom); + result = true; + } + } + return result; #endif } diff --git a/src/SafeFile.cpp b/src/SafeFile.cpp index 45b96ad07..284a3080e 100644 --- a/src/SafeFile.cpp +++ b/src/SafeFile.cpp @@ -8,8 +8,10 @@ static File openFile(const char *filename, bool fullAtomic) concurrency::LockGuard g(spiLock); LOG_DEBUG("Opening %s, fullAtomic=%d", filename, fullAtomic); #ifdef ARCH_NRF52 - FSCom.remove(filename); - return FSCom.open(filename, FILE_O_WRITE); + if (!fullAtomic) { + FSCom.remove(filename); + return FSCom.open(filename, FILE_O_WRITE); + } #endif if (!fullAtomic) { FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists) @@ -75,10 +77,9 @@ bool SafeFile::close() { // Scope for lock concurrency::LockGuard g(spiLock); - // brief window of risk here ;-) - if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) { - LOG_ERROR("Can't remove old pref file"); - return false; + if (fullAtomic && FSCom.exists(filename.c_str())) { + // Old config will be replaced by renameFile + // Do not remove here to avoid data loss if power fails before rename } } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 0a79f94a8..4e8730039 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1049,6 +1049,29 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t } else { LOG_ERROR("Could not open / read %s", filename); } + + if (state != LoadFileResult::LOAD_SUCCESS) { + // Try loading from temporary file in case rename was interrupted + String tmp = filename; + tmp += ".tmp"; + if (FSCom.exists(tmp.c_str())) { + LOG_WARN("Attempting recovery from %s", tmp.c_str()); + auto f2 = FSCom.open(tmp.c_str(), FILE_O_READ); + if (f2) { + pb_istream_t stream = {&readcb, &f2, protoSize}; + memset(dest_struct, 0, objSize); + if (pb_decode(&stream, fields, dest_struct)) { + LOG_INFO("Recovered preferences from %s", tmp.c_str()); + state = LoadFileResult::LOAD_SUCCESS; + f2.close(); + renameFile(tmp.c_str(), filename); + } else { + LOG_ERROR("Recovery decode failed for %s", tmp.c_str()); + f2.close(); + } + } + } + } #else LOG_ERROR("ERROR: Filesystem not implemented"); state = LoadFileResult::NO_FILESYSTEM;