]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add trailing letter b to bsdtar substitute pattern (#2012)
authorgrembo <freebsd@grem.de>
Mon, 11 Dec 2023 05:51:13 +0000 (06:51 +0100)
committerGitHub <noreply@github.com>
Mon, 11 Dec 2023 05:51:13 +0000 (21:51 -0800)
The letter b stands for "from (b)eginning" and specifies that a
substitute expression should be matched from the beginning of the
string, regardless if and where a previous substitute expression
matched.

Example:
Transform filename from B-A to A-B and remove all underscores.

Attempt without option b:

    bsdtar -cft -s '/\(.*\)-\(.*\)/\2-\1/gp' -s "/_//g" ab_c-d_ef
    ab_c-d_ef >> d_ef-ab_c

With option b:

    bsdtar -cft -s '/\(.*\)-\(.*\)/\2-\1/gp' -s "/_//gb" ab_c-d_ef
    ab_c-d_ef >> def-abc

tar/bsdtar.1
tar/subst.c
tar/test/test_option_s.c

index c80952600165ed916cafa61791544fdb78774f01..9a94bf7612349d483b8d89856924df3c77b983e1 100644 (file)
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd December 1, 2022
+.Dd December 10, 2023
 .Dt TAR 1
 .Os
 .Sh NAME
@@ -772,7 +772,7 @@ This works similar to the conv=sparse option of dd.
 Modify file or archive member names according to
 .Pa pattern .
 The pattern has the format
-.Ar /old/new/ Ns Op ghHprRsS
+.Ar /old/new/ Ns Op bghHprRsS
 where
 .Ar old
 is a basic regular expression,
@@ -794,6 +794,9 @@ of symbolic links.
 The optional trailing p specifies that after a successful substitution
 the original path name and the new path name should be printed to
 standard error.
+The optional trailing b specifies that the substitution should be
+matched from the beginning of the string rather than from right after the
+position at which the previous matching substitution ended.
 Optional trailing H, R, or S characters suppress substitutions
 for hardlink targets, regular filenames, or symlink targets,
 respectively.
index 659c0b88f9b11796077c40fff66c117d3321fd34..9747abb906c44a186f7aed350d1e9f5c3ecd328a 100644 (file)
@@ -49,7 +49,7 @@ struct subst_rule {
        struct subst_rule *next;
        regex_t re;
        char *result;
-       unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1;
+       unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1, from_begin:1;
 };
 
 struct substitution {
@@ -129,9 +129,14 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text)
        rule->regular = 1; /* Rewrite regular filenames. */
        rule->symlink = 1; /* Rewrite symlink targets. */
        rule->hardlink = 1; /* Rewrite hardlink targets. */
+       rule->from_begin = 0; /* Don't match from start. */
 
        while (*++end_pattern) {
                switch (*end_pattern) {
+               case 'b':
+               case 'B':
+                       rule->from_begin = 1;
+                       break;
                case 'g':
                case 'G':
                        rule->global = 1;
@@ -214,6 +219,7 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
 {
        const char *path = name;
        regmatch_t matches[10];
+       char* buffer = NULL;
        size_t i, j;
        struct subst_rule *rule;
        struct substitution *subst;
@@ -239,6 +245,13 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
                                continue;
                }
 
+               if (rule->from_begin && *result) {
+                       realloc_strcat(result, name);
+                       realloc_strcat(&buffer, *result);
+                       name = buffer;
+                       (*result)[0] = 0;
+               }
+
                while (1) {
                        if (regexec(&rule->re, name, 10, matches, 0))
                                break;
@@ -278,6 +291,7 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
                                case '9':
                                        realloc_strncat(result, rule->result + j, i - j - 1);
                                        if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) {
+                                               free(buffer);
                                                free(*result);
                                                *result = NULL;
                                                return -1;
@@ -304,6 +318,8 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
        if (got_match)
                realloc_strcat(result, name);
 
+       free(buffer);
+
        if (print_match)
                fprintf(stderr, "%s >> %s\n", path, *result);
 
index ed68ebf7290eb1c5fdd1caa2fae2b2223d483e6b..564793b97d5ed46bee475d83547b765ba66c7aad 100644 (file)
@@ -87,6 +87,17 @@ DEFINE_TEST(test_option_s)
        assertFileContents("foo", 3, "test4/in/d1/bar");
        assertFileContents("bar", 3, "test4/in/d1/baz");
 
+       /*
+        * Test 4b: Multiple substitutions behavior with option b).
+        */
+       assertMakeDir("test4b", 0755);
+       systemf("%s -cf test4b.tar in/d1/foo in/d1/bar",
+           testprog);
+       systemf("%s -xf test4b.tar -s /oo/ar/ -s }ar}az}b -C test4b",
+           testprog);
+       assertFileContents("foo", 3, "test4b/in/d1/faz");
+       assertFileContents("bar", 3, "test4b/in/d1/baz");
+
        /*
         * Test 5: Name-switching substitutions when extracting archive.
         */