]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix bsdtar zero-length pattern issue. 2787/head
authorARJANEN Loïc Jean David <ljd@luigiscorner.mu>
Fri, 14 Nov 2025 19:34:48 +0000 (20:34 +0100)
committerARJANEN Loïc Jean David <ljd@luigiscorner.mu>
Thu, 20 Nov 2025 23:44:38 +0000 (00:44 +0100)
Uses the sed-like way (and Java-like, and .Net-like, and Javascript-like…) to fix this issue of advancing the string to be processed by one if the match is zero-length.

Fixes libarchive/libarchive#2725 and solves libarchive/libarchive#2438.

tar/subst.c
tar/test/test_option_s.c

index 9747abb906c44a186f7aed350d1e9f5c3ecd328a..902a4d648532017e5bfbba31a62e8398d34490c1 100644 (file)
@@ -252,7 +252,9 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
                        (*result)[0] = 0;
                }
 
-               while (1) {
+               char isEnd = 0;
+               do {
+            isEnd = *name == '\0';
                        if (regexec(&rule->re, name, 10, matches, 0))
                                break;
 
@@ -307,12 +309,15 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
                        }
 
                        realloc_strcat(result, rule->result + j);
-
-                       name += matches[0].rm_eo;
-
-                       if (!rule->global)
-                               break;
-               }
+                       if (matches[0].rm_eo > 0) {
+                name += matches[0].rm_eo;
+            } else {
+                // We skip a character because the match is 0-length
+                // so we need to add it to the output
+                realloc_strncat(result, name, 1);
+                name += 1;
+            }
+               } while (rule->global && !isEnd); // Testing one step after because sed et al. run 0-length patterns a last time on the empty string at the end
        }
 
        if (got_match)
index 564793b97d5ed46bee475d83547b765ba66c7aad..90b4c471c1aa85ff235fea9c7dc9ca474f928aff 100644 (file)
@@ -60,7 +60,13 @@ DEFINE_TEST(test_option_s)
        systemf("%s -cf test1_2.tar -s /d1/d2/ in/d1/foo", testprog);
        systemf("%s -xf test1_2.tar -C test1", testprog);
        assertFileContents("foo", 3, "test1/in/d2/foo");
-
+       systemf("%s -cf test1_3.tar -s /o/#/g in/d1/foo", testprog);
+       systemf("%s -xf test1_3.tar -C test1", testprog);
+       assertFileContents("foo", 3, "test1/in/d1/f##");
+       // For the 0-length pattern check, remember that "test1/" isn't part of the string affected by the regexp
+       systemf("%s -cf test1_4.tar -s /f*/\\<~\\>/g in/d1/foo", testprog);
+       systemf("%s -xf test1_4.tar -C test1", testprog);
+       assertFileContents("foo", 3, "test1/<>i<>n<>/<>d<>1<>/<f><>o<>o<>");
        /*
         * Test 2: Basic substitution when extracting archive.
         */