Add some more operations to the filesystem library (#5968)

Specifically this adds `WriteStream` to get an LLVM-style
`raw_fd_ostream` for an open file, and `Rename` corresponding to
`rename` and `renameat` Unix-like system calls.

Some basic testing for both is added as well.

This was split out of work to switch the runtimes building to use the
new filesystem library.
This commit is contained in:
Chandler Carruth
2025-08-20 02:54:22 +00:00
committed by GitHub
parent 41ed82e033
commit 3c9b87ab54
2 changed files with 101 additions and 0 deletions
+65
View File
@@ -327,5 +327,70 @@ TEST_F(FilesystemTest, Chdir) {
(*std::move(f)).Close().Check();
}
TEST_F(FilesystemTest, WriteStream) {
std::string content_str = "0123456789";
auto write = dir_.OpenWriteOnly("test", CreationOptions::CreateNew);
ASSERT_THAT(write, IsSuccess(_));
{
llvm::raw_fd_ostream os = write->WriteStream();
os << content_str;
EXPECT_FALSE(os.has_error()) << os.error();
}
(*std::move(write)).Close().Check();
EXPECT_THAT(dir_.ReadFileToString("test"), IsSuccess(Eq(content_str)));
}
TEST_F(FilesystemTest, Rename) {
// Rename a file within a directory.
ASSERT_THAT(dir_.WriteFileFromString("file1", "content1"), IsSuccess(_));
EXPECT_THAT(dir_.Rename("file1", dir_, "file2"), IsSuccess(_));
EXPECT_THAT(dir_.ReadFileToString("file2"), IsSuccess(Eq("content1")));
auto read_missing = dir_.ReadFileToString("file1");
EXPECT_FALSE(read_missing.ok());
EXPECT_TRUE(read_missing.error().no_entity());
// Rename a file between two directories.
auto d1 = *dir_.CreateDirectories("subdir1");
EXPECT_THAT(dir_.Rename("file2", d1, "file1"), IsSuccess(_));
EXPECT_THAT(d1.ReadFileToString("file1"), IsSuccess(Eq("content1")));
auto d2 = *dir_.CreateDirectories("subdir2");
EXPECT_THAT(d1.Rename("file1", d2, "file1"), IsSuccess(_));
EXPECT_THAT(d2.ReadFileToString("file1"), IsSuccess(Eq("content1")));
// Close the first directory.
d1 = Filesystem::Dir();
EXPECT_THAT(dir_.Rmdir("subdir1"), IsSuccess(_))
<< "Directory should have bene empty!";
// Rename directories.
ASSERT_THAT(dir_.ReadFileToString(std::filesystem::path("subdir2") / "file1"),
IsSuccess(Eq("content1")));
EXPECT_THAT(dir_.Rename("subdir2", dir_, "subdir1"), IsSuccess(_));
EXPECT_THAT(dir_.ReadFileToString(std::filesystem::path("subdir1") / "file1"),
IsSuccess(Eq("content1")));
// The open directory `d2` should survive the rename and point at the same
// directory.
EXPECT_THAT(d2.ReadFileToString("file1"), IsSuccess(Eq("content1")));
EXPECT_THAT(d2.WriteFileFromString("file2", "content2"), IsSuccess(_));
EXPECT_THAT(dir_.ReadFileToString(std::filesystem::path("subdir1") / "file2"),
IsSuccess(Eq("content2")));
// Rename over an existing file.
EXPECT_THAT(d2.Rename("file2", d2, "file1"), IsSuccess(_));
EXPECT_THAT(d2.ReadFileToString("file1"), IsSuccess(Eq("content2")));
// Test error calls as well.
auto result = dir_.Rename("missing1", dir_, "missing2");
EXPECT_TRUE(result.error().no_entity()) << result.error();
result = d2.Rename("file1", dir_,
std::filesystem::path("missing_subdir") / "file2");
EXPECT_TRUE(result.error().no_entity()) << result.error();
// Note that `d2` was renamed `subdir1` above, which is why this creates
// infinite subdirectories.
result = dir_.Rename("subdir1", d2, "infinite_subdirs");
EXPECT_THAT(result.error().unix_errnum(), EINVAL) << result.error();
}
} // namespace
} // namespace Carbon::Filesystem