refactor: Removed redundant FsFile close() calls (#1434)
## Summary **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.) `DESTRUCTOR_CLOSES_FILE=1` is set in platformio.ini, which makes SdFat's FsBaseFile destructor call close() automatically when a file goes out of scope. Three categories of file close calls remain untouched: 1. Close before Storage.remove() on the same path: ScreenshotUtil.cpp closes the file before deleting it on write error. The remove might fail if the file is still open. 2. Close before reopening the same variable: Epub.cpp writes a temp NCX/nav file, closes it, then reopens it for reading. The RecentBooksStore.cpp close before saveToFile() is the same pattern, it rewrites the same file. 3. Close on member variables: BookMetadataCache.cpp (bookFile, spineFile, tocFile), Section.cpp (file), XtcParser.cpp (m_file), ZipFile.cpp (file). These persist beyond any single function scope, so the destructor timing doesn't match the intended close point. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**PARTIALLY**_
This commit is contained in:
@@ -126,7 +126,6 @@ bool CrossPointSettings::loadFromBinaryFile() {
|
||||
serialization::readPod(inputFile, version);
|
||||
if (version != SETTINGS_FILE_VERSION) {
|
||||
LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version);
|
||||
inputFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -220,7 +219,6 @@ bool CrossPointSettings::loadFromBinaryFile() {
|
||||
applyLegacyFrontButtonLayout(*this);
|
||||
}
|
||||
|
||||
inputFile.close();
|
||||
LOG_DBG("CPS", "Settings loaded from binary file");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ bool CrossPointState::loadFromBinaryFile() {
|
||||
serialization::readPod(inputFile, version);
|
||||
if (version > STATE_FILE_VERSION) {
|
||||
LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version);
|
||||
inputFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -76,6 +75,5 @@ bool CrossPointState::loadFromBinaryFile() {
|
||||
lastSleepFromReader = false;
|
||||
}
|
||||
|
||||
inputFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -163,6 +163,7 @@ bool RecentBooksStore::loadFromBinaryFile() {
|
||||
}
|
||||
|
||||
if (omitted > 0) {
|
||||
// Explicitly close() file before saveToFile() rewrites the same file
|
||||
inputFile.close();
|
||||
saveToFile();
|
||||
LOG_DBG("RBS", "Omitted %u recent book(s) with missing title", omitted);
|
||||
@@ -170,11 +171,9 @@ bool RecentBooksStore::loadFromBinaryFile() {
|
||||
}
|
||||
} else {
|
||||
LOG_ERR("RBS", "Deserialization failed: Unknown version %u", version);
|
||||
inputFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
inputFile.close();
|
||||
LOG_DBG("RBS", "Recent books loaded from binary file (%d entries)", static_cast<int>(recentBooks.size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ bool WifiCredentialStore::loadFromBinaryFile() {
|
||||
serialization::readPod(file, version);
|
||||
if (version > WIFI_FILE_VERSION) {
|
||||
LOG_DBG("WCS", "Unknown file version: %u", version);
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,7 +97,6 @@ bool WifiCredentialStore::loadFromBinaryFile() {
|
||||
credentials.push_back(cred);
|
||||
}
|
||||
|
||||
file.close();
|
||||
// LOG_DBG("WCS", "Loaded %zu WiFi credentials from binary file", credentials.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
if (dir && dir.isDirectory()) {
|
||||
sleepDir = "/.sleep";
|
||||
} else {
|
||||
if (dir) dir.close();
|
||||
dir = Storage.open("/sleep");
|
||||
if (dir && dir.isDirectory()) {
|
||||
sleepDir = "/sleep";
|
||||
@@ -56,29 +55,24 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
// collect all valid BMP files
|
||||
for (auto file = dir.openNextFile(); file; file = dir.openNextFile()) {
|
||||
if (file.isDirectory()) {
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
file.getName(name, sizeof(name));
|
||||
auto filename = std::string(name);
|
||||
if (filename[0] == '.') {
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!FsHelpers::hasBmpExtension(filename)) {
|
||||
LOG_DBG("SLP", "Skipping non-.bmp file name: %s", name);
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
|
||||
LOG_DBG("SLP", "Skipping invalid BMP file: %s", name);
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
files.emplace_back(filename);
|
||||
file.close();
|
||||
}
|
||||
const auto numFiles = files.size();
|
||||
if (numFiles > 0) {
|
||||
@@ -98,16 +92,11 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
Bitmap bitmap(file, true);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
file.close();
|
||||
dir.close();
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dir) dir.close();
|
||||
|
||||
// Look for sleep.bmp on the root of the sd card to determine if we should
|
||||
// render a custom sleep screen instead of the default.
|
||||
FsFile file;
|
||||
@@ -116,10 +105,8 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
LOG_DBG("SLP", "Loading: /sleep.bmp");
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
renderDefaultSleepScreen();
|
||||
@@ -286,10 +273,8 @@ void SleepActivity::renderCoverSleepScreen() const {
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
LOG_DBG("SLP", "Rendering sleep cover: %s", coverBmpPath.c_str());
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
return (this->*renderNoCoverSleepScreen)();
|
||||
|
||||
@@ -75,7 +75,6 @@ void FileBrowserActivity::loadFiles() {
|
||||
|
||||
auto root = Storage.open(basepath.c_str());
|
||||
if (!root || !root.isDirectory()) {
|
||||
if (root) root.close();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +84,6 @@ void FileBrowserActivity::loadFiles() {
|
||||
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
|
||||
file.getName(name, sizeof(name));
|
||||
if ((!SETTINGS.showHiddenFiles && name[0] == '.') || strcmp(name, "System Volume Information") == 0) {
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -99,9 +97,7 @@ void FileBrowserActivity::loadFiles() {
|
||||
files.emplace_back(filename);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
root.close();
|
||||
sortFileList(files);
|
||||
}
|
||||
|
||||
@@ -115,7 +111,6 @@ void FileBrowserActivity::onEnter() {
|
||||
basepath = "/";
|
||||
loadFiles();
|
||||
} else if (!root.isDirectory()) {
|
||||
root.close();
|
||||
lockLongPressBack = mappedInput.isPressed(MappedInputManager::Button::Back);
|
||||
|
||||
const std::string oldPath = basepath;
|
||||
@@ -126,7 +121,6 @@ void FileBrowserActivity::onEnter() {
|
||||
const std::string fileName = oldPath.substr(pos + 1);
|
||||
selectorIndex = findEntry(fileName);
|
||||
} else {
|
||||
root.close();
|
||||
loadFiles();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ void EpubReaderActivity::onEnter() {
|
||||
if (dataSize == 6) {
|
||||
cachedChapterTotalPageCount = data[4] + (data[5] << 8);
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
// We may want a better condition to detect if we are opening for the first time.
|
||||
// This will trigger if the book is re-opened at Chapter 0.
|
||||
@@ -696,7 +695,6 @@ void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageC
|
||||
data[4] = pageCount & 0xFF;
|
||||
data[5] = (pageCount >> 8) & 0xFF;
|
||||
f.write(data, 6);
|
||||
f.close();
|
||||
LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d", spineIndex, currentPage);
|
||||
} else {
|
||||
LOG_ERR("ERS", "Could not save progress!");
|
||||
|
||||
@@ -405,7 +405,6 @@ void TxtReaderActivity::saveProgress() const {
|
||||
data[2] = 0;
|
||||
data[3] = 0;
|
||||
f.write(data, 4);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +422,6 @@ void TxtReaderActivity::loadProgress() {
|
||||
}
|
||||
LOG_DBG("TRS", "Loaded progress: page %d/%d", currentPage, totalPages);
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +450,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, magic);
|
||||
if (magic != CACHE_MAGIC) {
|
||||
LOG_DBG("TRS", "Cache magic mismatch, rebuilding");
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -460,7 +457,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, version);
|
||||
if (version != CACHE_VERSION) {
|
||||
LOG_DBG("TRS", "Cache version mismatch (%d != %d), rebuilding", version, CACHE_VERSION);
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -468,7 +464,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, fileSize);
|
||||
if (fileSize != txt->getFileSize()) {
|
||||
LOG_DBG("TRS", "Cache file size mismatch, rebuilding");
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -476,7 +471,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, cachedWidth);
|
||||
if (cachedWidth != viewportWidth) {
|
||||
LOG_DBG("TRS", "Cache viewport width mismatch, rebuilding");
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -484,7 +478,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, cachedLines);
|
||||
if (cachedLines != linesPerPage) {
|
||||
LOG_DBG("TRS", "Cache lines per page mismatch, rebuilding");
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -492,7 +485,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, fontId);
|
||||
if (fontId != cachedFontId) {
|
||||
LOG_DBG("TRS", "Cache font ID mismatch (%d != %d), rebuilding", fontId, cachedFontId);
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -500,7 +492,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, margin);
|
||||
if (margin != cachedScreenMargin) {
|
||||
LOG_DBG("TRS", "Cache screen margin mismatch, rebuilding");
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -508,7 +499,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
serialization::readPod(f, alignment);
|
||||
if (alignment != cachedParagraphAlignment) {
|
||||
LOG_DBG("TRS", "Cache paragraph alignment mismatch, rebuilding");
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -525,7 +515,6 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
pageOffsets.push_back(offset);
|
||||
}
|
||||
|
||||
f.close();
|
||||
totalPages = pageOffsets.size();
|
||||
LOG_DBG("TRS", "Loaded page index cache: %d pages", totalPages);
|
||||
return true;
|
||||
@@ -555,6 +544,5 @@ void TxtReaderActivity::savePageIndexCache() const {
|
||||
serialization::writePod(f, static_cast<uint32_t>(offset));
|
||||
}
|
||||
|
||||
f.close();
|
||||
LOG_DBG("TRS", "Saved page index cache: %d pages", totalPages);
|
||||
}
|
||||
|
||||
@@ -422,7 +422,6 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
bookWidth = rect.width / 2; // Fallback
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +475,6 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ void CrossPointWebServer::begin() {
|
||||
}
|
||||
|
||||
void CrossPointWebServer::abortWsUpload(const char* tag) {
|
||||
// Explicit close() required: file-scope global persists beyond function scope
|
||||
wsUploadFile.close();
|
||||
String filePath = wsUploadPath;
|
||||
if (!filePath.endsWith("/")) filePath += "/";
|
||||
@@ -1342,6 +1343,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
|
||||
|
||||
// Zero-byte upload: complete immediately without waiting for BIN frames
|
||||
if (wsUploadSize == 0) {
|
||||
// Explicit close() required: file-scope global persists beyond function scope
|
||||
wsUploadFile.close();
|
||||
wsLastCompleteName = wsUploadFileName;
|
||||
wsLastCompleteSize = 0;
|
||||
@@ -1397,6 +1399,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
|
||||
|
||||
// Check if upload complete
|
||||
if (wsUploadReceived >= wsUploadSize) {
|
||||
// Explicit close() required: file-scope global persists beyond function scope
|
||||
wsUploadFile.close();
|
||||
wsUploadInProgress = false;
|
||||
wsUploadClientNum = 255;
|
||||
|
||||
@@ -70,6 +70,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f
|
||||
}
|
||||
|
||||
if (write_error) {
|
||||
// Explicitly close() file before calling Storage.remove()
|
||||
file.close();
|
||||
Storage.remove(filename);
|
||||
return false;
|
||||
@@ -80,6 +81,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f
|
||||
constexpr size_t kMaxRowSize = 68;
|
||||
if (rowSizePadded > kMaxRowSize) {
|
||||
LOG_ERR("SCR", "Row size %u exceeds buffer capacity", rowSizePadded);
|
||||
// Explicitly close() file before calling Storage.remove()
|
||||
file.close();
|
||||
Storage.remove(filename);
|
||||
return false;
|
||||
@@ -106,6 +108,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f
|
||||
memset(rowBuffer, 0, rowSizePadded); // Clear the buffer for the next row
|
||||
}
|
||||
|
||||
// Explicitly close() file before calling Storage.remove()
|
||||
file.close();
|
||||
|
||||
if (write_error) {
|
||||
|
||||
Reference in New Issue
Block a user