summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2016-06-29 14:46:34 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2016-06-29 14:46:34 +0200
commitfc5db01bb7d1546944200d197866b0b5c378f100 (patch)
treead044e6819655d1fddeb3331680557b934a2666f
parentcfc6566d5097ef5518e12f5c1e5f15a8f5b182cf (diff)
don't do atomic overrides with failed files
We deploy atomic renames for some files, but these renames also happen if something about the file failed which isn't really the point of the exercise… Closes: 828908
-rw-r--r--apt-pkg/contrib/fileutl.cc2
-rw-r--r--test/libapt/fileutl_test.cc35
2 files changed, 36 insertions, 1 deletions
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index 94d1432cf..388849144 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -2623,7 +2623,7 @@ bool FileFd::Close()
}
if ((Flags & Replace) == Replace) {
- if (rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
+ if (Failed() == false && rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
FileName = TemporaryFileName; // for the unlink() below.
diff --git a/test/libapt/fileutl_test.cc b/test/libapt/fileutl_test.cc
index 8cd5132ce..0a299b51a 100644
--- a/test/libapt/fileutl_test.cc
+++ b/test/libapt/fileutl_test.cc
@@ -327,6 +327,7 @@ TEST(FileUtlTest, flAbsPath)
static void TestDevNullFileFd(unsigned int const filemode)
{
+ SCOPED_TRACE(filemode);
FileFd f("/dev/null", filemode);
EXPECT_FALSE(f.Failed());
EXPECT_TRUE(f.IsOpen());
@@ -354,3 +355,37 @@ TEST(FileUtlTest, WorkingWithDevNull)
TestDevNullFileFd(FileFd::WriteTemp);
TestDevNullFileFd(FileFd::WriteAtomic);
}
+constexpr char const * const TESTSTRING = "This is a test";
+static void TestFailingAtomicKeepsFile(char const * const label, std::string const &filename)
+{
+ SCOPED_TRACE(label);
+ EXPECT_TRUE(FileExists(filename));
+ FileFd fd;
+ EXPECT_TRUE(fd.Open(filename, FileFd::ReadOnly));
+ char buffer[50];
+ EXPECT_NE(nullptr, fd.ReadLine(buffer, sizeof(buffer)));
+ EXPECT_STREQ(TESTSTRING, buffer);
+}
+TEST(FileUtlTest, FailingAtomic)
+{
+ FileFd fd;
+ std::string filename;
+ createTemporaryFile("failingatomic", fd, &filename, TESTSTRING);
+ TestFailingAtomicKeepsFile("init", filename);
+
+ FileFd f;
+ EXPECT_TRUE(f.Open(filename, FileFd::ReadWrite | FileFd::Atomic));
+ f.EraseOnFailure();
+ EXPECT_FALSE(f.Failed());
+ EXPECT_TRUE(f.IsOpen());
+ TestFailingAtomicKeepsFile("before-fail", filename);
+ EXPECT_TRUE(f.Write("Bad file write", 10));
+ f.OpFail();
+ EXPECT_TRUE(f.Failed());
+ TestFailingAtomicKeepsFile("after-fail", filename);
+ EXPECT_TRUE(f.Close());
+ TestFailingAtomicKeepsFile("closed", filename);
+
+ if (filename.empty() == false)
+ unlink(filename.c_str());
+}