summaryrefslogtreecommitdiff
path: root/unittests/Support/ReplaceFileTest.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /unittests/Support/ReplaceFileTest.cpp
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'unittests/Support/ReplaceFileTest.cpp')
-rw-r--r--unittests/Support/ReplaceFileTest.cpp88
1 files changed, 74 insertions, 14 deletions
diff --git a/unittests/Support/ReplaceFileTest.cpp b/unittests/Support/ReplaceFileTest.cpp
index 8b16daf3233c..794f36b1f654 100644
--- a/unittests/Support/ReplaceFileTest.cpp
+++ b/unittests/Support/ReplaceFileTest.cpp
@@ -52,6 +52,21 @@ class ScopedFD {
~ScopedFD() { Process::SafelyCloseFileDescriptor(FD); }
};
+bool FDHasContent(int FD, StringRef Content) {
+ auto Buffer = MemoryBuffer::getOpenFile(FD, "", -1);
+ assert(Buffer);
+ return Buffer.get()->getBuffer() == Content;
+}
+
+bool FileHasContent(StringRef File, StringRef Content) {
+ int FD = 0;
+ auto EC = fs::openFileForRead(File, FD);
+ (void)EC;
+ assert(!EC);
+ ScopedFD EventuallyCloseIt(FD);
+ return FDHasContent(FD, Content);
+}
+
TEST(rename, FileOpenedForReadingCanBeReplaced) {
// Create unique temporary directory for this test.
SmallString<128> TestDirectory;
@@ -79,25 +94,15 @@ TEST(rename, FileOpenedForReadingCanBeReplaced) {
// We should still be able to read the old data through the existing
// descriptor.
- auto Buffer = MemoryBuffer::getOpenFile(ReadFD, TargetFileName, -1);
- ASSERT_TRUE(static_cast<bool>(Buffer));
- EXPECT_EQ(Buffer.get()->getBuffer(), "!!target!!");
+ EXPECT_TRUE(FDHasContent(ReadFD, "!!target!!"));
// The source file should no longer exist
EXPECT_FALSE(fs::exists(SourceFileName));
}
- {
- // If we obtain a new descriptor for the target file, we should find that it
- // contains the content that was in the source file.
- int ReadFD = 0;
- ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, ReadFD));
- ScopedFD EventuallyCloseIt(ReadFD);
- auto Buffer = MemoryBuffer::getOpenFile(ReadFD, TargetFileName, -1);
- ASSERT_TRUE(static_cast<bool>(Buffer));
-
- EXPECT_EQ(Buffer.get()->getBuffer(), "!!source!!");
- }
+ // If we obtain a new descriptor for the target file, we should find that it
+ // contains the content that was in the source file.
+ EXPECT_TRUE(FileHasContent(TargetFileName, "!!source!!"));
// Rename the target file back to the source file name to confirm that rename
// still works if the destination does not already exist.
@@ -110,4 +115,59 @@ TEST(rename, FileOpenedForReadingCanBeReplaced) {
ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
}
+TEST(rename, ExistingTemp) {
+ // Test that existing .tmpN files don't get deleted by the Windows
+ // sys::fs::rename implementation.
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("ExistingTemp-test", TestDirectory));
+
+ SmallString<128> SourceFileName(TestDirectory);
+ path::append(SourceFileName, "source");
+
+ SmallString<128> TargetFileName(TestDirectory);
+ path::append(TargetFileName, "target");
+
+ SmallString<128> TargetTmp0FileName(TestDirectory);
+ path::append(TargetTmp0FileName, "target.tmp0");
+
+ SmallString<128> TargetTmp1FileName(TestDirectory);
+ path::append(TargetTmp1FileName, "target.tmp1");
+
+ ASSERT_NO_ERROR(CreateFileWithContent(SourceFileName, "!!source!!"));
+ ASSERT_NO_ERROR(CreateFileWithContent(TargetFileName, "!!target!!"));
+ ASSERT_NO_ERROR(CreateFileWithContent(TargetTmp0FileName, "!!target.tmp0!!"));
+
+ {
+ // Use mapped_file_region to make sure that the destination file is mmap'ed.
+ // This will cause SetInformationByHandle to fail when renaming to the
+ // destination, and we will follow the code path that tries to give target
+ // a temporary name.
+ int TargetFD;
+ std::error_code EC;
+ ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, TargetFD));
+ ScopedFD X(TargetFD);
+ sys::fs::mapped_file_region MFR(
+ TargetFD, sys::fs::mapped_file_region::readonly, 10, 0, EC);
+ ASSERT_FALSE(EC);
+
+ ASSERT_NO_ERROR(fs::rename(SourceFileName, TargetFileName));
+
+#ifdef _WIN32
+ // Make sure that target was temporarily renamed to target.tmp1 on Windows.
+ // This is signified by a permission denied error as opposed to no such file
+ // or directory when trying to open it.
+ int Tmp1FD;
+ EXPECT_EQ(errc::permission_denied,
+ fs::openFileForRead(TargetTmp1FileName, Tmp1FD));
+#endif
+ }
+
+ EXPECT_TRUE(FileHasContent(TargetTmp0FileName, "!!target.tmp0!!"));
+
+ ASSERT_NO_ERROR(fs::remove(TargetFileName));
+ ASSERT_NO_ERROR(fs::remove(TargetTmp0FileName));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
+}
+
} // anonymous namespace