Skip to content

Commit 27fbc4a

Browse files
committed
fix: follow symlinks when iterating entries directory
1. Add QDirIterator::FollowSymlinks flag to directory iterator in Cli::content method 2. This enables proper resolution of desktop files from symlinked entries/share directories 3. Previously, symlinks in the entries directory were not being followed, causing desktop files pointed to by symbolic links to be missed 4. Add two test cases to verify symlink resolution works correctly: - contentResolvesDesktopFromSymlinkedEntriesShareDir: tests resolving desktop from symlinked entries - contentResolvesOverlayDesktopFromSymlinkedEntriesShareDir: tests overlay desktop resolution with symlinks Influence: 1. Test content command with applications that have symlinked entries/ share directories 2. Verify desktop file discovery works correctly when entries/share is a symlink to files/share 3. Test both default directory fallback and overlay directory scenarios with symlinked paths 4. Verify no regression in normal (non-symlinked) directory traversal 5. Test that symlinked directories pointing outside expected paths are handled safely
1 parent 403a228 commit 27fbc4a

2 files changed

Lines changed: 85 additions & 1 deletion

File tree

libs/linglong/src/linglong/cli/cli.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,7 @@ int Cli::content(const ContentOptions &options)
17151715

17161716
QDirIterator it(entriesDir.absolutePath(),
17171717
QDir::AllEntries | QDir::NoDot | QDir::NoDotDot | QDir::System,
1718-
QDirIterator::Subdirectories);
1718+
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
17191719
while (it.hasNext()) {
17201720
it.next();
17211721
const auto entryPath = it.fileInfo().absoluteFilePath();

libs/linglong/tests/ll-tests/src/linglong/cli/cli_test.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,90 @@ TEST_F(CliTest, contentPreferDesktopFromDefaultSharedDir)
291291
EXPECT_EQ(cli->content(cli::ContentOptions{ .appid = "org.example.app" }), 0);
292292
}
293293

294+
TEST_F(CliTest, contentResolvesDesktopFromSymlinkedEntriesShareDir)
295+
{
296+
auto ref = package::Reference::parse("main:org.example.app/1.0.0/x86_64");
297+
ASSERT_TRUE(ref.has_value());
298+
299+
const std::string commit = "test-commit-symlinked-share";
300+
const auto layerFilesDir =
301+
tempDir->path() / "layers" / commit / "files" / "share" / "applications";
302+
const auto layerEntriesShareLink = tempDir->path() / "layers" / commit / "entries" / "share";
303+
const auto defaultDesktopPath =
304+
repo->defaultSharedDir() / "applications" / "org.example.app.desktop";
305+
306+
std::filesystem::create_directories(layerFilesDir);
307+
std::filesystem::create_directories(layerEntriesShareLink.parent_path());
308+
std::filesystem::create_directories(defaultDesktopPath.parent_path());
309+
std::ofstream(layerFilesDir / "org.example.app.desktop") << "Test desktop content";
310+
std::ofstream(defaultDesktopPath) << "Test desktop content in default";
311+
312+
std::error_code ec;
313+
std::filesystem::create_directory_symlink("../files/share", layerEntriesShareLink, ec);
314+
if (ec) {
315+
GTEST_SKIP() << "directory symlink support is required: " << ec.message();
316+
}
317+
318+
api::types::v1::RepositoryCacheLayersItem layerItem;
319+
layerItem.commit = commit;
320+
layerItem.info.kind = "app";
321+
322+
EXPECT_CALL(*repo, clearReference(_, _, _, _)).WillOnce(Return(*ref));
323+
EXPECT_CALL(*repo, getLayerItem(_, _, _))
324+
.WillRepeatedly(
325+
[layerItem](const package::Reference &, std::string, const std::optional<std::string> &)
326+
-> utils::error::Result<api::types::v1::RepositoryCacheLayersItem> {
327+
return layerItem;
328+
});
329+
EXPECT_CALL(*printer,
330+
printContent(ElementsAre(QString::fromStdString(defaultDesktopPath.string()))))
331+
.WillOnce(Return());
332+
333+
EXPECT_EQ(cli->content(cli::ContentOptions{ .appid = "org.example.app" }), 0);
334+
}
335+
336+
TEST_F(CliTest, contentResolvesOverlayDesktopFromSymlinkedEntriesShareDir)
337+
{
338+
auto ref = package::Reference::parse("main:org.example.app/1.0.0/x86_64");
339+
ASSERT_TRUE(ref.has_value());
340+
341+
const std::string commit = "test-commit-symlinked-share-overlay";
342+
const auto layerFilesDir =
343+
tempDir->path() / "layers" / commit / "files" / "share" / "applications";
344+
const auto layerEntriesShareLink = tempDir->path() / "layers" / commit / "entries" / "share";
345+
const auto overlayDesktopPath =
346+
tempDir->path() / "entries" / "apps" / "share" / "applications" / "org.example.app.desktop";
347+
348+
std::filesystem::create_directories(layerFilesDir);
349+
std::filesystem::create_directories(layerEntriesShareLink.parent_path());
350+
std::filesystem::create_directories(overlayDesktopPath.parent_path());
351+
std::ofstream(layerFilesDir / "org.example.app.desktop") << "Test desktop content";
352+
std::ofstream(overlayDesktopPath) << "Test desktop content in overlay";
353+
354+
std::error_code ec;
355+
std::filesystem::create_directory_symlink("../files/share", layerEntriesShareLink, ec);
356+
if (ec) {
357+
GTEST_SKIP() << "directory symlink support is required: " << ec.message();
358+
}
359+
360+
api::types::v1::RepositoryCacheLayersItem layerItem;
361+
layerItem.commit = commit;
362+
layerItem.info.kind = "app";
363+
364+
EXPECT_CALL(*repo, clearReference(_, _, _, _)).WillOnce(Return(*ref));
365+
EXPECT_CALL(*repo, getLayerItem(_, _, _))
366+
.WillRepeatedly(
367+
[layerItem](const package::Reference &, std::string, const std::optional<std::string> &)
368+
-> utils::error::Result<api::types::v1::RepositoryCacheLayersItem> {
369+
return layerItem;
370+
});
371+
EXPECT_CALL(*printer,
372+
printContent(ElementsAre(QString::fromStdString(overlayDesktopPath.string()))))
373+
.WillOnce(Return());
374+
375+
EXPECT_EQ(cli->content(cli::ContentOptions{ .appid = "org.example.app" }), 0);
376+
}
377+
294378
TEST_F(CliTest, contentFallbackDesktopToOverlaySharedDir)
295379
{
296380
auto ref = package::Reference::parse("main:org.example.app/1.0.0/x86_64");

0 commit comments

Comments
 (0)