diff options
author | Tim Kientzle <kientzle@gmail.com> | 2011-11-05 01:29:29 -0400 |
---|---|---|
committer | Tim Kientzle <kientzle@gmail.com> | 2011-11-05 01:29:29 -0400 |
commit | be20a49001ac1421a3b3fe7cde70ea86f65dde7c (patch) | |
tree | 65f7585638bc76c1f6f17b8d88a66cf21dd1e1e2 /tar | |
parent | 44a85834ef84b95eec7fc830edd7f4d9ed4a6f54 (diff) | |
download | libarchive-be20a49001ac1421a3b3fe7cde70ea86f65dde7c.tar.gz |
Issue 165: Use GNU tar-style hHrRsS trailing flags to
control hardlink, regular filename, and symlink substitutions.
SVN-Revision: 3748
Diffstat (limited to 'tar')
-rw-r--r-- | tar/bsdtar.1 | 38 | ||||
-rw-r--r-- | tar/subst.c | 35 | ||||
-rw-r--r-- | tar/test/test_option_s.c | 107 | ||||
-rw-r--r-- | tar/test/test_option_s.tar.Z.uu | 16 |
4 files changed, 159 insertions, 37 deletions
diff --git a/tar/bsdtar.1 b/tar/bsdtar.1 index 13fd39cc..a9683604 100644 --- a/tar/bsdtar.1 +++ b/tar/bsdtar.1 @@ -496,24 +496,11 @@ Extract files as sparse files. For every block on disk, check first if it contains only NULL bytes and seek over it otherwise. This works similar to the conv=sparse option of dd. -.It Fl Fl same-owner -(x mode only) -Extract owner and group IDs. -This is the reverse of -.Fl Fl no-same-owner -and the default behavior if -.Nm -is run as root. -.It Fl Fl strip-components Ar count -Remove the specified number of leading path elements. -Pathnames with fewer elements will be silently skipped. -Note that the pathname is edited after checking inclusion/exclusion patterns -but before security checks. .It Fl s Ar pattern Modify file or archive member names according to .Pa pattern . The pattern has the format -.Ar /old/new/ Ns Op gps +.Ar /old/new/ Ns Op ghHprRsS where .Ar old is a basic regular expression, @@ -535,6 +522,29 @@ 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. +Optional trailing H, R, or S characters suppress substitutions +for hardlink targets, regular filenames, or symlink targets, +respectively. +Optional trailing h, r, or s characters enable substitutions +for hardlink targets, regular filenames, or symlink targets, +respectively. +The default is +.Ar hrs +which applies substitutions to all names. +In particular, it is never necessary to specify h, r, or s. +.It Fl Fl same-owner +(x mode only) +Extract owner and group IDs. +This is the reverse of +.Fl Fl no-same-owner +and the default behavior if +.Nm +is run as root. +.It Fl Fl strip-components Ar count +Remove the specified number of leading path elements. +Pathnames with fewer elements will be silently skipped. +Note that the pathname is edited after checking inclusion/exclusion patterns +but before security checks. .It Fl T Ar filename , Fl Fl files-from Ar filename In x or t mode, .Nm diff --git a/tar/subst.c b/tar/subst.c index 018d77af..0ef95b91 100644 --- a/tar/subst.c +++ b/tar/subst.c @@ -44,7 +44,7 @@ struct subst_rule { struct subst_rule *next; regex_t re; char *result; - unsigned int global:1, print:1, symlink:1, hardlink:1; + unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1; }; struct substitution { @@ -120,6 +120,7 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text) /* Defaults */ rule->global = 0; /* Don't do multiple replacements. */ rule->print = 0; /* Don't print. */ + rule->regular = 1; /* Rewrite regular filenames. */ rule->symlink = 1; /* Rewrite symlink targets. */ rule->hardlink = 1; /* Rewrite hardlink targets. */ @@ -129,14 +130,27 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text) case 'G': rule->global = 1; break; + case 'h': + rule->hardlink = 1; + break; + case 'H': + rule->hardlink = 0; + break; case 'p': case 'P': rule->print = 1; break; + case 'r': + rule->regular = 1; + break; + case 'R': + rule->regular = 0; + break; case 's': + rule->symlink = 1; + break; case 'S': rule->symlink = 0; - rule->hardlink = 0; break; default: lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern); @@ -189,7 +203,7 @@ realloc_strcat(char **str, const char *append) int apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, - int hardlink_target, int symlink_target) + int symlink_target, int hardlink_target) { const char *path = name; regmatch_t matches[10]; @@ -207,10 +221,17 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, print_match = 0; for (rule = subst->first_rule; rule != NULL; rule = rule->next) { - if (symlink_target && !rule->symlink) - continue; - if (hardlink_target && !rule->hardlink) - continue; + if (symlink_target) { + if (!rule->symlink) + continue; + } else if (hardlink_target) { + if (!rule->hardlink) + continue; + } else { /* Regular filename. */ + if (!rule->regular) + continue; + } + if (regexec(&rule->re, name, 10, matches, 0)) continue; diff --git a/tar/test/test_option_s.c b/tar/test/test_option_s.c index df2550c2..f643f187 100644 --- a/tar/test/test_option_s.c +++ b/tar/test/test_option_s.c @@ -152,27 +152,102 @@ DEFINE_TEST(test_option_s) /* * Test 9: selective renaming of hardlink target */ + /* At extraction. (assuming hardlink2 is the hardlink entry) */ + assertMakeDir("test9a", 0755); + systemf("%s -cf - in/d1 | %s -xf - -s /hardlink1/hardlink1-renamed/ -C test9a", + testprog, testprog); + assertIsHardlink("test9a/in/d1/hardlink1-renamed", "test9a/in/d1/hardlink2"); + /* At extraction. (assuming hardlink1 is the hardlink entry) */ + assertMakeDir("test9b", 0755); + systemf("%s -cf - in/d1 | %s -xf - -s /hardlink2/hardlink2-renamed/ -C test9b", + testprog, testprog); + assertIsHardlink("test9b/in/d1/hardlink1", "test9b/in/d1/hardlink2-renamed"); + /* At creation. (assuming hardlink2 is the hardlink entry) */ + assertMakeDir("test9c", 0755); + systemf("%s -cf - -s /hardlink1/hardlink1-renamed/ in/d1 | %s -xf - -C test9c", + testprog, testprog); + assertIsHardlink("test9c/in/d1/hardlink1-renamed", "test9c/in/d1/hardlink2"); + /* At creation. (assuming hardlink1 is the hardlink entry) */ + assertMakeDir("test9d", 0755); + systemf("%s -cf - -s /hardlink2/hardlink2-renamed/ in/d1 | %s -xf - -C test9d", + testprog, testprog); + assertIsHardlink("test9d/in/d1/hardlink1", "test9d/in/d1/hardlink2-renamed"); + + /* + * Test 10: renaming symlink target without repointing symlink + */ if (canSymlink()) { - /* At extraction. (assuming hardlink2 is the hardlink entry) */ - assertMakeDir("test9a", 0755); - systemf("%s -cf - in/d1 | %s -xf - -s /hardlink1/hardlink1-renamed/ -C test9a", + /* At extraction. */ + assertMakeDir("test10a", 0755); + systemf("%s -cf - in/d1 | %s -xf - -s /realfile/foo/S -s /foo/realfile/ -C test10a", testprog, testprog); - assertIsHardlink("test9a/in/d1/hardlink1-renamed", "test9a/in/d1/hardlink2"); - /* At extraction. (assuming hardlink1 is the hardlink entry) */ - assertMakeDir("test9b", 0755); - systemf("%s -cf - in/d1 | %s -xf - -s /hardlink2/hardlink2-renamed/ -C test9b", + assertFileContents("realfile", 8, "test10a/in/d1/foo"); + assertFileContents("foo", 3, "test10a/in/d1/realfile"); + assertFileContents("foo", 3, "test10a/in/d1/symlink"); + assertIsSymlink("test10a/in/d1/symlink", "realfile"); + /* At creation. */ + assertMakeDir("test10b", 0755); + systemf("%s -cf - -s /realfile/foo/S -s /foo/realfile/ in/d1 | %s -xf - -C test10b", testprog, testprog); - assertIsHardlink("test9b/in/d1/hardlink1", "test9b/in/d1/hardlink2-renamed"); - /* At creation. (assuming hardlink2 is the hardlink entry) */ - assertMakeDir("test9c", 0755); - systemf("%s -cf - -s /hardlink1/hardlink1-renamed/ in/d1 | %s -xf - -C test9c", + assertFileContents("realfile", 8, "test10b/in/d1/foo"); + assertFileContents("foo", 3, "test10b/in/d1/realfile"); + assertFileContents("foo", 3, "test10b/in/d1/symlink"); + assertIsSymlink("test10b/in/d1/symlink", "realfile"); + } + + /* + * Test 11: repointing symlink without renaming file + */ + if (canSymlink()) { + /* At extraction. */ + assertMakeDir("test11a", 0755); + systemf("%s -cf - in/d1 | %s -xf - -s /realfile/foo/sR -C test11a", testprog, testprog); - assertIsHardlink("test9c/in/d1/hardlink1-renamed", "test9c/in/d1/hardlink2"); - /* At creation. (assuming hardlink1 is the hardlink entry) */ - assertMakeDir("test9d", 0755); - systemf("%s -cf - -s /hardlink2/hardlink2-renamed/ in/d1 | %s -xf - -C test9d", + assertFileContents("foo", 3, "test11a/in/d1/foo"); + assertFileContents("realfile", 8, "test11a/in/d1/realfile"); + assertFileContents("foo", 3, "test11a/in/d1/symlink"); + assertIsSymlink("test11a/in/d1/symlink", "foo"); + /* At creation. */ + assertMakeDir("test11b", 0755); + systemf("%s -cf - -s /realfile/foo/R in/d1 | %s -xf - -C test11b", testprog, testprog); - assertIsHardlink("test9d/in/d1/hardlink1", "test9d/in/d1/hardlink2-renamed"); + assertFileContents("foo", 3, "test11b/in/d1/foo"); + assertFileContents("realfile", 8, "test11b/in/d1/realfile"); + assertFileContents("foo", 3, "test11b/in/d1/symlink"); + assertIsSymlink("test11b/in/d1/symlink", "foo"); } + /* + * Test 12: renaming hardlink target without changing hardlink. + * (Requires a pre-built archive, since we otherwise can't know + * which element will be stored as the hardlink.) + */ + extract_reference_file("test_option_s.tar.Z"); + assertMakeDir("test12a", 0755); + systemf("%s -xf test_option_s.tar.Z -s /hardlink1/foo/H -s /foo/hardlink1/ -C test12a", + testprog); + assertFileContents("foo", 3, "test12a/in/d1/hardlink1"); + assertFileContents("hardlinkedfile", 14, "test12a/in/d1/foo"); + assertFileContents("foo", 3, "test12a/in/d1/hardlink2"); + assertIsHardlink("test12a/in/d1/hardlink1", "test12a/in/d1/hardlink2"); + /* TODO: Expand this test to verify creation as well. + * Since either hardlink1 or hardlink2 might get stored as a hardlink, + * this will either requiring testing both cases and accepting either + * pass, or some very creative renames that can be tested regardless. + */ + + /* + * Test 13: repoint hardlink without changing files + * (Requires a pre-built archive, since we otherwise can't know + * which element will be stored as the hardlink.) + */ + extract_reference_file("test_option_s.tar.Z"); + assertMakeDir("test13a", 0755); + systemf("%s -xf test_option_s.tar.Z -s /hardlink1/foo/Rh -s /foo/hardlink1/Rh -C test13a", + testprog); + assertFileContents("foo", 3, "test13a/in/d1/foo"); + assertFileContents("hardlinkedfile", 14, "test13a/in/d1/hardlink1"); + assertFileContents("foo", 3, "test13a/in/d1/hardlink2"); + assertIsHardlink("test13a/in/d1/foo", "test13a/in/d1/hardlink2"); + /* TODO: See above; expand this test to verify renames at creation. */ } diff --git a/tar/test/test_option_s.tar.Z.uu b/tar/test/test_option_s.tar.Z.uu new file mode 100644 index 00000000..df690bfa --- /dev/null +++ b/tar/test/test_option_s.tar.Z.uu @@ -0,0 +1,16 @@ +begin 644 test_option_s.tar.Z +M'YV0:=R\(!/C!8"#"!,J7,BPH<.'$"-*1`BCXHT:-4``J`CCAHV,&SG*H*&1 +MHTF3(&+$^%@C!HT8,&C(``%#Y0T9,P"`J#&QI\^?0(,"J#.'3A@Y(>FD:2/4 +M8=$P9LPT77@21LF3&J=JW<JUJU>A`0<6%'/TJ]FS"3G:H$$R9,>/5RN.C%L5 +MQHR4*S&ZA"F39HR1=G7"0$NX<$*B1I%65,KTZ].H7JO2K9C5L.7+F+>219JY +ML^?/H$.+'DVZM&G+80F^,//FS6G0:MG&]0C2Y%RW=>^J9+DWYLR:(V7($/SZ +M->*RBY>:?2RUJV3<E(M+GQZ1M6OJV+-KW\Z]NW?3J0NB.4J&3<`U,;YKC=V6 +M(VVZM^M67(F7]TO??F?4D#&8IGK,QRD&`V/+&069<UA!9]5_#'8VGASEG5<& +M&6:DP489#6:HX88<=NAA3^&]\&"$;JPQW(<0L3<;7+C%)Q]EN^EU7U\UV2!< +M3BF%.*)Y)::'XD,!)J6<8P8VQ]5SS_VHI$\ARE%&&&Q4>.&2#JGHUGLMMB<? +M3/7)R-=O,<P@4W^#4=E4D,DUYA5SD268I)EP,N0DE%)B&.>=>.:IYYX'A3A' +M'FWPN`:?[F&T8FTB:?EBERW-"&8-=N$HPYQ16F@GGPBA.>"0:Q;9)DH*5H;I +MJ*26:NJIJ*:JZJJLMNKJJ[#&*NNLM-9JZZVXYJKKKKSVZNNOP`8K[+#$%FOL +)L<@FJ^RRS.X) +` +end |