fix(files): refuse to replace an item with a link to itself

pull/18/head
reionwong 2 weeks ago
parent 7daff75e4d
commit dd068a7e2c

@ -321,10 +321,16 @@ static void validateDestination(const std::string& source, const std::string& de
throw Failure(EINVAL, destination);
}
// A folder that holds the source cannot be replaced: merging into it would write the
// source's copy into the source itself, and a move would then delete both.
// Neither the source nor a folder that holds it can be replaced: a link would take
// the place of what it points to, and merging into the folder would write the source's
// copy into the source itself, which a move would then delete.
static void validateReplacement(const std::string& source, const std::string& destination)
{
struct stat a, b;
if (::lstat(native(source).c_str(), &a) == 0 && ::lstat(native(destination).c_str(), &b) == 0
&& a.st_dev == b.st_dev && a.st_ino == b.st_ino)
throw Failure(EINVAL, destination);
const std::string sourceParent = canonicalPath(absolutePathOf(source));
const std::string destinationParent = canonicalPath(absolutePathOf(destination));
if (sourceParent.empty() || destinationParent.empty())

@ -1956,6 +1956,26 @@ TEST_F(FilesTest, LinkDrop)
EXPECT_TRUE(exists(dir.filePath("file")));
}
TEST_F(FilesTest, LinkDoesNotReplaceWhatItPointsTo)
{
TemporaryDirectory dir;
ASSERT_TRUE(makePath(dir.filePath("real")));
writeFile(dir.filePath("real/file"), "data");
ASSERT_EQ(::symlink("real", dir.filePath("alias").c_str()), 0);
OperationContext ctx;
EXPECT_EQ(errorCode([&] {
LocalFileSystem::link(dir.filePath("real/file"), dir.filePath("alias/file"), ConflictPolicy::Replace,
ctx);
}),
EINVAL);
EXPECT_FALSE(isSymbolicLink(dir.filePath("real/file")));
EXPECT_EQ(readFile(dir.filePath("real/file")), "data");
for (const std::string& name : entries(dir.filePath("real")))
EXPECT_FALSE(name.starts_with(".cutefish-")) << name;
}
TEST_F(FilesTest, TypeDescriptionsAndIcons)
{
TemporaryDirectory dir;

Loading…
Cancel
Save