From a394f3e59aa5c2d5c625c6120be1751b02ded846 Mon Sep 17 00:00:00 2001 From: PointerL <124577547+PointerL@users.noreply.github.com> Date: Thu, 22 Oct 2026 23:49:30 +0800 Subject: [PATCH 1/2] test: cover file error path diagnostics Exercise each file utility failure path so missing path context is caught before implementation changes. Signed-off-by: PointerL --- .../ll-tests/src/linglong/utils/file_test.cpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/libs/linglong/tests/ll-tests/src/linglong/utils/file_test.cpp b/libs/linglong/tests/ll-tests/src/linglong/utils/file_test.cpp index 09ab6ff4a..6b3035612 100644 --- a/libs/linglong/tests/ll-tests/src/linglong/utils/file_test.cpp +++ b/libs/linglong/tests/ll-tests/src/linglong/utils/file_test.cpp @@ -406,6 +406,38 @@ TEST_F(FileTest, EnsureDirectory) EXPECT_TRUE(fs::is_directory(multiple_dir)); } +TEST_F(FileTest, EnsureDirectoryErrorIncludesPathWhenRemovingFileFails) +{ + if (::geteuid() == 0) { + GTEST_SKIP() << "root can remove files regardless of the parent permission bits"; + } + + const auto parent = dest_dir / "read-only-parent"; + fs::create_directory(parent); + const auto permissions = fs::status(parent).permissions(); + const auto file = parent / "existing-file"; + std::ofstream(file) << "content"; + fs::permissions(parent, fs::perms::owner_read | fs::perms::owner_exec); + + auto result = linglong::utils::ensureDirectory(file); + + fs::permissions(parent, permissions); + ASSERT_FALSE(result); + EXPECT_NE(result.error().message().find(file.string()), std::string::npos); +} + +TEST_F(FileTest, EnsureDirectoryErrorIncludesPathWhenCreatingDirectoryFails) +{ + const auto parent = dest_dir / "regular-file"; + std::ofstream(parent) << "content"; + const auto directory = parent / "nested-directory"; + + auto result = linglong::utils::ensureDirectory(directory); + + ASSERT_FALSE(result); + EXPECT_NE(result.error().message().find(directory.string()), std::string::npos); +} + TEST_F(FileTest, EnsureDirectoryWithPermissionsIgnoresUmask) { constexpr auto permissions = fs::perms::owner_all | fs::perms::group_read @@ -532,6 +564,20 @@ TEST_F(FileTest, RelinkFile) } } +TEST_F(FileTest, RelinkFileErrorIncludesTemporaryPath) +{ + const auto parent = dest_dir / "regular-file"; + std::ofstream(parent) << "content"; + const auto link = parent / "link"; + const auto target = dest_dir / "target"; + const auto temporary = fs::path{ link.string() + ".linyaps.tmp" }; + + auto result = linglong::utils::relinkFileTo(link, target); + + ASSERT_FALSE(result); + EXPECT_NE(result.error().message().find(temporary.string()), std::string::npos); +} + TEST_F(FileTest, WriteFile) { // Test writing to a new file @@ -575,6 +621,19 @@ TEST_F(FileTest, WriteFile) EXPECT_FALSE(result.has_value()); // Should fail because parent directory doesn't exist } +TEST_F(FileTest, WriteFileErrorIncludesPath) +{ + const fs::path fullDevice{ "/dev/full" }; + if (!fs::exists(fullDevice)) { + GTEST_SKIP() << "/dev/full is required to exercise a deferred write failure"; + } + + auto result = linglong::utils::writeFile(fullDevice, "content"); + + ASSERT_FALSE(result); + EXPECT_NE(result.error().message().find(fullDevice.string()), std::string::npos); +} + TEST_F(FileTest, ReadFile) { // Test reading an existing file From 48e81ead4b3277a25fc64ac2c329f46894953833 Mon Sep 17 00:00:00 2001 From: PointerL <124577547+PointerL@users.noreply.github.com> Date: Fri, 23 Oct 2026 00:02:58 +0800 Subject: [PATCH 2/2] fix(utils): include paths in file errors Name the affected file, directory, or temporary symlink path in failure diagnostics while preserving existing error codes and control flow. Signed-off-by: PointerL --- libs/utils/src/linglong/utils/file.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/utils/src/linglong/utils/file.cpp b/libs/utils/src/linglong/utils/file.cpp index 8175b197a..d50c1b704 100644 --- a/libs/utils/src/linglong/utils/file.cpp +++ b/libs/utils/src/linglong/utils/file.cpp @@ -81,8 +81,9 @@ linglong::utils::error::Result writeFile(const std::filesystem::path &file out << content; out.close(); if (!out) { - return LINGLONG_ERR( - fmt::format("failed to write file {}", common::error::errorString(errno))); + return LINGLONG_ERR(fmt::format("failed to write file {}: {}", + filepath, + common::error::errorString(errno))); } return LINGLONG_OK; } @@ -356,12 +357,12 @@ linglong::utils::error::Result ensureDirectory(const std::filesystem::path std::filesystem::remove(dir, ec); if (ec) { - return LINGLONG_ERR("failed to remove directory", ec); + return LINGLONG_ERR(fmt::format("failed to remove directory {}", dir), ec); } } if (!std::filesystem::create_directories(dir, ec) && ec) { - return LINGLONG_ERR("failed to create directory", ec); + return LINGLONG_ERR(fmt::format("failed to create directory {}", dir), ec); } return LINGLONG_OK; @@ -466,7 +467,8 @@ linglong::utils::error::Result relinkFileTo(const std::filesystem::path &l std::filesystem::create_symlink(target, tmpPath, ec); if (ec) { - return LINGLONG_ERR("failed to create symlink", ec); + return LINGLONG_ERR( + fmt::format("failed to create symlink {} -> {}", tmpPath, target), ec); } std::filesystem::rename(tmpPath, link, ec);