NEWS | 49 ++++++++++++++++++-- THANKS | 2 +- doc/tar.texi | 128 +++++++++++++++++++++++++++++--------------------- lib/rtapelib.c | 16 ++++++- src/buffer.c | 10 ++-- src/common.h | 4 +- src/create.c | 45 +++++++++++------- src/extract.c | 65 +++++++++++++++++++------- src/list.c | 25 +++++----- src/misc.c | 98 +++++++++++++++++++++++++++++++++++++-- src/names.c | 52 +++++++++++++++++--- src/system.c | 20 ++++++++- src/tar.c | 40 +++++++++------- src/xheader.c | 4 +- tests/Makefile.am | 5 ++ tests/extrac07.at | 4 +- tests/genfile.c | 12 +++-- tests/label03.at | 89 +++++++++++++++++++++++++++++++++++ tests/label04.at | 53 +++++++++++++++++++++ tests/label05.at | 50 ++++++++++++++++++++ tests/remfiles01.at | 5 ++- tests/remfiles03.at | 45 ++++++++++++++++++ tests/sigpipe.at | 39 +++++++++++++++ tests/testsuite.at | 6 ++ 24 files changed, 713 insertions(+), 153 deletions(-) diff --git a/NEWS b/NEWS index 3254266..8b55ece 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,48 @@ -GNU tar NEWS - User visible changes. 2010-03-10 +GNU tar NEWS - User visible changes. 2010-03-20 Please send GNU tar bug reports to + +* Bugfixes. + +** Spurious error diagnostics on broken pipe. + +When receiving SIGPIPE, tar would exit with error status and +"write error" diagnostics. In particular, this occurred if +invoked as in the example below: + + tar tf archive.tar | head -n 1 + +** --remove-files + +Tar --remove-files failed to remove a directory which contained +symlinks to another files within that directory. + +** --test-label behavior + +In case of a mismatch, `tar --test-label LABEL' exits with code 1, +not 2 as it did in previous versions. + +The `--verbose' option used with `--test-label' provides additional +diagnostics. + +Several volume labels may be specified in a command line, e.g.: + + tar --test-label -f archive 'My volume' 'New volume' 'Test volume' + +In this case, tar exits with code 0 if any one of the arguments +matches the actual volume label. + +** --label used with --update + +The `--label' option can be used with `--update' to prevent accidental +update of an archive: + + tar -rf archive --label 'My volume' . + +This did not work in previous versions, in spite of what the docs said. + + version 1.23 - Sergey Poznyakoff, 2010-03-10 * Record size autodetection @@ -694,7 +735,7 @@ tar. * New message translations fi (Finnish), gl (Galician), hr (Croatian), hu (Hungarian), ms (Malaysian), nb (Norwegian), ro (Romanian), sk (Slovak), zh_CN (Chinese simplified), zh_TW (Chinese traditional). - The code 'no' for Norwegian (BokmÃ¥l) has been withdrawn; use 'nb' instead. + The code 'no' for Norwegian (Bokmål) has been withdrawn; use 'nb' instead. * Bug fixes. @@ -1019,7 +1060,7 @@ version 1.13 - Paul Eggert, 1999-07-08. but they have been removed to maintain compatibility with paxutils. Please try --use=bzip2 instead of --bzip2. -Version 1.12 - François Pinard, 1997-04. +Version 1.12 - François Pinard, 1997-04. Sensitive matters * Use shell globbing patterns for --label, instead of regular expressions. @@ -1062,7 +1103,7 @@ Various changes Many bugs are squashed, while others still run free. -Version 1.11.8 - François Pinard, 1995-06. +Version 1.11.8 - François Pinard, 1995-06. * Messages available in French, German, Portuguese and Swedish. * The distribution provides a rudimentary Texinfo manual. diff --git a/THANKS b/THANKS index 525981c..0364c50 100644 --- a/THANKS +++ b/THANKS @@ -133,7 +133,7 @@ David Steiner dsteiner@ispa.uni-osnabrueck.de David Taylor taylor@think.com Dean Gaudet dgaudet@watdragon.uwaterloo.ca Demizu Noritoshi nori-d@is.aist-nara.ac.jp -Denis Excoffier denis.excoffier@airbus.com +Denis Excoffier denis.excoffier@free.fr Denis Fortin fortin@acm.org Dennis Pixton dennis@math.binghamton.edu Dick Streefland dicks@tasking.nl diff --git a/doc/tar.texi b/doc/tar.texi index 0fcd04b..18ffea0 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -449,7 +449,7 @@ operations (@samp{create}, @samp{list}, and @samp{extract}) as well as two frequently used options (@samp{file} and @samp{verbose}). The other chapters do not refer to the tutorial frequently; however, if a section discusses something which is a complex variant of a basic concept, there -may be a cross reference to that basic concept. (The entire book, +may be a cross-reference to that basic concept. (The entire book, including the tutorial, assumes that the reader understands some basic concepts of using a Unix-type operating system; @pxref{Tutorial}.) @@ -3210,7 +3210,7 @@ successfully. This option is intended for use in shell scripts. Here is an example of what you can see using this option: @smallexample -$ tar --show-defaults +$ @kbd{tar --show-defaults} --format=gnu -f- -b20 --quoting-style=escape --rmt-command=/usr/libexec/rmt --rsh-command=/usr/bin/rsh @end smallexample @@ -3342,12 +3342,12 @@ To see transformed member names in verbose listings, use @opsummary{uncompress} @item --uncompress -(See @option{--compress}. @pxref{gzip}) +(See @option{--compress}, @pxref{gzip}) @opsummary{ungzip} @item --ungzip -(See @option{--gzip}. @pxref{gzip}) +(See @option{--gzip}, @pxref{gzip}) @opsummary{unlink-first} @item --unlink-first @@ -4551,7 +4551,7 @@ $ @kbd{tar --extract -vv --occurrence --file=collection.tar blues} @end smallexample @xref{Writing}, for more information on @option{--extract} and -@xref{Option Summary, --occurrence}, for the description of +see @ref{Option Summary, --occurrence}, for a description of @option{--occurrence} option. @node update @@ -4599,7 +4599,7 @@ To see the @option{--update} option at work, create a new file, @file{classical}, in your practice directory, and some extra text to the file @file{blues}, using any text editor. Then invoke @command{tar} with the @samp{update} operation and the @option{--verbose} (@option{-v}) -option specified, using the names of all the files in the practice +option specified, using the names of all the files in the @file{practice} directory as file name arguments: @smallexample @@ -4646,8 +4646,8 @@ To use @option{--concatenate}, give the first archive with @option{--file} option and name the rest of archives to be concatenated on the command line. The members, and their member names, will be copied verbatim from those archives to the first -one@footnote{This can cause multiple members to have the same name, for -information on how this affects reading the archive, @ref{multiple}.}. +one@footnote{This can cause multiple members to have the same name. For +information on how this affects reading the archive, see @ref{multiple}.}. The new, concatenated archive will be called by the same name as the one given with the @option{--file} option. As usual, if you omit @option{--file}, @command{tar} will use the value of the environment @@ -4811,7 +4811,7 @@ tar: funk not found in archive The spirit behind the @option{--compare} (@option{--diff}, @option{-d}) option is to check whether the archive represents the current state of files on disk, more than validating the integrity of -the archive media. For this latter goal, @xref{verify}. +the archive media. For this latter goal, see @ref{verify}. @node create options @section Options Used by @option{--create} @@ -4869,7 +4869,7 @@ either a textual date representation in almost arbitrary format with @samp{/} or @samp{.}. In the latter case, the modification time of that file will be used. -The following example will set the modification date to 00:00:00 UTC, +The following example will set the modification date to 00:00:00, January 1, 1970: @smallexample @@ -5536,9 +5536,9 @@ space, you can use @option{--starting-file=@var{name}} (@option{-K archive. This assumes, of course, that there is now free space, or that you are now extracting into a different file system. (You could also choose to suspend @command{tar}, remove unnecessary files from -the file system, and then restart the same @command{tar} operation. -In this case, @option{--starting-file} is not necessary. -@xref{Incremental Dumps}, @xref{interactive}, and @ref{exclude}.) +the file system, and then resume the same @command{tar} operation. +In this case, @option{--starting-file} is not necessary.) See also +@ref{interactive}, and @ref{exclude}. @node Same Order @unnumberedsubsubsec Same Order @@ -5692,16 +5692,20 @@ $ @kbd{tar -C sourcedir -cf - . | tar -C targetdir -xf -} The command also works using long option forms: @smallexample +@group $ @kbd{(cd sourcedir; tar --create --file=- . ) \ | (cd targetdir; tar --extract --file=-)} +@end group @end smallexample @noindent or @smallexample -$ @kbd{tar --directory sourcedir --create --file=- . ) \ +@group +$ @kbd{tar --directory sourcedir --create --file=- . \ | tar --directory targetdir --extract --file=-} +@end group @end smallexample @noindent @@ -8069,8 +8073,8 @@ $ @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 +lrwxrwxrwx root/root 0 2008-06-24 17:12 /usr/local/lib/libc.so.6 \ + -> libc-2.3.2.so @end smallexample Unlike @option{--strip-components}, @option{--transform} can be used @@ -8691,7 +8695,7 @@ $ @kbd{tar cfa archive.tar.lzma .} @end smallexample For a complete list of file name suffixes recognized by @GNUTAR{}, -@ref{auto-compress}. +see @ref{auto-compress}. Reading compressed archive is even simpler: you don't need to specify any additional options as @GNUTAR{} recognizes its format @@ -8709,7 +8713,7 @@ The format recognition algorithm is based on @dfn{signatures}, a special byte sequences in the beginning of file, that are specific for certain compression formats. If this approach fails, @command{tar} falls back to using archive name suffix to determine its format -(@xref{auto-compress}, for a list of recognized suffixes). +(@pxref{auto-compress}, for a list of recognized suffixes). The only case when you have to specify a decompression option while reading the archive is when reading from a pipe or from a tape drive @@ -9370,7 +9374,7 @@ free from many of @samp{v7}'s drawbacks. @cindex ustar archive format Archive format defined by @acronym{POSIX}.1-1988 specification is called @code{ustar}. Although it is more flexible than the V7 format, it -still has many restrictions (@xref{Formats,ustar}, for the detailed +still has many restrictions (@pxref{Formats,ustar}, for the detailed description of @code{ustar} format). Along with V7 format, @code{ustar} format is a good choice for archives intended to be read with other implementations of @command{tar}. @@ -9800,7 +9804,7 @@ The condensed file will contain both file map and file data, so no additional data will be needed to restore it. If the original file name was @file{@var{dir}/@var{name}}, then the condensed file will be named @file{@var{dir}/@/GNUSparseFile.@var{n}/@/@var{name}}, where -@var{n} is a decimal number@footnote{technically speaking, @var{n} is a +@var{n} is a decimal number@footnote{Technically speaking, @var{n} is a @dfn{process @acronym{ID}} of the @command{tar} process which created the archive (@pxref{PAX keywords}).}. @@ -10233,16 +10237,8 @@ Archive file is local even if it contains a colon. @opindex rsh-command @item --rsh-command=@var{command} -Use remote @var{command} instead of @command{rsh}. This option exists -so that people who use something other than the standard @command{rsh} -(e.g., a Kerberized @command{rsh}) can access a remote device. - -When this command is not used, the shell command found when -the @command{tar} program was installed is used instead. This is -the first found of @file{/usr/ucb/rsh}, @file{/usr/bin/remsh}, -@file{/usr/bin/rsh}, @file{/usr/bsd/rsh} or @file{/usr/bin/nsh}. -The installer may have overridden this by defining the environment -variable @env{RSH} @emph{at installation time}. +Use remote @var{command} instead of the compile-time default (if any). +The typical setting to use is @code{--rsh-command=/usr/bin/ssh}. @item -[0-7][lmh] Specify drive and density. @@ -11300,9 +11296,9 @@ archive which will be displayed when the archive is listed with @option{--multi-volume} (@pxref{Using Multiple Tapes}), then the volume label will have @samp{Volume @var{nnn}} appended to the name you give, where @var{nnn} is the number of the volume of the archive. -If you use the @option{--label=@var{volume-label}}) option when +If you use the @option{--label=@var{volume-label}} option when reading an archive, it checks to make sure the label on the tape -matches the one you give. @xref{label}. +matches the one you gave. @xref{label}. When @command{tar} writes an archive to tape, it creates a single tape file. If multiple archives are written to the same tape, one @@ -11351,15 +11347,16 @@ will usually see lots of spurious messages. @cindex Labeling an archive @cindex Labels on the archive media @cindex Labeling multi-volume archives -@UNREVISED @opindex label To avoid problems caused by misplaced paper labels on the archive -media, you can include a @dfn{label} entry---an archive member which -contains the name of the archive---in the archive itself. Use the +media, you can include a @dfn{label} entry --- an archive member which +contains the name of the archive --- in the archive itself. Use the @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) -option in conjunction with the @option{--create} operation to include -a label entry in the archive as it is being created. +option@footnote{Until version 1.10, that option was called +@option{--volume}, but is not available under that name anymore.} in +conjunction with the @option{--create} operation to include a label +entry in the archive as it is being created. @table @option @item --label=@var{archive-label} @@ -11398,7 +11395,7 @@ V--------- 0 0 0 1992-03-07 12:01 iamalabel--Volume Header-- However, @option{--list} option will cause listing entire contents of the archive, which may be undesirable (for example, if the archive is stored on a tape). You can request checking only the volume -by specifying @option{--test-label} option. This option reads only the +label by specifying @option{--test-label} option. This option reads only the first block of an archive, so it can be used with slow storage devices. For example: @@ -11409,16 +11406,35 @@ iamalabel @end group @end smallexample - If @option{--test-label} is used with a single command line -argument, @command{tar} compares the volume label with the -argument. It exits with code 0 if the two strings match, and with code -2 otherwise. In this case no output is displayed. For example: + If @option{--test-label} is used with one or more command line +arguments, @command{tar} compares the volume label with each +argument. It exits with code 0 if a match is found, and with code 1 +otherwise@footnote{Note that @GNUTAR{} versions up to 1.23 indicated +mismatch with an exit code 2 and printed a spurious diagnostics on +stderr.}. No output is displayed, unless you also used the +@option{--verbose} option. For example: @smallexample @group -$ @kbd{tar --test-label --file=iamanarchive 'iamalable'} +$ @kbd{tar --test-label --file=iamanarchive 'iamalabel'} @result{} 0 -$ @kbd{tar --test-label --file=iamanarchive 'iamalable' alabel} +$ @kbd{tar --test-label --file=iamanarchive 'alabel'} +@result{} 1 +@end group +@end smallexample + + When used with the @option{--verbose} option, @command{tar} +prints the actual volume label (if any), and a verbose diagnostics in +case of a mismatch: + +@smallexample +@group +$ @kbd{tar --test-label --verbose --file=iamanarchive 'iamalabel'} +iamalabel +@result{} 0 +$ @kbd{tar --test-label --verbose --file=iamanarchive 'alabel'} +iamalabel +tar: Archive label mismatch @result{} 1 @end group @end smallexample @@ -11458,9 +11474,6 @@ up. Since the volume numbering is automatically added in labels at creation time, it sounded logical to equally help the user taking care of it when the archive is being read. - The @option{--label} was once called @option{--volume}, but is not -available under that name anymore. - You can also use @option{--label} to get a common information on all tapes of a series. For having this information different in each series created through a single script used on a regular basis, just @@ -11474,13 +11487,19 @@ $ @kbd{tar --create --file=/dev/tape --multi-volume \ @end group @end smallexample - Also note that each label has its own date and time, which corresponds -to when @GNUTAR{} initially attempted to write it, + Some more notes about volume labels: + +@itemize @bullet +@item Each label has its own date and time, which corresponds +to the time when @GNUTAR{} initially attempted to write it, often soon after the operator launches @command{tar} or types the -carriage return telling that the next tape is ready. Comparing date -labels does give an idea of tape throughput only if the delays for -rewinding tapes and the operator switching them were negligible, which -is usually not the case. +carriage return telling that the next tape is ready. + +@item Comparing date labels to get an idea of tape throughput is +unreliable. It gives correct results only if the delays for rewinding +tapes and the operator switching them were negligible, which is +usually not the case. +@end itemize @node verify @section Verifying Data as It is Stored @@ -11907,7 +11926,8 @@ Right margin of the text output. Used for wrapping. This appendix contains an index of all @GNUTAR{} long command line options. The options are listed without the preceding double-dash. -For a cross-reference of short command line options, @ref{Short Option Summary}. +For a cross-reference of short command line options, see +@ref{Short Option Summary}. @printindex op diff --git a/lib/rtapelib.c b/lib/rtapelib.c index cb645db..435c17c 100644 --- a/lib/rtapelib.c +++ b/lib/rtapelib.c @@ -367,6 +367,15 @@ rmt_open__ (const char *file_name, int open_mode, int bias, char *remote_file; /* remote file name (often a device) */ char *remote_user; /* remote user name */ +#ifndef REMOTE_SHELL + /* We could use a more specific error message here (such as to recommend the + use of --rsh-command), but this one already has translations to languages + other than English. */ + if (!remote_shell) + error (EXIT_ON_EXEC_ERROR, 0, "%s: %s", + file_name, _("Cannot execute remote shell")); +#endif + /* Find an unused pair of file descriptors. */ for (remote_pipe_number = 0; @@ -459,6 +468,7 @@ rmt_open__ (const char *file_name, int open_mode, int bias, #ifdef REMOTE_SHELL remote_shell = REMOTE_SHELL; #else + /* "Can't happen" given the check at the beginning of this function. */ free (file_name_copy); errno = EIO; return -1; @@ -491,12 +501,14 @@ rmt_open__ (const char *file_name, int open_mode, int bias, /* Child. */ close (STDIN_FILENO); - dup (to_remote[remote_pipe_number][PREAD]); + if (dup (to_remote[remote_pipe_number][PREAD]) != STDIN_FILENO) + error (EXIT_ON_EXEC_ERROR, errno, _("Cannot dup")); close (to_remote[remote_pipe_number][PREAD]); close (to_remote[remote_pipe_number][PWRITE]); close (STDOUT_FILENO); - dup (from_remote[remote_pipe_number][PWRITE]); + if (dup (from_remote[remote_pipe_number][PWRITE]) != STDOUT_FILENO) + error (EXIT_ON_EXEC_ERROR, errno, _("Cannot dup")); close (from_remote[remote_pipe_number][PREAD]); close (from_remote[remote_pipe_number][PWRITE]); diff --git a/src/buffer.c b/src/buffer.c index 8147def..d3bdaf8 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1374,7 +1374,6 @@ static bool check_label_pattern (const char *label) { char *string; - bool result; if (fnmatch (volume_label_option, label, 0) == 0) return true; @@ -1385,10 +1384,11 @@ check_label_pattern (const char *label) string = drop_volume_label_suffix (label); if (string) { - result = fnmatch (string, volume_label_option, 0) == 0; + bool result = fnmatch (string, volume_label_option, 0) == 0; free (string); + return result; } - return result; + return false; } /* Check if the next block contains a volume label and if this matches @@ -1841,6 +1841,7 @@ open_archive (enum access_mode wanted_access) switch (wanted_access) { case ACCESS_READ: + case ACCESS_UPDATE: if (volume_label_option) match_volume_label (); break; @@ -1850,9 +1851,6 @@ open_archive (enum access_mode wanted_access) if (volume_label_option) write_volume_label (); break; - - default: - break; } set_volume_start_time (); } diff --git a/src/common.h b/src/common.h index d2de528..8e7e255 100644 --- a/src/common.h +++ b/src/common.h @@ -835,7 +835,9 @@ void checkpoint_run (bool do_write); /* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default in verbose mode */ -#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY) +#define WARN_VERBOSE_WARNINGS (WARN_ALONE_ZERO_BLOCK | \ + WARN_RENAME_DIRECTORY | \ + WARN_NEW_DIRECTORY) #define WARN_ALL (0xffffffff & ~WARN_VERBOSE_WARNINGS) void set_warning_option (const char *arg); diff --git a/src/create.c b/src/create.c index c69d340..355cedd 100644 --- a/src/create.c +++ b/src/create.c @@ -575,7 +575,12 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type) GNAME_TO_CHARS (tmpname, header->header.gname); free (tmpname); - strcpy (header->header.magic, OLDGNU_MAGIC); + /* OLDGNU_MAGIC is string of 7 chars and trailing \0 */ + strncpy (header->header.magic, + OLDGNU_MAGIC, sizeof(header->header.magic)); + strncpy (header->header.version, + OLDGNU_MAGIC + sizeof(header->header.magic), + sizeof(header->header.version)); header->header.typeflag = type; finish_header (st, header, -1); @@ -910,9 +915,13 @@ start_header (struct tar_stat_info *st) break; case OLDGNU_FORMAT: - case GNU_FORMAT: /*FIXME?*/ - /* Overwrite header->header.magic and header.version in one blow. */ - strcpy (header->header.magic, OLDGNU_MAGIC); + case GNU_FORMAT: + /* OLDGNU_MAGIC is string of 7 chars and trailing \0 */ + strncpy (header->header.magic, OLDGNU_MAGIC, + sizeof(header->header.magic)); + strncpy (header->header.version, + OLDGNU_MAGIC + sizeof(header->header.magic), + sizeof(header->header.version)); break; case POSIX_FORMAT: @@ -1554,6 +1563,19 @@ dump_file0 (struct tar_stat_info *st, const char *p, return; } + if (S_ISSOCK (st->stat.st_mode)) + { + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: socket ignored"), quotearg_colon (p))); + return; + } + else if (S_ISDOOR (st->stat.st_mode)) + { + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: door ignored"), quotearg_colon (p))); + return; + } + is_dir = S_ISDIR (st->stat.st_mode) != 0; if (!is_dir && dump_hard_link (st)) @@ -1666,7 +1688,8 @@ dump_file0 (struct tar_stat_info *st, const char *p, set_exit_status (TAREXIT_DIFFERS); } else if (atime_preserve_option == replace_atime_preserve - && set_file_atime (fd, p, restore_times) != 0) + && set_file_atime (fd, p, restore_times) != 0 + && errno != EROFS ) utime_error (p); } @@ -1725,18 +1748,6 @@ dump_file0 (struct tar_stat_info *st, const char *p, type = BLKTYPE; else if (S_ISFIFO (st->stat.st_mode)) type = FIFOTYPE; - else if (S_ISSOCK (st->stat.st_mode)) - { - WARNOPT (WARN_FILE_IGNORED, - (0, 0, _("%s: socket ignored"), quotearg_colon (p))); - return; - } - else if (S_ISDOOR (st->stat.st_mode)) - { - WARNOPT (WARN_FILE_IGNORED, - (0, 0, _("%s: door ignored"), quotearg_colon (p))); - return; - } else { unknown_file_error (p); diff --git a/src/extract.c b/src/extract.c index 32a883f..8ac39dd 100644 --- a/src/extract.c +++ b/src/extract.c @@ -131,6 +131,33 @@ extr_init (void) } } +static int +fstat_or_stat (int fd, const char *name, struct stat *st) +{ + if (fd != -1) + return fstat (fd, st); + else + return stat (name, st); +} + +static int +fchown_or_chown (int fd, const char *name, uid_t uid, uid_t gid) +{ + if (fd != -1) + return fchown (fd, uid, gid); + else + return chown (name, uid, gid); +} + +static int +fchmod_or_chmod (int fd, const char *name, mode_t mode) +{ + if (fd != -1) + return fchmod (fd, mode); + else + return chmod(name, mode); +} + /* If restoring permissions, restore the mode for FILE_NAME from information given in *STAT_INFO (where *CUR_INFO gives the current status if CUR_INFO is nonzero); otherwise invert the @@ -138,7 +165,7 @@ extr_init (void) PERMSTATUS specifies the status of the file's permissions. TYPEFLAG specifies the type of the file. */ static void -set_mode (char const *file_name, +set_mode (int fd, char const *file_name, struct stat const *stat_info, struct stat const *cur_info, mode_t invert_permissions, enum permstatus permstatus, @@ -178,7 +205,7 @@ set_mode (char const *file_name, struct stat st; if (! cur_info) { - if (stat (file_name, &st) != 0) + if (fstat_or_stat (fd, file_name, &st) != 0) { stat_error (file_name); return; @@ -188,7 +215,7 @@ set_mode (char const *file_name, mode = cur_info->st_mode ^ invert_permissions; } - failed = chmod (file_name, mode) != 0; + failed = fchmod_or_chmod (fd, file_name, mode) != 0; if (failed && errno == EPERM) { /* On Solaris, chmod may fail if we don't have PRIV_ALL. */ @@ -247,7 +274,7 @@ check_time (char const *file_name, struct timespec t) punt for the rest. Sigh! */ static void -set_stat (char const *file_name, +set_stat (int fd, char const *file_name, struct tar_stat_info const *st, struct stat const *cur_info, mode_t invert_permissions, enum permstatus permstatus, @@ -273,7 +300,7 @@ set_stat (char const *file_name, ts[0] = start_time; ts[1] = st->mtime; - if (utimens (file_name, ts) != 0) + if (gl_futimens (fd, file_name, ts) != 0) utime_error (file_name); else { @@ -306,7 +333,8 @@ set_stat (char const *file_name, } else { - chown_result = chown (file_name, st->stat.st_uid, st->stat.st_gid); + chown_result = fchown_or_chown (fd, file_name, st->stat.st_uid, + st->stat.st_gid); } if (chown_result == 0) @@ -324,7 +352,7 @@ set_stat (char const *file_name, } if (typeflag != SYMTYPE) - set_mode (file_name, &st->stat, cur_info, + set_mode (fd, file_name, &st->stat, cur_info, invert_permissions, permstatus, typeflag); } @@ -624,7 +652,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) sb.stat.st_gid = data->gid; sb.atime = data->atime; sb.mtime = data->mtime; - set_stat (data->file_name, &sb, cur_info, + set_stat (-1, data->file_name, &sb, cur_info, data->invert_permissions, data->permstatus, DIRTYPE); } @@ -675,7 +703,7 @@ extract_dir (char *file_name, int typeflag) || old_files_option == OVERWRITE_OLD_FILES)) { struct stat st; - if (stat (file_name, &st) == 0) + if (lstat (file_name, &st) == 0) { if (interdir_made) { @@ -854,6 +882,12 @@ extract_file (char *file_name, int typeflag) mv_end (); + if (!to_stdout_option && !to_command_option) + set_stat (fd, file_name, ¤t_stat_info, NULL, invert_permissions, + (old_files_option == OVERWRITE_OLD_FILES ? + UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS), + typeflag); + /* If writing to stdout, don't try to do anything to the filename; it doesn't exist, or we don't want to touch it anyway. */ @@ -866,11 +900,6 @@ extract_file (char *file_name, int typeflag) if (to_command_option) sys_wait_command (); - else - set_stat (file_name, ¤t_stat_info, NULL, invert_permissions, - (old_files_option == OVERWRITE_OLD_FILES ? - UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS), - typeflag); return status; } @@ -1023,7 +1052,7 @@ extract_symlink (char *file_name, int typeflag) break; if (status == 0) - set_stat (file_name, ¤t_stat_info, NULL, 0, 0, SYMTYPE); + set_stat (-1, file_name, ¤t_stat_info, NULL, 0, 0, SYMTYPE); else symlink_error (current_stat_info.link_name, file_name); return status; @@ -1060,7 +1089,7 @@ extract_node (char *file_name, int typeflag) if (status != 0) mknod_error (file_name); else - set_stat (file_name, ¤t_stat_info, NULL, invert_permissions, + set_stat (-1, file_name, ¤t_stat_info, NULL, invert_permissions, ARCHIVED_PERMSTATUS, typeflag); return status; } @@ -1081,7 +1110,7 @@ extract_fifo (char *file_name, int typeflag) break; if (status == 0) - set_stat (file_name, ¤t_stat_info, NULL, invert_permissions, + set_stat (-1, file_name, ¤t_stat_info, NULL, invert_permissions, ARCHIVED_PERMSTATUS, typeflag); else mkfifo_error (file_name); @@ -1335,7 +1364,7 @@ apply_delayed_links (void) struct tar_stat_info st1; st1.stat.st_uid = ds->uid; st1.stat.st_gid = ds->gid; - set_stat (source, &st1, NULL, 0, 0, SYMTYPE); + set_stat (-1, source, &st1, NULL, 0, 0, SYMTYPE); valid_source = source; } } diff --git a/src/list.c b/src/list.c index 716c0b4..0474fb1 100644 --- a/src/list.c +++ b/src/list.c @@ -1412,22 +1412,23 @@ test_archive_label () if (read_header (¤t_header, ¤t_stat_info, read_header_auto) == HEADER_SUCCESS) { - char *s = NULL; - decode_header (current_header, ¤t_stat_info, ¤t_format, 0); if (current_header->header.typeflag == GNUTYPE_VOLHDR) assign_string (&volume_label, current_header->header.name); - - if (volume_label - && (name_match (volume_label) - || (multi_volume_option - && (s = drop_volume_label_suffix (volume_label)) - && name_match (s)))) - if (verbose_option) - print_volume_label (); - free (s); + + if (volume_label) + { + if (verbose_option) + print_volume_label (); + if (!name_match (volume_label) && multi_volume_option) + { + char *s = drop_volume_label_suffix (volume_label); + name_match (s); + free (s); + } + } } close_archive (); - names_notfound (); + label_notfound (); } diff --git a/src/misc.c b/src/misc.c index f81111f..ff7e4b2 100644 --- a/src/misc.c +++ b/src/misc.c @@ -25,7 +25,6 @@ #include #include #include -#include #if HAVE_STROPTS_H # include @@ -34,6 +33,10 @@ # include #endif +#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +#endif + /* Handling strings. */ @@ -230,10 +233,99 @@ zap_slashes (char *name) return name; } +/* Normalize NAME by resolving any relative references and + removing trailing slashes. Destructive version: modifies its argument. */ +int +normalize_filename_x (char *name) +{ + char *p, *q; + + p = name; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && ISSLASH (*p)) + p++; + + /* Remove /./, resolve /../ and compress sequences of slashes */ + for (q = p; *q; ) + { + if (ISSLASH (*q)) + { + *p++ = *q++; + while (ISSLASH (*q)) + q++; + continue; + } + else if (p == name) + { + if (*q == '.') + { + if (ISSLASH (q[1])) + { + q += 2; + continue; + } + if (q[1] == '.' && ISSLASH (q[2])) + return 1; + } + } + else + { + if (*q == '.' && ISSLASH (p[-1])) + { + if (ISSLASH (q[1])) + { + q += 2; + while (ISSLASH (*q)) + q++; + continue; + } + else if (q[1] == '.' && ISSLASH (q[2])) + { + do + { + --p; + } + while (p > name && !ISSLASH (p[-1])); + q += 3; + continue; + } + } + } + *p++ = *q++; + } + + /* Remove trailing slashes */ + while (p - 1 > name && ISSLASH (p[-1])) + p--; + + *p = 0; + return 0; +} + +/* Normalize NAME by resolving any relative references, removing trailing + slashes, and converting it to absolute file name. Return the normalized + name, or NULL in case of error. */ + char * normalize_filename (const char *name) { - return zap_slashes (canonicalize_filename_mode (name, CAN_MISSING)); + char *copy; + + if (name[0] != '/') + { + copy = xgetcwd (); + copy = xrealloc (copy, strlen (copy) + strlen (name) + 2); + + strcat (copy, "/"); + strcat (copy, name); + } + else + copy = xstrdup (name); + if (normalize_filename_x (copy)) + { + free (copy); + return NULL; + } + return xrealloc (copy, strlen (copy) + 1); } @@ -870,5 +962,3 @@ namebuf_name (namebuf_t buf, const char *name) return buf->buffer; } - - diff --git a/src/names.c b/src/names.c index 1146020..2beaf3e 100644 --- a/src/names.c +++ b/src/names.c @@ -589,7 +589,7 @@ all_names_found (struct tar_stat_info *p) return true; } -static void +static int regex_usage_warning (const char *name) { static int warned_once = 0; @@ -603,6 +603,7 @@ regex_usage_warning (const char *name) _("Use --wildcards to enable pattern matching," " or --no-wildcards to suppress this warning"))); } + return warned_once; } /* Print the names of things in the namelist that were not matched. */ @@ -615,12 +616,11 @@ names_notfound (void) if (!WASFOUND (cursor) && cursor->name[0]) { regex_usage_warning (cursor->name); - if (cursor->found_count == 0) - ERROR ((0, 0, _("%s: Not found in archive"), - quotearg_colon (cursor->name))); - else - ERROR ((0, 0, _("%s: Required occurrence not found in archive"), - quotearg_colon (cursor->name))); + ERROR ((0, 0, + (cursor->found_count == 0) ? + _("%s: Not found in archive") : + _("%s: Required occurrence not found in archive"), + quotearg_colon (cursor->name))); } /* Don't bother freeing the name list; we're about to exit. */ @@ -639,6 +639,42 @@ names_notfound (void) } } } + +void +label_notfound (void) +{ + struct name const *cursor; + + if (!namelist) + return; + + for (cursor = namelist; cursor; cursor = cursor->next) + if (WASFOUND (cursor)) + return; + + if (verbose_option) + error (0, 0, _("Archive label mismatch")); + set_exit_status (TAREXIT_DIFFERS); + + for (cursor = namelist; cursor; cursor = cursor->next) + { + if (regex_usage_warning (cursor->name)) + break; + } + + /* Don't bother freeing the name list; we're about to exit. */ + namelist = NULL; + nametail = NULL; + + if (same_order_option) + { + const char *name; + + while ((name = name_next (1)) != NULL + && regex_usage_warning (name) == 0) + ; + } +} /* Sorting name lists. */ @@ -871,7 +907,7 @@ void collect_and_sort_names (void) { struct name *name; - struct name *next_name, *prev_name; + struct name *next_name, *prev_name = NULL; int num_names; struct stat statbuf; Hash_table *nametab; diff --git a/src/system.c b/src/system.c index d646822..0adbb92 100644 --- a/src/system.c +++ b/src/system.c @@ -230,7 +230,25 @@ int sys_truncate (int fd) { off_t pos = lseek (fd, (off_t) 0, SEEK_CUR); - return pos < 0 ? -1 : ftruncate (fd, pos); + + if (pos < 0) + return -1; + + if (ftruncate (fd, pos) && errno == EPERM) { + /* + * ftruncate may fail to grow the size of a file with some OS and + * filesystem combinations. Linux and vfat/fat is one example. + * If this is the case do a write to grow the file to the desired length. + */ + struct stat st; + + if (fstat (fd, &st) || + st.st_size >= pos || + lseek (fd, pos - 1, SEEK_SET) == (off_t)-1 || + write (fd, "\0", 1) != 1) + return -1; + } + return 0; } /* Return nonzero if NAME is the name of a regular file, or if the file diff --git a/src/tar.c b/src/tar.c index da12419..380da10 100644 --- a/src/tar.c +++ b/src/tar.c @@ -1254,7 +1254,7 @@ tar_help_filter (int key, const char *text, void *input) { struct obstack stk; char *s; - + switch (key) { default: @@ -1286,19 +1286,23 @@ tar_help_filter (int key, const char *text, void *input) break; case ARGP_KEY_HELP_EXTRA: - obstack_init (&stk); - s = _("Valid arguments for the --quoting-style option are:"); - obstack_grow (&stk, s, strlen (s)); - obstack_grow (&stk, "\n\n", 2); - tar_list_quoting_styles (&stk, " "); - s = _("\n*This* tar defaults to:\n"); - obstack_grow (&stk, s, strlen (s)); - s = format_default_settings (); - obstack_grow (&stk, s, strlen (s)); - obstack_1grow (&stk, '\n'); - obstack_1grow (&stk, 0); - s = xstrdup (obstack_finish (&stk)); - obstack_free (&stk, NULL); + { + const char *tstr; + + obstack_init (&stk); + tstr = _("Valid arguments for the --quoting-style option are:"); + obstack_grow (&stk, tstr, strlen (tstr)); + obstack_grow (&stk, "\n\n", 2); + tar_list_quoting_styles (&stk, " "); + tstr = _("\n*This* tar defaults to:\n"); + obstack_grow (&stk, tstr, strlen (tstr)); + s = format_default_settings (); + obstack_grow (&stk, s, strlen (s)); + obstack_1grow (&stk, '\n'); + obstack_1grow (&stk, 0); + s = xstrdup (obstack_finish (&stk)); + obstack_free (&stk, NULL); + } } return s; } @@ -1463,7 +1467,11 @@ parse_opt (int key, char *arg, struct argp_state *state) ignore_zeros_option = true; break; - + + case 'y': + WARN ((0, 0, _("Warning: option '%c' is deprecated!" + " Next time use -j instead."), key)); + /* Fall through to using bzip2. */ case 'j': set_use_compress_program_option (BZIP2_PROGRAM); break; @@ -2566,8 +2574,6 @@ main (int argc, char **argv) obstack_init (&argv_stk); - /* Ensure default behavior for some signals */ - signal (SIGPIPE, SIG_IGN); /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL); diff --git a/src/xheader.c b/src/xheader.c index b5c9869..04eca6f 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -261,7 +261,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) char *dir = NULL; char *base = NULL; char pidbuf[UINTMAX_STRSIZE_BOUND]; - char const *pptr; + char const *pptr = NULL; char nbuf[UINTMAX_STRSIZE_BOUND]; char const *nptr = NULL; @@ -1330,7 +1330,7 @@ sparse_map_decoder (struct tar_stat_info *st, { uintmax_t u; char *delim; - struct sp_array e; + struct sp_array e = {0, 0}; if (!ISDIGIT (*arg)) { diff --git a/tests/Makefile.am b/tests/Makefile.am index e9b753c..31811b0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -89,6 +89,9 @@ TESTSUITE_AT = \ ignfail.at\ label01.at\ label02.at\ + label03.at\ + label04.at\ + label05.at\ link01.at\ link02.at\ link03.at\ @@ -118,11 +121,13 @@ TESTSUITE_AT = \ rename05.at\ remfiles01.at\ remfiles02.at\ + remfiles03.at\ same-order01.at\ same-order02.at\ shortfile.at\ shortupd.at\ shortrec.at\ + sigpipe.at\ sparse01.at\ sparse02.at\ sparse03.at\ diff --git a/tests/extrac07.at b/tests/extrac07.at index 1c45e97..bd301ab 100644 --- a/tests/extrac07.at +++ b/tests/extrac07.at @@ -52,7 +52,9 @@ Extract dir/ dir/foo ], -[],[],[ustar]) # Testing one format is enough +[],[],[],[ustar]) # Testing one format is enough + +chmod +w ustar/out/dir AT_CLEANUP diff --git a/tests/genfile.c b/tests/genfile.c index 7ebeddf..4e915a4 100644 --- a/tests/genfile.c +++ b/tests/genfile.c @@ -488,7 +488,8 @@ mkhole (int fd, off_t displ) { if (lseek (fd, displ, SEEK_CUR) == -1) error (EXIT_FAILURE, errno, "lseek"); - ftruncate (fd, lseek (fd, 0, SEEK_CUR)); + if (ftruncate (fd, lseek (fd, 0, SEEK_CUR))) + error (EXIT_FAILURE, errno, "ftruncate"); } static void @@ -686,13 +687,15 @@ exec_checkpoint (struct action *p) error (0, errno, _("cannot open `%s'"), p->name); break; } - ftruncate (fd, p->size); + if (ftruncate (fd, p->size)) + error (0, errno, _("cannot truncate `%s'"), p->name); close (fd); } break; case OPT_EXEC: - system (p->name); + if (system (p->name) == -1) + error (0, errno, _("cannot execute `%s'"), p->name); break; case OPT_UNLINK: @@ -762,7 +765,8 @@ exec_command (void) signal (SIGCHLD, SIG_DFL); #endif - pipe (fd); + if (pipe (fd)) + error (EXIT_FAILURE, errno, "pipe"); pid = fork (); if (pid == -1) diff --git a/tests/label03.at b/tests/label03.at new file mode 100644 index 0000000..71a422f --- /dev/null +++ b/tests/label03.at @@ -0,0 +1,89 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Description: Test the functionality of the --test-label option. +# In versions up to 1.23 it did not match the documentation. This +# test case follows the examples from "9.7 Including a Label in the Archive". +# References: <15929_1268069389_4B95340D_15929_35_1_D621E31C29598A43AF7B4BBD30CCDDFD0838294A@fr0-mailmb04.res.airbus.corp> +# + +AT_SETUP([test-label option]) +AT_KEYWORDS([label label03 test-label]) + +AT_TAR_CHECK([ +exec <&- +genfile --file file +tar -c --label='iamalabel' --file iamanarchive file +tar -c --file unlabeled.tar file +decho "# Display label" +tar --test-label --file=iamanarchive; echo $? +decho "# Display label: unlabeled" +tar --test-label --file=unlabeled.tar; echo $? +decho "# Test label: success" +tar --test-label --file=iamanarchive 'iamalabel'; echo $? +decho "# Test label: failure" +tar --test-label --file=iamanarchive 'amalabel'; echo $? +decho "# Test label: unlabeled" +tar --test-label --file=unlabeled.tar 'amalabel'; echo $? +decho "# Test label, verbose: success" +tar --test-label --verbose --file=iamanarchive 'iamalabel'; echo $? +decho "# Test label, verbose: failure" +tar --test-label --verbose --file=iamanarchive 'amalabel'; echo $? +decho "# Test label: multiple arguments" +tar --test-label --file=iamanarchive a iamalabel b; echo $? +decho "# Test label: wildcards" +tar --test-label --file=iamanarchive --wildcards '*label'; echo $? +], +[0], +[# Display label +iamalabel +0 +# Display label: unlabeled +0 +# Test label: success +0 +# Test label: failure +1 +# Test label: unlabeled +1 +# Test label, verbose: success +iamalabel +0 +# Test label, verbose: failure +iamalabel +1 +# Test label: multiple arguments +0 +# Test label: wildcards +0 +], +[# Display label +# Display label: unlabeled +# Test label: success +# Test label: failure +# Test label: unlabeled +# Test label, verbose: success +# Test label, verbose: failure +tar: Archive label mismatch +# Test label: multiple arguments +# Test label: wildcards +],[],[],[gnu,oldgnu,posix]) + +AT_CLEANUP + + diff --git a/tests/label04.at b/tests/label04.at new file mode 100644 index 0000000..e551502 --- /dev/null +++ b/tests/label04.at @@ -0,0 +1,53 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Description: Test the functionality of the --label option used in +# conjunction with an operation, other than create. It was broken +# in versions up to 1.23. +# References: <15929_1268069389_4B95340D_15929_35_1_D621E31C29598A43AF7B4BBD30CCDDFD0838294A@fr0-mailmb04.res.airbus.corp> +# + +AT_SETUP([label with non-create option]) +AT_KEYWORDS([label label04]) + +AT_TAR_CHECK([ +exec <&- +genfile --file file +decho "# Create volume" +tar -c -f archive --label='New volume' file +decho "# Update: wrong label" +tar -rf archive --label='My volume' file; echo $? +decho "# Update: right label" +tar -rf archive --label='New volume' file +], +[0], +[# Create volume +# Update: wrong label +2 +# Update: right label +], +[# Create volume +# Update: wrong label +tar: Volume `New volume' does not match `My volume' +tar: Error is not recoverable: exiting now +# Update: right label +],[],[],[gnu,oldgnu,posix]) + +AT_CLEANUP + + diff --git a/tests/label05.at b/tests/label05.at new file mode 100644 index 0000000..5f8cffc --- /dev/null +++ b/tests/label05.at @@ -0,0 +1,50 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Description: See label04. This testcase uses an unlabeled archive +# volume. + +AT_SETUP([label with non-create option]) +AT_KEYWORDS([label label05]) + +AT_TAR_CHECK([ +exec <&- +genfile --file file +decho "# Create volume" +tar -c -f archive file +decho "# Update: wrong label" +tar -rf archive --label='My volume' file; echo $? +decho "# Update: right label" +tar -rf archive file +], +[0], +[# Create volume +# Update: wrong label +2 +# Update: right label +], +[# Create volume +# Update: wrong label +tar: Archive not labeled to match `My volume' +tar: Error is not recoverable: exiting now +# Update: right label +],[],[],[gnu,oldgnu,posix]) + +AT_CLEANUP + + diff --git a/tests/remfiles01.at b/tests/remfiles01.at index 940fd95..86b5c03 100644 --- a/tests/remfiles01.at +++ b/tests/remfiles01.at @@ -30,6 +30,7 @@ AT_KEYWORDS([create remove-files remfiles01 gzip]) unset TAR_OPTIONS AT_CHECK([ +AT_UNPRIVILEGED_PREREQ AT_GZIP_PREREQ AT_SORT_PREREQ @@ -51,7 +52,9 @@ EC=$? sed -n '/(child)/p' err >&2 rm err find . | sort -exit $EC +# Gzip exit code is propagated to the shell. Usually it is +# 141. We convert all non-zero exits to 2 to make it predictable. +test $EC && exit 2 ], [2], [. diff --git a/tests/remfiles03.at b/tests/remfiles03.at new file mode 100644 index 0000000..02104e9 --- /dev/null +++ b/tests/remfiles03.at @@ -0,0 +1,45 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# Description: Called with --remove-files, tar 1.23 failed +# to remove a directory if it contained symlinks to another files +# within that directory. +# Reported-by: Alexander Kozlov +# References: http://lists.gnu.org/archive/html/bug-tar/2010-03/msg00028.html +# + +AT_SETUP([remove-files with symbolic links]) +AT_KEYWORDS([create remove-files remfiles03]) + +AT_CHECK([ +mkdir a +mkdir a/b +ln -s b a/c || AT_SKIP_TEST +tar --remove-files -cf a.tar a +genfile --stat a +], +[0], +[], +[genfile: stat(a) failed: No such file or directory +]) + +AT_CLEANUP + + diff --git a/tests/sigpipe.at b/tests/sigpipe.at new file mode 100644 index 0000000..9edca77 --- /dev/null +++ b/tests/sigpipe.at @@ -0,0 +1,39 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +AT_SETUP([sigpipe handling]) +AT_KEYWORDS([sigpipe]) + +# Description: Tar 1.23 ignored sigpipe which lead to spurious "write +# error" diagnostics when piping output to another programs. +# Reported-by: "Dmitry V. Levin" +# References: http://lists.gnu.org/archive/html/bug-tar/2010-03/msg00039.html +# <20100319184141.GC30047@wo.int.altlinux.org> + +AT_CHECK([ +genfile --length 2048 --file first +genfile --length 2048 --file second +genfile --length 2049 --file third + +tar cf archive first second third + +tar tf archive | : +], +[0]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index f581071..9205d52 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -148,6 +148,9 @@ m4_include([extrac08.at]) m4_include([label01.at]) m4_include([label02.at]) +m4_include([label03.at]) +m4_include([label04.at]) +m4_include([label05.at]) m4_include([backup01.at]) @@ -226,6 +229,9 @@ m4_include([grow.at]) m4_include([remfiles01.at]) m4_include([remfiles02.at]) +m4_include([remfiles03.at]) + +m4_include([sigpipe.at]) m4_include([star/gtarfail.at]) m4_include([star/gtarfail2.at])