Skip to content

[clang] Fix handling of adding a file with the same name as an existing dir to VFS #94461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 31 additions & 30 deletions llvm/lib/Support/VirtualFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,21 +867,16 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
// Any intermediate directories we create should be accessible by
// the owner, even if Perms says otherwise for the final path.
const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;

StringRef Name = *I;
while (true) {
StringRef Name = *I;
detail::InMemoryNode *Node = Dir->getChild(Name);
Name = *I;
++I;
if (I == E)
break;
detail::InMemoryNode *Node = Dir->getChild(Name);
if (!Node) {
if (I == E) {
// End of the path.
Dir->addChild(
Name, MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,
std::move(Buffer), ResolvedUser, ResolvedGroup,
ResolvedType, ResolvedPerms}));
return true;
}

// Create a new directory. Use the path up to here.
// This isn't the last element, so we create a new directory.
Status Stat(
StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
getDirectoryID(Dir->getUniqueID(), Name),
Expand All @@ -891,27 +886,33 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
continue;
}
// Creating file under another file.
if (!isa<detail::InMemoryDirectory>(Node))
return false;
Dir = cast<detail::InMemoryDirectory>(Node);
}
detail::InMemoryNode *Node = Dir->getChild(Name);
if (!Node) {
Dir->addChild(Name,
MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,
std::move(Buffer), ResolvedUser, ResolvedGroup,
ResolvedType, ResolvedPerms}));
return true;
}
if (isa<detail::InMemoryDirectory>(Node))
return ResolvedType == sys::fs::file_type::directory_file;

if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
Dir = NewDir;
} else {
assert((isa<detail::InMemoryFile>(Node) ||
isa<detail::InMemoryHardLink>(Node)) &&
"Must be either file, hardlink or directory!");

// Trying to insert a directory in place of a file.
if (I != E)
return false;
assert((isa<detail::InMemoryFile>(Node) ||
isa<detail::InMemoryHardLink>(Node)) &&
"Must be either file, hardlink or directory!");

// Return false only if the new file is different from the existing one.
if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
return Link->getResolvedFile().getBuffer()->getBuffer() ==
Buffer->getBuffer();
}
return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
Buffer->getBuffer();
}
// Return false only if the new file is different from the existing one.
if (auto *Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
return Link->getResolvedFile().getBuffer()->getBuffer() ==
Buffer->getBuffer();
}
return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
Buffer->getBuffer();
}

bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
Expand Down
5 changes: 5 additions & 0 deletions llvm/unittests/Support/VirtualFileSystemTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,11 @@ TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
ASSERT_TRUE(FS.addFile("/b/c/d", 0, MemoryBuffer::getMemBuffer("a")));
ASSERT_FALSE(FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer("a")));
ASSERT_TRUE(FS.addFile(
"/b/c", 0, MemoryBuffer::getMemBuffer(""), /*User=*/std::nullopt,
/*Group=*/std::nullopt, sys::fs::file_type::directory_file));
}

TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
Expand Down
Loading