Преглед изворни кода

LibDiff: Reject patches adding files when a file already exists

We should still add an informational message about when this happens
before we even get here - but we still shouldn't be able to locate a
place to apply a hunk as it ends up producing unexpected results where
the patch is prepended to the existing file.
Shannon Booth пре 1 година
родитељ
комит
df6a627323
2 измењених фајлова са 34 додато и 3 уклоњено
  1. 20 0
      Tests/Utilities/TestPatch.cpp
  2. 14 3
      Userland/Libraries/LibDiff/Applier.cpp

+ 20 - 0
Tests/Utilities/TestPatch.cpp

@@ -200,3 +200,23 @@ TEST_CASE(two_patches_in_single_patch_file)
     EXPECT_FILE_EQ(ByteString::formatted("{}/first_file_to_add", s_test_dir), "Hello, friends!\n");
     EXPECT_FILE_EQ(ByteString::formatted("{}/second_file_to_add", s_test_dir), "Hello, friends!\n");
 }
+
+TEST_CASE(patch_adding_file_to_existing_file)
+{
+    PatchSetup setup;
+
+    auto patch = R"(
+--- /dev/null
++++ a
+@@ -0,0 +1 @@
++1
+)"sv;
+
+    auto file = "a\n"sv;
+    auto input = MUST(Core::File::open(ByteString::formatted("{}/a", s_test_dir), Core::File::OpenMode::Write));
+    MUST(input->write_until_depleted(file.bytes()));
+
+    run_patch(ExpectSuccess::No, {}, patch);
+
+    EXPECT_FILE_EQ(ByteString::formatted("{}/a", s_test_dir), "a\n"sv);
+}

+ 14 - 3
Userland/Libraries/LibDiff/Applier.cpp

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
+ * Copyright (c) 2023-2024, Shannon Booth <shannon@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -35,9 +35,20 @@ static Optional<Location> locate_hunk(Vector<StringView> const& content, Hunk co
     // Make a first best guess at where the from-file range is telling us where the hunk should be.
     size_t offset_guess = expected_line_number(hunk.location) - 1 + offset;
 
-    // If there's no lines surrounding this hunk - it will always succeed, so there is no point in checking any further.
-    if (hunk.location.old_range.number_of_lines == 0)
+    // If there's no lines surrounding this hunk - it will always succeed,
+    // so there is no point in checking any further. Note that this check is
+    // also what makes matching against an empty 'from file' work (with no lines),
+    // as in that case there is no content for us to even match against in the
+    // first place!
+    //
+    // However, we also should reject patches being added when the hunk is
+    // claiming the file is completely empty - but there are actually lines in
+    // that file.
+    if (hunk.location.old_range.number_of_lines == 0) {
+        if (hunk.location.old_range.start_line == 0 && !content.is_empty())
+            return {};
         return Location { offset_guess, 0, 0 };
+    }
 
     size_t patch_prefix_context = 0;
     for (auto const& line : hunk.lines) {