ソースを参照

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
David Kalnischkies 10 年 前
コミット
fc5db01bb7
共有2 個のファイルを変更した36 個の追加1 個の削除を含む
  1. 1 1
      apt-pkg/contrib/fileutl.cc
  2. 35 0
      test/libapt/fileutl_test.cc

+ 1 - 1
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.

+ 35 - 0
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());
+}