fix: clear cache when deleting folders in FileBrowserActivity (#1892)
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
#include "FileBrowserActivity.h"
|
#include "FileBrowserActivity.h"
|
||||||
|
|
||||||
#include <Epub.h>
|
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <HalStorage.h>
|
#include <HalStorage.h>
|
||||||
#include <I18n.h>
|
#include <I18n.h>
|
||||||
|
#include <Memory.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -13,9 +13,11 @@
|
|||||||
#include "activities/util/ConfirmationActivity.h"
|
#include "activities/util/ConfirmationActivity.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
#include "util/BookCacheUtils.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr unsigned long GO_HOME_MS = 1000;
|
constexpr unsigned long GO_HOME_MS = 1000;
|
||||||
|
constexpr size_t NAME_BUFFER_SIZE = 500;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void FileBrowserActivity::loadFiles() {
|
void FileBrowserActivity::loadFiles() {
|
||||||
@@ -28,17 +30,23 @@ void FileBrowserActivity::loadFiles() {
|
|||||||
|
|
||||||
root.rewindDirectory();
|
root.rewindDirectory();
|
||||||
|
|
||||||
char name[500];
|
if (!fileNameBuffer) {
|
||||||
|
LOG_ERR("FileBrowser", "fileNameBuffer not allocated");
|
||||||
|
root.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
|
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
|
||||||
file.getName(name, sizeof(name));
|
file.getName(fileNameBuffer.get(), NAME_BUFFER_SIZE);
|
||||||
if ((!SETTINGS.showHiddenFiles && name[0] == '.') || strcmp(name, "System Volume Information") == 0) {
|
if ((!SETTINGS.showHiddenFiles && fileNameBuffer[0] == '.') ||
|
||||||
|
strcmp(fileNameBuffer.get(), "System Volume Information") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
files.emplace_back(std::string(name) + "/");
|
files.emplace_back(std::string(fileNameBuffer.get()) + "/");
|
||||||
} else {
|
} else {
|
||||||
std::string_view filename{name};
|
std::string_view filename{fileNameBuffer.get()};
|
||||||
if (mode == Mode::PickFirmware) {
|
if (mode == Mode::PickFirmware) {
|
||||||
// Firmware picker: only show .bin files.
|
// Firmware picker: only show .bin files.
|
||||||
if (FsHelpers::checkFileExtension(filename, ".bin")) {
|
if (FsHelpers::checkFileExtension(filename, ".bin")) {
|
||||||
@@ -58,6 +66,12 @@ void FileBrowserActivity::loadFiles() {
|
|||||||
void FileBrowserActivity::onEnter() {
|
void FileBrowserActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
|
|
||||||
|
fileNameBuffer = makeUniqueNoThrow<char[]>(NAME_BUFFER_SIZE);
|
||||||
|
if (!fileNameBuffer) {
|
||||||
|
LOG_ERR("FileBrowser", "malloc failed for name buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
|
|
||||||
// If Confirm was held while this activity opened (typical when launched from a menu), ignore
|
// If Confirm was held while this activity opened (typical when launched from a menu), ignore
|
||||||
@@ -88,14 +102,88 @@ void FileBrowserActivity::onEnter() {
|
|||||||
void FileBrowserActivity::onExit() {
|
void FileBrowserActivity::onExit() {
|
||||||
Activity::onExit();
|
Activity::onExit();
|
||||||
files.clear();
|
files.clear();
|
||||||
|
fileNameBuffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileBrowserActivity::clearFileMetadata(const std::string& fullPath) {
|
// To avoid traversing directories twice (once for cache clearing, once for deletion),
|
||||||
// Only clear cache for .epub files
|
// we do both in one pass here, instead of using Storage.removeDir
|
||||||
if (FsHelpers::hasEpubExtension(fullPath)) {
|
bool FileBrowserActivity::removeDirFile(const std::string& fullPath) {
|
||||||
Epub(fullPath, "/.crosspoint").clearCache();
|
auto file = Storage.open(fullPath.c_str());
|
||||||
LOG_DBG("FileBrowser", "Cleared metadata cache for: %s", fullPath.c_str());
|
if (!file) {
|
||||||
|
LOG_ERR("FileBrowser", "Failed to open for metadata clearing: %s", fullPath.c_str());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!file.isDirectory()) {
|
||||||
|
file.close();
|
||||||
|
clearBookCache(fullPath);
|
||||||
|
return Storage.remove(fullPath.c_str());
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (!fileNameBuffer) {
|
||||||
|
LOG_ERR("FileBrowser", "fileNameBuffer not allocated");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack of (dirPath, postOrder): postOrder=true means rmdir this path after children are processed.
|
||||||
|
std::vector<std::pair<std::string, bool>> stack;
|
||||||
|
stack.reserve(16);
|
||||||
|
stack.push_back({fullPath, false});
|
||||||
|
|
||||||
|
while (!stack.empty()) {
|
||||||
|
auto [currentPath, postOrder] = std::move(stack.back());
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
if (postOrder) {
|
||||||
|
if (!Storage.rmdir(currentPath.c_str())) {
|
||||||
|
LOG_ERR("FileBrowser", "Failed to rmdir: %s", currentPath.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir = Storage.open(currentPath.c_str());
|
||||||
|
if (!dir) {
|
||||||
|
LOG_ERR("FileBrowser", "Failed to open dir: %s", currentPath.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!dir.isDirectory()) {
|
||||||
|
LOG_ERR("FileBrowser", "Not a directory: %s", currentPath.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push this dir for post-order rmdir (after all children are processed).
|
||||||
|
stack.push_back({currentPath, true});
|
||||||
|
|
||||||
|
dir.rewindDirectory();
|
||||||
|
for (auto entry = dir.openNextFile(); entry; entry = dir.openNextFile()) {
|
||||||
|
entry.getName(fileNameBuffer.get(), NAME_BUFFER_SIZE);
|
||||||
|
if (strcmp(fileNameBuffer.get(), ".") == 0 || strcmp(fileNameBuffer.get(), "..") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string entryPath = currentPath;
|
||||||
|
if (entryPath.back() != '/') {
|
||||||
|
entryPath += "/";
|
||||||
|
}
|
||||||
|
entryPath += fileNameBuffer.get();
|
||||||
|
|
||||||
|
const bool isDir = entry.isDirectory();
|
||||||
|
entry.close();
|
||||||
|
|
||||||
|
if (isDir) {
|
||||||
|
stack.push_back({std::move(entryPath), false});
|
||||||
|
} else {
|
||||||
|
clearBookCache(entryPath);
|
||||||
|
if (!Storage.remove(entryPath.c_str())) {
|
||||||
|
LOG_ERR("FileBrowser", "Failed to remove file: %s", entryPath.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileBrowserActivity::loop() {
|
void FileBrowserActivity::loop() {
|
||||||
@@ -145,14 +233,10 @@ void FileBrowserActivity::loop() {
|
|||||||
if (cleanBasePath.back() != '/') cleanBasePath += "/";
|
if (cleanBasePath.back() != '/') cleanBasePath += "/";
|
||||||
const std::string fullPath = cleanBasePath + entry;
|
const std::string fullPath = cleanBasePath + entry;
|
||||||
|
|
||||||
auto handler = [this, fullPath, isDirectory](const ActivityResult& res) {
|
auto handler = [this, fullPath](const ActivityResult& res) {
|
||||||
if (!res.isCancelled) {
|
if (!res.isCancelled) {
|
||||||
LOG_DBG("FileBrowser", "Attempting to delete: %s", fullPath.c_str());
|
LOG_DBG("FileBrowser", "Attempting to delete: %s", fullPath.c_str());
|
||||||
if (!isDirectory) {
|
if (removeDirFile(fullPath)) {
|
||||||
clearFileMetadata(fullPath);
|
|
||||||
}
|
|
||||||
const bool deleted = isDirectory ? Storage.removeDir(fullPath.c_str()) : Storage.remove(fullPath.c_str());
|
|
||||||
if (deleted) {
|
|
||||||
LOG_DBG("FileBrowser", "Deleted successfully");
|
LOG_DBG("FileBrowser", "Deleted successfully");
|
||||||
loadFiles();
|
loadFiles();
|
||||||
if (files.empty()) {
|
if (files.empty()) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ class FileBrowserActivity final : public Activity {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Deletion
|
// Deletion
|
||||||
void clearFileMetadata(const std::string& fullPath);
|
bool removeDirFile(const std::string& fullPath);
|
||||||
|
|
||||||
ButtonNavigator buttonNavigator;
|
ButtonNavigator buttonNavigator;
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ class FileBrowserActivity final : public Activity {
|
|||||||
// Files state
|
// Files state
|
||||||
std::string basepath = "/";
|
std::string basepath = "/";
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
|
std::unique_ptr<char[]> fileNameBuffer;
|
||||||
|
|
||||||
// Data loading
|
// Data loading
|
||||||
void loadFiles();
|
void loadFiles();
|
||||||
|
|||||||
Reference in New Issue
Block a user