Skip to content

Commit e2a26de

Browse files
reddevillgdengbo11
authored andcommitted
fix: retry cache removal after modify directory permissions
kenrel overlay will generated a 000 permission work directory under workdir. Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent 891dc89 commit e2a26de

4 files changed

Lines changed: 131 additions & 3 deletions

File tree

libs/linglong/src/linglong/package_manager/package_manager.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1992,7 +1992,19 @@ utils::error::Result<void> PackageManager::removeCache(const package::Reference
19921992
std::error_code ec;
19931993
std::filesystem::remove_all(appCache, ec);
19941994
if (ec) {
1995-
return LINGLONG_ERR("failed to remove cache directory", ec);
1995+
LogD("failed to remove cache directory {}, retry after fixing permissions: {}",
1996+
appCache,
1997+
ec.message());
1998+
1999+
auto ret = utils::makeDirectoryTreeRemovable(appCache);
2000+
if (!ret) {
2001+
return LINGLONG_ERR("failed to make cache directory removable", ret);
2002+
}
2003+
2004+
std::filesystem::remove_all(appCache, ec);
2005+
if (ec) {
2006+
return LINGLONG_ERR("failed to remove cache directory", ec);
2007+
}
19962008
}
19972009

19982010
return LINGLONG_OK;

libs/linglong/tests/ll-tests/src/linglong/utils/file_test.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2025-2026 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2025 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

@@ -13,6 +13,8 @@
1313
#include <memory>
1414
#include <string>
1515

16+
#include <unistd.h>
17+
1618
namespace fs = std::filesystem;
1719

1820
class FileTest : public ::testing::Test
@@ -277,6 +279,54 @@ TEST_F(FileTest, EnsureDirectory)
277279
EXPECT_TRUE(fs::is_directory(multiple_dir));
278280
}
279281

282+
TEST_F(FileTest, MakeDirectoryTreeRemovable)
283+
{
284+
const fs::perms ownerAll =
285+
fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec;
286+
287+
fs::path root = dest_dir / "removable";
288+
fs::path blockedDir = root / "blocked-dir";
289+
fs::path nestedFile = blockedDir / "nested.txt";
290+
fs::path blockedFile = root / "blocked-file.txt";
291+
fs::path writeOnlyFile = root / "write-only.txt";
292+
293+
fs::create_directories(blockedDir);
294+
std::ofstream(nestedFile) << "nested";
295+
std::ofstream(blockedFile) << "blocked";
296+
std::ofstream(writeOnlyFile) << "write";
297+
298+
fs::permissions(root, ownerAll, fs::perm_options::replace);
299+
fs::permissions(blockedDir, fs::perms::none, fs::perm_options::replace);
300+
fs::permissions(blockedFile, fs::perms::none, fs::perm_options::replace);
301+
fs::permissions(writeOnlyFile, fs::perms::owner_write, fs::perm_options::replace);
302+
303+
if (geteuid() == 0) {
304+
GTEST_SKIP() << "root can remove files regardless of the owner permission bits";
305+
}
306+
307+
auto rootPermsBefore = fs::symlink_status(root).permissions();
308+
309+
std::error_code removeBeforeEc;
310+
fs::remove_all(root, removeBeforeEc);
311+
ASSERT_TRUE(removeBeforeEc)
312+
<< "directory tree should not be removable before permissions are fixed";
313+
ASSERT_TRUE(fs::exists(root));
314+
315+
auto result = linglong::utils::makeDirectoryTreeRemovable(root);
316+
ASSERT_TRUE(result.has_value()) << result.error().message();
317+
318+
auto rootPermsAfter = fs::symlink_status(root).permissions();
319+
EXPECT_EQ(rootPermsAfter & ownerAll, rootPermsBefore & ownerAll);
320+
321+
auto blockedDirPerms = fs::symlink_status(blockedDir).permissions();
322+
EXPECT_EQ(blockedDirPerms & ownerAll, ownerAll);
323+
324+
std::error_code ec;
325+
fs::remove_all(root, ec);
326+
EXPECT_FALSE(ec) << ec.message();
327+
EXPECT_FALSE(fs::exists(root));
328+
}
329+
280330
TEST_F(FileTest, RelinkFile)
281331
{
282332
fs::path target = dest_dir / "target_file";

libs/utils/src/linglong/utils/file.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,30 @@
1818

1919
namespace linglong::utils {
2020

21+
namespace {
22+
23+
linglong::utils::error::Result<void>
24+
ensureOwnerPermissionsIfNeeded(const std::filesystem::path &path,
25+
std::filesystem::perms currentPerms,
26+
std::filesystem::perms requiredPerms) noexcept
27+
{
28+
LINGLONG_TRACE("ensure owner permissions if needed");
29+
30+
if ((currentPerms & requiredPerms) == requiredPerms) {
31+
return LINGLONG_OK;
32+
}
33+
34+
std::error_code ec;
35+
std::filesystem::permissions(path, requiredPerms, std::filesystem::perm_options::add, ec);
36+
if (ec) {
37+
return LINGLONG_ERR(fmt::format("failed to change permissions: {}", path), ec);
38+
}
39+
40+
return LINGLONG_OK;
41+
}
42+
43+
} // namespace
44+
2145
linglong::utils::error::Result<std::string> readFile(const std::filesystem::path &filepath)
2246
{
2347
LINGLONG_TRACE(fmt::format("read file {}", filepath));
@@ -275,6 +299,45 @@ linglong::utils::error::Result<void> ensureDirectory(const std::filesystem::path
275299
return LINGLONG_OK;
276300
}
277301

302+
linglong::utils::error::Result<void>
303+
makeDirectoryTreeRemovable(const std::filesystem::path &root) noexcept
304+
{
305+
LINGLONG_TRACE("make directory tree removable");
306+
307+
namespace fs = std::filesystem;
308+
309+
std::error_code ec;
310+
fs::recursive_directory_iterator iter{ root,
311+
fs::directory_options::skip_permission_denied,
312+
ec };
313+
if (ec) {
314+
return LINGLONG_ERR(fmt::format("failed to iterate directory: {}", root), ec);
315+
}
316+
317+
const fs::recursive_directory_iterator end;
318+
for (; iter != end; iter.increment(ec)) {
319+
if (ec) {
320+
return LINGLONG_ERR(fmt::format("failed to iterate directory: {}", root), ec);
321+
}
322+
323+
auto status = iter->symlink_status(ec);
324+
if (ec) {
325+
return LINGLONG_ERR(fmt::format("failed to get entry status: {}", iter->path()), ec);
326+
}
327+
328+
if (status.type() == fs::file_type::directory) {
329+
auto ret = ensureOwnerPermissionsIfNeeded(iter->path(),
330+
status.permissions(),
331+
fs::perms::owner_all);
332+
if (!ret) {
333+
return ret;
334+
}
335+
}
336+
}
337+
338+
return LINGLONG_OK;
339+
}
340+
278341
linglong::utils::error::Result<void> relinkFileTo(const std::filesystem::path &link,
279342
const std::filesystem::path &target) noexcept
280343
{

libs/utils/src/linglong/utils/file.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

@@ -38,6 +38,9 @@ getFiles(const std::filesystem::path &dir);
3838

3939
linglong::utils::error::Result<void> ensureDirectory(const std::filesystem::path &dir);
4040

41+
linglong::utils::error::Result<void>
42+
makeDirectoryTreeRemovable(const std::filesystem::path &root) noexcept;
43+
4144
linglong::utils::error::Result<void> relinkFileTo(const std::filesystem::path &link,
4245
const std::filesystem::path &target) noexcept;
4346

0 commit comments

Comments
 (0)