From dcec0bf7ffd0970702646645d0de7429985fa271 Mon Sep 17 00:00:00 2001 From: Gerhard Schwanzer Date: Sun, 5 Jul 2026 17:39:38 +0200 Subject: [PATCH] Skip actively locked autosave files Check the QLockFile in staleFiles() before returning a no-KF5 recovery candidate, matching the KAutoSaveFile contract that actively owned autosave files are not stale. Extend the no-KF5 Catch test so a child process keeps the autosave lock alive while allStaleFiles() runs, then verify recovery after the child is killed. Assisted-by: pi coding agent / Mika (OpenAI GPT-5.5) --- sources/ui/nokde/kautosavefile.cpp | 23 ++++++++++++++++-- tests/catch/src/kautosavefile_test.cpp | 33 +++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/sources/ui/nokde/kautosavefile.cpp b/sources/ui/nokde/kautosavefile.cpp index 1e896e38f..d9a38450f 100644 --- a/sources/ui/nokde/kautosavefile.cpp +++ b/sources/ui/nokde/kautosavefile.cpp @@ -48,6 +48,11 @@ QString metadataFileName(const QString &autosave_file_name) return autosave_file_name + QStringLiteral(".path"); } +QString lockFileName(const QString &autosave_file_name) +{ + return autosave_file_name + QStringLiteral(".lock"); +} + QUrl normalizeManagedFile(const QUrl &url) { if (url.isEmpty()) { @@ -165,6 +170,18 @@ QStringList findAllStaleFiles(const QString &application_name) return files; } +bool autosaveFileIsRecoverable(const QString &autosave_file_name) +{ + QLockFile lock(lockFileName(autosave_file_name)); + lock.setStaleLockTime(60 * 1000); + if (!lock.tryLock()) { + return false; + } + + lock.unlock(); + return true; +} + } // namespace KAutoSaveFile::KAutoSaveFile(const QUrl &filename, QObject *parent) : @@ -239,8 +256,7 @@ bool KAutoSaveFile::open(OpenMode openmode) } if (!m_lock) { - m_lock = std::make_unique( - fileName() + QStringLiteral(".lock")); + m_lock = std::make_unique(lockFileName(fileName())); m_lock->setStaleLockTime(60 * 1000); } @@ -268,6 +284,9 @@ QList KAutoSaveFile::staleFiles( && managed_file != managed_file_filter) { continue; } + if (!autosaveFileIsRecoverable(file)) { + continue; + } auto *stale_file = new KAutoSaveFile(managed_file); stale_file->setFileName(file); diff --git a/tests/catch/src/kautosavefile_test.cpp b/tests/catch/src/kautosavefile_test.cpp index c2690bb9c..64258c117 100644 --- a/tests/catch/src/kautosavefile_test.cpp +++ b/tests/catch/src/kautosavefile_test.cpp @@ -11,6 +11,7 @@ #include #ifdef Q_OS_UNIX +#include #include #include #include @@ -34,11 +35,16 @@ TEST_CASE("Qt-only KAutoSaveFile recovers stale files", "[nokde][autosave]") REQUIRE(managed_file.write("\n") > 0); managed_file.close(); + int ready_pipe[2] = {-1, -1}; + REQUIRE(pipe(ready_pipe) == 0); + const QByteArray payload("\n"); const auto child_pid = fork(); REQUIRE(child_pid >= 0); if (child_pid == 0) { + close(ready_pipe[0]); + KAutoSaveFile backup(QUrl::fromLocalFile(managed_path)); if (!backup.open(QIODevice::WriteOnly | QIODevice::Truncate @@ -52,13 +58,34 @@ TEST_CASE("Qt-only KAutoSaveFile recovers stale files", "[nokde][autosave]") _exit(4); } - _exit(0); + const char ready = '1'; + if (write(ready_pipe[1], &ready, 1) != 1) { + _exit(5); + } + close(ready_pipe[1]); + + for (;;) { + pause(); + } } + close(ready_pipe[1]); + char ready = 0; + REQUIRE(read(ready_pipe[0], &ready, 1) == 1); + close(ready_pipe[0]); + REQUIRE(ready == '1'); + + auto active_files = KAutoSaveFile::allStaleFiles(); + CHECK(active_files.isEmpty()); + for (auto *file : active_files) { + delete file; + } + + REQUIRE(kill(child_pid, SIGKILL) == 0); int status = 0; REQUIRE(waitpid(child_pid, &status, 0) == child_pid); - REQUIRE(WIFEXITED(status)); - REQUIRE(WEXITSTATUS(status) == 0); + REQUIRE(WIFSIGNALED(status)); + REQUIRE(WTERMSIG(status) == SIGKILL); auto stale_files = KAutoSaveFile::allStaleFiles(); REQUIRE(stale_files.size() == 1);