From: Sergey Poznyakoff Date: Thu, 30 Oct 2008 14:13:01 +0000 (+0000) Subject: * NEWS, configure.ac: Version 1.20.91 X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=b4ec8aedf9c8948bee9bf1635132a7da7a522611;p=chaz%2Ftar * NEWS, configure.ac: Version 1.20.91 * doc/tar.texi: Document transformation scope flags. * src/common.h (transform_symlinks_option): Remove in favor of transformation scope flags. (XFORM_REGFILE, XFORM_LINK, XFORM_SYMLINK, XFORM_ALL): New macros. (transform_name, transform_member_name, transform_name_fp): Take an additional argument, specifying scope flags. * src/create.c: Reflect changes to transform_name. * src/extract.c (extract_link, extract_symlink): Remove calls to transform_member_name. It is done in read_header. * src/list.c (decode_xform): Reflect change in data type of 2nd argument. (transform_member_name): 2nd arg is int. (decode_header): Transform file name and link target names. * src/tar.c: Remove --transform-symlinks. * src/transform.c (struct transform): New member `flags'. (transform_flags): New variable. (parse_transform_expr): Parse transformation scope flags. Allow to set global flags using `flags=' syntax. (_transform_name_to_obstack, transform_name_fp) (transform_name): Take an additional argument, specifying scope flags. --- diff --git a/ChangeLog b/ChangeLog index 2d54b2a..8c1c4f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2008-10-30 Sergey Poznyakoff + + * NEWS, configure.ac: Version 1.20.91 + * doc/tar.texi: Document transformation scope flags. + * src/common.h (transform_symlinks_option): Remove in favor of + transformation scope flags. + (XFORM_REGFILE, XFORM_LINK, XFORM_SYMLINK, XFORM_ALL): New macros. + (transform_name, transform_member_name, transform_name_fp): Take + an additional argument, specifying scope flags. + * src/create.c: Reflect changes to transform_name. + * src/extract.c (extract_link, extract_symlink): Remove calls to + transform_member_name. It is done in read_header. + * src/list.c (decode_xform): Reflect change in data type of 2nd + argument. + (transform_member_name): 2nd arg is int. + (decode_header): Transform file name and link target names. + * src/tar.c: Remove --transform-symlinks. + * src/transform.c (struct transform): New member `flags'. + (transform_flags): New variable. + (parse_transform_expr): Parse transformation scope flags. Allow to + set global flags using `flags=' syntax. + (_transform_name_to_obstack, transform_name_fp) + (transform_name): Take an additional argument, specifying scope + flags. + 2008-10-19 Sergey Poznyakoff * THANKS: Add Ed Leaver. diff --git a/NEWS b/NEWS index b87d017..8037aed 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,8 @@ -GNU tar NEWS - User visible changes. 2008-10-22 +GNU tar NEWS - User visible changes. 2008-10-30 Please send GNU tar bug reports to -version 1.20.90 (CVS) +version 1.20.91 (CVS) * New short option -J @@ -28,21 +28,40 @@ back to using archive suffix to determine it. Using --exclude-vcs handles also files used internally by Bazaar, Mercurial and Darcs. -* The --transform-symlink option. +* Transformation scope flags -The effect of the --transform option on the symbolic links targets is -controlled by --transform-symlink and --no-transform-symlink options. -By default, transformations do not apply to symlink targets, -which corresponds to the behavior of version 1.19. To apply -transformations to symlink targets as well, use --transform-symlink -option. The --no-transform-symlink option cancels the effect of any -prior --transform-symlink. +Name transformation expressions understand additional flags that +control type of archive members affected by them. The flags are: + + - r + Apply transformation to regular archive members. + + - s + Apply transformation to symbolic link targets. + + - h + Apply transformation to hard link targets. + +Corresponding upper-case letters negate the flag meaning, so that +`H' means ``do not apply transformation to hard link targets.'' + +The scope flags are listed in the third part of an `s' expression, +e.g.: + + tar --transform 's|^|/usr/local/|S' + +Default is `rsh', which means that transformations are applied to +both regular archive members and to the targets of symbolic and hard +links. If several transform expressions are used, the default flags +can be changed using `flags=' statement before the expressions, e.g.: + + tar --transform 'flags=S;s|^|/usr/local/|S' * Bugfixes ** The --null option disabled handling of tar options in list files. This is fixed. -** Fixed record size autodetection. If the detected record size differs from +** Fixed record size autodetection. If detected record size differs from the expected value (either default, or set on the command line), tar always prints a warning if verbosity level is set to 1 or greater, i.e. if either -t or -v option is given. diff --git a/configure.ac b/configure.ac index f749aa4..453e853 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. -AC_INIT([GNU tar], [1.20.90], [bug-tar@gnu.org]) +AC_INIT([GNU tar], [1.20.91], [bug-tar@gnu.org]) AC_CONFIG_SRCDIR([src/tar.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h:config.hin]) diff --git a/doc/tar.texi b/doc/tar.texi index 43970ad..cb8bd19 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -2905,13 +2905,6 @@ characters set by the previous @option{--quote-chars} option With this option, @command{tar} will not recurse into directories. @xref{recurse}. -@opsummary{no-transform-symlinks} -@item --no-transform-symlinks -Cancel the effect of any prior @command{--transform-symlinks} option -(see below) and return to the default behavior of applying name -transformation expression only to the names of files (archive -members), not to target of symbolic links. - @opsummary{no-same-owner} @item --no-same-owner @itemx -o @@ -3292,11 +3285,6 @@ To see transformed member names in verbose listings, use @option{--show-transformed-names} option (@pxref{show-transformed-names}). -@opsummary{transform-symlinks} -@item --transform-symlinks -Apply @command{--transform} option to symbolic link targets -(@pxref{transform}). - @opsummary{uncompress} @item --uncompress @@ -7605,8 +7593,8 @@ The option @option{--strip=2} instructs @command{tar} to strip the two leading components (@file{usr/} and @file{include/}) off the file name. -If you add to the above invocation @option{--verbose} (@option{-v}) -option, you will note that the verbose listing still contains the +If you add the @option{--verbose} (@option{-v}) option to the invocation +above, you will note that the verbose listing still contains the full file name, with the two removed components still in place. This can be inconvenient, so @command{tar} provides a special option for altering this behavior: @@ -7631,7 +7619,7 @@ stdlib.h @end group @end smallexample -Notice that in both cases the file is @file{stdlib.h} extracted to the +Notice that in both cases the file @file{stdlib.h} is extracted to the current working directory, @option{--show-transformed-names} affects only the way its name is displayed. @@ -7677,6 +7665,21 @@ replacement for each file name part that matches @var{regexp}. Both @var{regexp} and @var{replace} are described in detail in @ref{The "s" Command, The "s" Command, The `s' Command, sed, GNU sed}. +Any delimiter can be used in lieue of @samp{/}, the only requirement being +that it be used consistently throughout the expression. For example, +the following two expressions are equivalent: + +@smallexample +@group +s/one/two/ +s,one,two, +@end group +@end smallexample + +Changing delimiters is often useful when the @var{regex} contains +slashes. For example, it is more convenient to write @code{s,/,-,} than +@code{s/\//-/}. + As in @command{sed}, you can give several replace expressions, separated by a semicolon. @@ -7707,21 +7710,41 @@ the interaction is defined to be: ignore matches before the @end table -Any delimiter can be used in lieue of @samp{/}, the only requirement being -that it be used consistently throughout the expression. For example, -the following two expressions are equivalent: +In addition, several @dfn{transformation scope} flags are supported, +that control to what files transformations apply. These are: + +@table @samp +@item r +Apply transformation to regular archive members. + +@item R +Do not apply transformation to regular archive members. + +@item s +Apply transformation to symbolic link targets. + +@item S +Do not apply transformation to symbolic link targets. + +@item h +Apply transformation to hard link targets. + +@item H +Do not apply transformation to hard link targets. +@end table + +Default is @samp{rsh}, which means to apply tranformations to both archive +members and targets of symbolic and hard links. + +Default scope flags can also be changed using @samp{flags=} statement +in the transform expression. The flags set this way remain in force +until next @samp{flags=} statement or end of expression, whichever +occurs first. For example: @smallexample -@group -s/one/two/ -s,one,two, -@end group + --transform 'flags=S;s|^|/usr/local/|' @end smallexample -Changing delimiters is often useful when the @var{regex} contains -slashes. For example, it is more convenient to write @code{s,/,-,} than -@code{s/\//-/}. - Here are several examples of @option{--transform} usage: @enumerate @@ -7738,61 +7761,59 @@ $ @kbd{tar --transform='s,usr/,usr/local/,' -x -f arch.tar} $ @kbd{tar --transform='s,/*[^/]*/[^/]*/,,' -x -f arch.tar} @end smallexample +@item Convert each file name to lower case: + +@smallexample +$ @kbd{tar --transform 's/.*/\L&/' -x -f arch.tar} +@end smallexample + @item Prepend @file{/prefix/} to each file name: @smallexample $ @kbd{tar --transform 's,^,/prefix/,' -x -f arch.tar} @end smallexample -@item Convert each file name to lower case: +@item Archive the @file{/lib} directory, prepending @samp{/usr/local} +to each archive member: @smallexample -$ @kbd{tar --transform 's/.*/\L&/' -x -f arch.tar} +$ @kbd{tar --transform 's,^,/usr/local/,S' -c -f arch.tar /lib} @end smallexample - @end enumerate -The @option{--transform} option applies only to member names. It does -not apply to symbolic link targets. In many cases, this is the -desired behavior. Consider for example, archiving the @file{/lib} -directory: +Notice the use of flags in the last example. The @file{/lib} +directory often contains many symbolic links to files within it. +It may look, for example, like this: @smallexample -$ @kbd{tar -vv -c -f archive /lib} -tar: Removing leading `/' from member names +$ @kbd{ls -l} drwxr-xr-x root/root 0 2008-07-08 16:20 /lib/ -rwxr-xr-x root/root 1250840 2008-05-25 07:44 /lib/libc-2.3.2.so lrwxrwxrwx root/root 0 2008-06-24 17:12 /lib/libc.so.6 -> libc-2.3.2.so ... @end smallexample -Now, you can use our example above to extract it into @file{/usr/local}: +Using the expression @samp{s,^,/usr/local/,} would mean adding +@samp{/usr/local} to both regular archive members and to link +targets. In this case, @file{/lib/libc.so.6} would become: + +@smallexample + /usr/local/lib/libc.so.6 -> /usr/local/libc-2.3.2.so +@end smallexample + +This is definitely not desired. To avoid this, the @samp{S} flag +are used, which excludes symbolic link targets from filename +transformations. The result is: @smallexample -$ @kbd{tar --transform 's,^,/usr/local/,' \ - --show-transformed -v -x -f archive} +$ @kbd{tar --transform 's,^,/usr/local/,S', -c -v -f arch.tar \ + --show-transformed /lib} drwxr-xr-x root/root 0 2008-07-08 16:20 /usr/local/lib/ -rwxr-xr-x root/root 1250840 2008-05-25 07:44 /usr/local/lib/libc-2.3.2.so lrwxrwxrwx root/root 0 2008-06-24 17:12 /usr/local/lib/libc.so.6 -> libc-2.3.2.so @end smallexample -As you see, it correctly extracts @file{libc.so.6} as a symbolic link -to @file{libc-2.3.2.so}. - -However, sometimes you may need to transform symbolic link targets as -well. To do so, @GNUTAR provides an additional option: - -@table @option -@opindex transform-symlinks -@item --transform-symlinks -Apply @command{--transform} option to symbolic link targets. - -@opindex no-transform-symlinks -@itemx --no-transform-symlinks -Cancel the effect of the previous @option{--transform-symlinks} option. -@end table - Unlike @option{--strip-components}, @option{--transform} can be used in any @GNUTAR{} operation mode. For example, the following command adds files to the archive while replacing the leading @file{usr/} diff --git a/lib/.cvsignore b/lib/.cvsignore index 9173507..dd95780 100644 --- a/lib/.cvsignore +++ b/lib/.cvsignore @@ -35,6 +35,7 @@ chdir-long.h chown.c close-stream.c close-stream.h +close.c closeout.c closeout.h config.charset @@ -59,6 +60,7 @@ fchdir.c fchmodat.c fchown-stub.c fchownat.c +fclose.c fcntl--.h fcntl-safer.h fcntl.h diff --git a/src/common.h b/src/common.h index 947546a..cc3483e 100644 --- a/src/common.h +++ b/src/common.h @@ -346,9 +346,6 @@ GLOBAL bool unquote_option; GLOBAL bool test_label_option; /* Test archive volume label and exit */ -/* Apply transformations to symlink targets as well. */ -GLOBAL bool transform_symlinks_option; - /* Show file or archive names after transformation. In particular, when creating archive in verbose mode, list member names as stored in the archive */ @@ -738,17 +735,16 @@ bool string_ascii_p (const char *str); bool utf8_convert (bool to_utf, char const *input, char **output); /* Module transform.c */ -typedef enum - { - xform_regfile, - xform_link, - xform_symlink - } xform_type; +#define XFORM_REGFILE 0x01 +#define XFORM_LINK 0x02 +#define XFORM_SYMLINK 0x04 +#define XFORM_ALL (XFORM_REGFILE|XFORM_LINK|XFORM_SYMLINK) void set_transform_expr (const char *expr); -bool transform_name (char **pinput); -bool transform_member_name (char **pinput, xform_type type); -bool transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *); +bool transform_name (char **pinput, int type); +bool transform_member_name (char **pinput, int type); +bool transform_name_fp (char **pinput, int type, + char *(*fun)(char *, void *), void *); /* Module suffix.c */ void set_comression_program_by_suffix (const char *name, const char *defprog); diff --git a/src/create.c b/src/create.c index 7b20c02..a925160 100644 --- a/src/create.c +++ b/src/create.c @@ -1495,7 +1495,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, assign_string (&st->file_name, safer_name_suffix (p, false, absolute_names_option)); - transform_name (&st->file_name); + transform_name (&st->file_name, XFORM_REGFILE); if (deref_stat (dereference_option, p, &st->stat) != 0) { @@ -1705,8 +1705,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, } buffer[size] = '\0'; assign_string (&st->link_name, buffer); - if (transform_symlinks_option) - transform_name (&st->link_name); + transform_name (&st->link_name, XFORM_SYMLINK); if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size) write_long_link (st); diff --git a/src/extract.c b/src/extract.c index 0d938e6..6d70398 100644 --- a/src/extract.c +++ b/src/extract.c @@ -917,7 +917,6 @@ extract_link (char *file_name, int typeflag) int interdir_made = 0; char const *link_name; - transform_member_name (¤t_stat_info.link_name, xform_link); link_name = current_stat_info.link_name; if (! absolute_names_option && contains_dot_dot (link_name)) @@ -974,8 +973,6 @@ extract_symlink (char *file_name, int typeflag) int status; int interdir_made = 0; - transform_member_name (¤t_stat_info.link_name, xform_symlink); - if (! absolute_names_option && (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name) || contains_dot_dot (current_stat_info.link_name))) diff --git a/src/list.c b/src/list.c index b17f604..98c1e39 100644 --- a/src/list.c +++ b/src/list.c @@ -472,11 +472,11 @@ read_header (bool raw_extended_headers) static char * decode_xform (char *file_name, void *data) { - xform_type type = *(xform_type*)data; + int type = *(int*)data; switch (type) { - case xform_symlink: + case XFORM_SYMLINK: /* FIXME: It is not quite clear how and to which extent are the symbolic links subject to filename transformation. In the absence of another solution, symbolic links are exempt from component stripping and @@ -484,11 +484,11 @@ decode_xform (char *file_name, void *data) proper. */ return file_name; - case xform_link: + case XFORM_LINK: file_name = safer_name_suffix (file_name, true, absolute_names_option); break; - case xform_regfile: + case XFORM_REGFILE: file_name = safer_name_suffix (file_name, false, absolute_names_option); break; } @@ -505,9 +505,9 @@ decode_xform (char *file_name, void *data) } bool -transform_member_name (char **pinput, xform_type type) +transform_member_name (char **pinput, int type) { - return transform_name_fp (pinput, decode_xform, &type); + return transform_name_fp (pinput, type, decode_xform, &type); } #define ISOCTAL(c) ((c)>='0'&&(c)<='7') @@ -628,7 +628,16 @@ decode_header (union block *header, struct tar_stat_info *stat_info, stat_info->is_dumpdir = true; } - transform_member_name (&stat_info->file_name, xform_regfile); + transform_member_name (&stat_info->file_name, XFORM_REGFILE); + switch (header->header.typeflag) + { + case SYMTYPE: + transform_member_name (&stat_info->link_name, XFORM_SYMLINK); + break; + + case LNKTYPE: + transform_member_name (&stat_info->link_name, XFORM_LINK); + } } /* Convert buffer at WHERE0 of size DIGS from external format to diff --git a/src/tar.c b/src/tar.c index 1b9ffce..ae0c739 100644 --- a/src/tar.c +++ b/src/tar.c @@ -287,7 +287,6 @@ enum NO_RECURSION_OPTION, NO_SAME_OWNER_OPTION, NO_SAME_PERMISSIONS_OPTION, - NO_TRANSFORM_SYMLINKS_OPTION, NO_UNQUOTE_OPTION, NO_WILDCARDS_MATCH_SLASH_OPTION, NO_WILDCARDS_OPTION, @@ -322,7 +321,6 @@ enum TOTALS_OPTION, TO_COMMAND_OPTION, TRANSFORM_OPTION, - TRANSFORM_SYMLINKS_OPTION, UNQUOTE_OPTION, USAGE_OPTION, USE_COMPRESS_PROGRAM_OPTION, @@ -689,10 +687,6 @@ static struct argp_option options[] = { {"transform", TRANSFORM_OPTION, N_("EXPRESSION"), 0, N_("use sed replace EXPRESSION to transform file names"), GRID+1 }, {"xform", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, - {"transform-symlinks", TRANSFORM_SYMLINKS_OPTION, NULL, 0, - N_("apply transformations to symlink targets"), GRID+1 }, - {"no-transform-symlinks", NO_TRANSFORM_SYMLINKS_OPTION, NULL, 0, - N_("cancel effect of the previous --transform-symlinks option"), GRID+1 }, #undef GRID #define GRID 120 @@ -1911,14 +1905,6 @@ parse_opt (int key, char *arg, struct argp_state *state) set_transform_expr (arg); break; - case TRANSFORM_SYMLINKS_OPTION: - transform_symlinks_option = true; - break; - - case NO_TRANSFORM_SYMLINKS_OPTION: - transform_symlinks_option = false; - break; - case USE_COMPRESS_PROGRAM_OPTION: set_use_compress_program_option (arg); break; diff --git a/src/transform.c b/src/transform.c index fc3eb48..2e0de31 100644 --- a/src/transform.c +++ b/src/transform.c @@ -61,6 +61,7 @@ struct transform { struct transform *next; enum transform_type transform_type; + int flags; unsigned match_number; regex_t regex; /* Compiled replacement expression */ @@ -69,6 +70,8 @@ struct transform }; + +int transform_flags = XFORM_ALL; static struct transform *transform_head, *transform_tail; static struct transform * @@ -131,6 +134,41 @@ add_backref_segment (struct transform *tf, size_t ref) segm->v.ref = ref; } +static int +parse_xform_flags (int *pflags, int c) +{ + switch (c) + { + case 'r': + *pflags |= XFORM_REGFILE; + break; + + case 'R': + *pflags &= ~XFORM_REGFILE; + break; + + case 'h': + *pflags |= XFORM_LINK; + break; + + case 'H': + *pflags &= ~XFORM_LINK; + break; + + case 's': + *pflags |= XFORM_SYMLINK; + break; + + case 'S': + *pflags &= ~XFORM_SYMLINK; + break; + + default: + return 1; + } + return 0; +} + static void add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl) { @@ -150,8 +188,26 @@ parse_transform_expr (const char *expr) struct transform *tf = new_transform (); if (expr[0] != 's') - USAGE_ERROR ((0, 0, _("Invalid transform expression"))); - + { + if (strncmp (expr, "flags=", 6) == 0) + { + transform_flags = 0; + for (expr += 6; *expr; expr++) + { + if (*expr == ';') + { + expr++; + break; + } + if (parse_xform_flags (&transform_flags, *expr)) + USAGE_ERROR ((0, 0, _("Unknown transform flag: %c"), + *expr)); + } + return expr; + } + USAGE_ERROR ((0, 0, _("Invalid transform expression"))); + } + delim = expr[1]; /* Scan regular expression */ @@ -172,6 +228,7 @@ parse_transform_expr (const char *expr) /* Check flags */ tf->transform_type = transform_first; + tf->flags = transform_flags; for (p = expr + j + 1; *p && *p != ';'; p++) switch (*p) { @@ -186,7 +243,7 @@ parse_transform_expr (const char *expr) case 'x': cflags |= REG_EXTENDED; break; - + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tf->match_number = strtoul (p, (char**) &p, 0); @@ -194,8 +251,9 @@ parse_transform_expr (const char *expr) break; default: - USAGE_ERROR ((0, 0, _("Unknown flag in transform expression: %c"), - *p)); + if (parse_xform_flags (&tf->flags, *p)) + USAGE_ERROR ((0, 0, _("Unknown flag in transform expression: %c"), + *p)); } if (*p == ';') @@ -520,10 +578,11 @@ _single_transform_name_to_obstack (struct transform *tf, char *input) } bool -_transform_name_to_obstack (char *input, char **output) +_transform_name_to_obstack (int flags, char *input, char **output) { struct transform *tf; - + bool alloced = false; + if (!stk_init) { obstack_init (&stk); @@ -532,18 +591,23 @@ _transform_name_to_obstack (char *input, char **output) for (tf = transform_head; tf; tf = tf->next) { - _single_transform_name_to_obstack (tf, input); - input = obstack_finish (&stk); + if (tf->flags & flags) + { + _single_transform_name_to_obstack (tf, input); + input = obstack_finish (&stk); + alloced = true; + } } *output = input; - return transform_head != NULL; + return alloced; } bool -transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat) +transform_name_fp (char **pinput, int flags, + char *(*fun)(char *, void *), void *dat) { char *str; - bool ret = _transform_name_to_obstack (*pinput, &str); + bool ret = _transform_name_to_obstack (flags, *pinput, &str); if (ret) { assign_string (pinput, fun ? fun (str, dat) : str); @@ -560,8 +624,8 @@ transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat) } bool -transform_name (char **pinput) +transform_name (char **pinput, int type) { - return transform_name_fp (pinput, NULL, NULL); + return transform_name_fp (pinput, type, NULL, NULL); }