99 Commits

Author SHA1 Message Date
Sergey Poznyakoff
aea443b9e8 Version 1.26
* NEWS, configure.ac: Update.
* po/POTFILES.in: Remove paxexit.c (see bb971a1e).
2011-03-12 12:20:07 +02:00
Paul Eggert
881e5626c5 --atime-preserve=replace: fix correctness and performance bugs
reported by Eric Blake in
<http://lists.gnu.org/archive/html/bug-tar/2011-03/msg00000.html>.
* src/compare.c (diff_file): Do not restore atime of size-zero files.
* src/create.c (dump_file0): Likewise.  Also, do not restore atime
when fd is zero, because that indicates a file we haven't opened.
2011-03-07 15:40:56 -08:00
Paul Eggert
67ae04ba31 * doc/tar.texi: Adjust example commands and output for accuracy.
The original problem was reported by Michael Witten in
<http://lists.gnu.org/archive/html/bug-tar/2011-02/msg00033.html>.
2011-02-22 16:41:10 -08:00
Paul Eggert
2807513841 tar: if (p) free (p); -> free (p);
There is no longer (since SunOS 4) any need to guard against
free (NULL), so replace each "if (p) free (p);" with "free (p);".
From Jim Meyering in
<http://lists.gnu.org/archive/html/bug-tar/2011-01/msg00026.html>.
* src/incremen.c (scan_directory, read_directory_file): As above.
(try_purge_directory): Likewise.
* src/list.c (read_header): Likewise.
* src/misc.c (assign_string): Likewise.
2011-02-16 13:47:28 -08:00
Sergey Poznyakoff
bb0af96c54 Correctly store long sparse file names in PAX archives.
* src/sparse.c (pax_dump_header_1): Make sure the created header name is
shorter than NAME_FIELD_SIZE bytes.
* tests/sparse04.at: New testcase.
* tests/Makefile.am (TESTSUITE_AT): Add sparse04.at.
* tests/testsuite.at: Include sparse04.at.
* NEWS: Update.
2010-12-14 15:27:55 +02:00
Paul Eggert
ec586b37e0 tests: make the truncate test smaller and less buggy (tiny change)
Reported by Solar Designer in
<http://lists.gnu.org/archive/html/bug-tar/2010-12/msg00003.html>.
* tests/truncate.at: Use a smaller test case, and make its
race condition less likely.
2010-12-06 14:27:29 -08:00
Paul Eggert
a7fc5ecead tests: skip SIGPIPE-dependent tests in environments ignoring SIGPIPE
Problem reported by Sven Joachim in
<http://lists.gnu.org/archive/html/bug-tar/2010-11/msg00043.html>.
* tests/remfiles01.at: Use AT_SIGPIPE_PREREQ.
* tests/sigpipe.at: Likewise.
* tests/testsuite.at (AT_SIGPIPE_PREREQ): New macro.
2010-11-26 19:36:05 -08:00
Paul Eggert
649b747913 tar: work around NetBSD and Tru64 symlink incompatibility with POSIX
Problem reported by Bruno Haible in
<http://lists.gnu.org/archive/html/bug-gnulib/2010-11/msg00306.html>.
* src/extract.c (maybe_recoverable):  Also treat EFTYPE (if defined)
and ENOTSUP like ELOOP.
2010-11-24 23:08:07 -08:00
Paul Eggert
bb971a1e8a tar: adjust to paxutils change: paxexit.c -> paxexit-status.c
* lib/Makefile.am (libtar_a_SOURCES): paxexit.c renamed to
paxexit-status.c.
2010-11-23 21:41:50 -08:00
Paul Eggert
50a57a0147 tar: remove unused function dir_removed_diag
* src/common.h (dir_removed_diag): Remove unused decl.
* src/misc.c (dir_removed_diag): Remove unused function.
2010-11-23 17:56:58 -08:00
Paul Eggert
1584b72ff2 tar: work around FreeBSD symlink incompatibility with POSIX
* src/extract.c (maybe_recoverable): Treat EMLINK like ELOOP, for
FreeBSD.  Problem reported by Christian Weisgerber in
<http://lists.gnu.org/archive/html/bug-tar/2010-11/msg00080.html>.
2010-11-23 12:58:09 -08:00
Paul Eggert
065cf0958c * src/names.c: tar: fix bug with --one-file-system --listed-incremental
Problem (and idea for fix) reported by Martin Weigel
<http://lists.gnu.org/archive/html/bug-tar/2010-11/msg00071.html>.
* src/common.h (is_individual_file): Remove decl.
* src/create.c (dump_file0): Replace "is_individual_file (p)"
with "top_level".
* src/incremen.c (procdir): Replace "!is_individual_file
(name_buffer)" with "st->parent".  Fix bug with --one-file-system
and --listed-incremental.
* src/names.c (individual_file_table, register_individual_file):
(is_individual_file): Remove.  All uses removed.
2010-11-22 22:51:29 -08:00
Paul Eggert
2a55b4b037 tests: new test listed04 for --one-file-system --listed-incremental
* tests/Makefile.am (TESTSUITE_AT): Add listed04.at.
* tests/listed04.at: New file.
* tests/testsuite.at: Include it.
2010-11-22 17:59:21 -08:00
Paul Eggert
27225be1a3 scripts: fix option parsing
Problem reported by Dennis Wydra in
<http://lists.gnu.org/archive/html/bug-tar/2010-11/msg00082.html>.
* scripts/backup.in: Accept "-l LEVEL".  Be more systematic about
backslashes inside ``; it shouldn't matter for modern shells but
it might matter for older ones.
* scripts/restore.in: Likewise.
* scripts/backup.in: Adjust implementation of -t/--time to match
the new implementation of -l/--level.
2010-11-22 15:18:41 -08:00
Sergey Poznyakoff
73d0d1a0f8 Issue a warning if the archive being compared contais transformed file names.
* src/common.h (transform_program_p): New proto.
* src/transform.c (transform_program_p): New function.
* src/compare.c (verify_volume): Warn if the archive contains
transformed file names.
2010-11-15 11:22:27 +02:00
Sergey Poznyakoff
ff2bc5c0a1 Minor change.
* doc/tar.texi: Reword the description of decompress-program.
2010-11-15 11:21:45 +02:00
Paul Eggert
24214ca5d5 tar: fix --verify option, which broke in 1.24
* NEWS: Document this.
* src/compare.c (verify_volume): Decode the header before invoking
diff_archive, as diff_archive no longer does this as of the
2010-06-28 commit.  Also, don't try to invoke diff_archive on a
zero block.
* tests/Makefile.am (TESTSUITE_AT): Add verify.at.
* tests/testsuite.at: Include verify.at.
* tests/verify.at: New file.
2010-11-15 00:08:27 -08:00
Paul Eggert
777042e024 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/tar 2010-11-08 11:14:28 -08:00
Jim Meyering
1801399830 tests: avoid spurious failure when VERSION_CONTROL envvar is set
* tests/backup01.at: Unset VERSION_CONTROL.  Otherwise,
when set to e.g., 'always', it would cause this test to fail.
2010-11-08 11:13:39 -08:00
Sergey Poznyakoff
ecd700fbfb Version 1.25
* configure.ac: Version 1.25
* NEWS: Describe the changes.
2010-11-07 16:04:48 +02:00
Sergey Poznyakoff
f1fed3996a Run alternative decompression programs if the principal one is not available.
Some compression programs are able to handle various compression formats
(e.g. `gzip' can decompress files created by `compress', `xz' is able
to handle lzma, etc.)  Tar tries to use such programs for decompression
if the principal decompressor cannot be started.

* src/buffer.c (compress_type): Swap ct_none and ct_tar.
(archive_compression_type): New static variable.
(zip_magic): Remove program and option fields.
(zip_program): New structure and static.
(compress_program): Remove macro.
(find_zip_program): New static function.
(first_decompress_program,next_decompress_program): New functions.
(open_compressed_archive): Set archive_compression_type instead of
use_compress_program_option.
* src/common.h (first_decompress_program)
(next_decompress_program): New functions.
(WARN_DECOMPRESS_PROGRAM): New flag.
(WARN_VERBOSE_WARNINGS): Include WARN_DECOMPRESS_PROGRAM.
* src/warning.c (warning_args): Add "decompress-program".
(warning_types): Add WARN_DECOMPRESS_PROGRAM.
* src/system.c (run_decompress_program): New function.
(sys_child_open_for_uncompress): Use run_decompress_program
instead of calling execlp directly.
2010-11-05 10:09:51 +02:00
Paul Eggert
b32edff5aa tests: fix some issues with signals, timestamps, "test" typo
* tests/extrac17.at: Add --warning=no-timestamp, to avoid
bogus warning due to NFS clock skew.
* tests/remfiles01.at: Discard diagnostics that some shells
generate about broken pipes.
* tests/sigpipe.at: Likewise.
* tests/remfiles01.at: Fix typo: "test $EC" was written where
"test $EC -ne 0" was intended.
2010-11-02 01:05:16 -07:00
Sergey Poznyakoff
3913675640 Fix extraction of device nodes.
* src/extract.c (extract_node): Do not mask out node type.
The bug was introduced in commit ea964cce.
2010-11-01 15:05:25 +02:00
Paul Eggert
b8feb2b142 tar: don't cross struct member boundaries with OLDGNU_MAGIC
* src/create.c (write_gnu_long_link, start_header): Access
header->buffer + offsetof (struct posix_header, magic), instead of
header->header.magic, when reading or writing the OLDGNU_MAGIC
pattern.  The code violates the C standard without this change,
and GCC warns about this if fortify checking is enabled.  It's not
a bug on traditional (i.e., non-debugging) platforms, but it does
violate the C standard so it should be fixed.  Problem originally
reported by John Emil Karlson in
<http://lists.gnu.org/archive/html/bug-tar/2010-04/msg00023.html>.
* src/list.c (decode_header): Likewise.
2010-10-27 22:31:16 -07:00
Paul Eggert
3fe59ed5ef tests: port to sh variants that squirrel away file descriptors
OpenBSD /bin/sh, and some other sh variants, squirrel away file
descriptors before closing them.  For example, for "cat 3<&-" they
first dup file descriptor 3 to a fd that is 10 or greater, then
close 3 (because if "cat" had been a builtin command like ":" then
they would have wanted to avoid the fork and restore the fd after
":" finished); and they treat ordinary (forking) commands the same
as builtin commands.  This approach fails after "ulimit -n 10".
Work around this deficiency by closing the file descriptors before
invoking ulimit.  Problem reported by Christian Weisgerber in
<http://lists.gnu.org/archive/html/bug-tar/2010-10/msg00041.html>;
solution suggested by Jilles Tjoelker in
<http://article.gmane.org/gmane.comp.shells.dash/415>.

* tests/extrac11.at (scarce file descriptors): Close file
descriptors before invoking ulimit -n.
2010-10-27 20:25:56 -07:00
Sergey Poznyakoff
5af29cb944 Transform file names when updating and appendig to archives.
This complements 28e91b48.

* src/common.h (transform_stat_info): New prototype.
* src/list.c (transform_stat_info): Remove static qualifier.
* src/update.c (update_archive): Call transform_stat_info.
* tests/Makefile.am (TESTSUITE_AT): Add append03.at
* tests/testsuite.at: Include append03.at
2010-10-27 14:07:46 +03:00
Paul Eggert
7dd57ebdfa tests: port to Solaris diff
* tests/extrac13.at: Don't assume that "diff -c" outputs nothing
when there are no differences.  This is not true on Solaris,
where it outputs "No differences encounted".
2010-10-26 18:13:03 -07:00
Paul Eggert
e23d123b93 tar: fix -x --overwrite bug (no --dereference, ! O_NOFOLLOW)
This bug was discovered on Solaris 8.  On older hosts lacking
O_NOFOLLOW, tar -x --overwrite (without --dereference) follows
symbolic links, causing the "extract over symlinks" test to fail.

* src/extract.c (open_output_file): If O_NOFOLLOW is needed but
does not work, check for a symlink separately.
2010-10-26 17:58:53 -07:00
Paul Eggert
6398c7a79c tar: don't use "((" in shell scripts
* tests/extrac11.at: Replace "((" with "( (" in shell scripts, as
"((" is not portable to the Korn shell, and POSIX 1003.1-2008 says
that "((" is not portable.
2010-10-26 15:04:56 -07:00
Sergey Poznyakoff
28e91b48f6 Make sure name matching occurs before name transformation.
The commit 9c194c99 altered that order.

* src/list.c (transform_stat_info): New function.  Split off from
decode_header.
(read_and): Call transform_stat_info right before do_something,
and after deciding if we should proceed with this member name,
so that name matching occurs before name transformation.

* tests/extrac17.at: New file.
* tests/Makefile.am (TESTSUITE_AT): Add extrac17.at
* tests/testsuite.at: Include extrac17.at.
2010-10-26 22:29:02 +03:00
Paul Eggert
3c0bedd494 tar: don't assume stdin is open when testing fd limits
* tests/extrac11.at: Redirect stdin from /dev/null, in case
the parent 'make' is running with stdin closed.
2010-10-26 11:33:38 -07:00
Sergey Poznyakoff
c520964e84 Further fixes in bootstrap.
* bootstrap: Restore the default for gnulib_path
(symlink_to_dir): Re-apply 67cad07.
2010-10-26 16:48:40 +03:00
Paul Eggert
acb77ac5bd tar: fix bug with -C and extracting directories
Problem reported by Denis Excoffier in
<http://lists.gnu.org/archive/html/bug-tar/2010-10/msg00034.html>.

* src/extract.c (extract_dir): Use mkdirat, not mkdir.
* tests/extrac16.at: New file, to test for this bug.
* tests/Makefile.am (TESTSUITE_AT): Add it.
* tests/testsuite.at: Include it.

This file is a placeholder. It will be replaced with the actual ChangeLog
by make dist.  Run make ChangeLog if you wish to create it earlier.
2010-10-25 20:21:06 -07:00
Sergey Poznyakoff
983113b140 Version 1.24
* configure.ac, NEWS: Version 1.24
* bootstrap: Restore tar-specific code lost during last
sync from gnulib (241b72ffad).
* src/misc.c (chdir_do): Remove unused automatic variable.
2010-10-25 00:35:50 +03:00
Paul Eggert
9447e799ab tar: use more-accurate diagnostic when intermediate mkdir fails
Without this change, if tar tried to extract a file A/B/C, noticed
that A/B didn't exist, attempted to mkdir A/B, and the mkdir
failed, it did not diagnose the mkdir failure, but simply reported
the failure to open A/B/C.  This sometimes led to confusion
because it wasn't clear what tar was trying to do, in particular
that tar tried to mkdir A/B.  With this patch, tar issues two
diagnostics in this case: one for A/B and the other for A/B/C.
Problem reported by Hauke Laging in
<http://lists.gnu.org/archive/html/bug-tar/2010-10/msg00020.html>.
* gnulib.modules: Remove faccessat.
* src/extract.c (make_directories): New arg INTERDIR_MADE.
Diagnose mkdir failure.  Return 0 on success, nonzero on failure,
as opposed to nonzero iff some directory was created.  All callers
changed.  Simplify the code when mkdir fails, by checking whether
the desired file exists unless errno==EEXIST: this is more robust.
* tests/extrac15.at: New test, to check this.
* tests/Makefile.am (TESTSUITE_AT): Add it.
* tests/testsuite.at: Include it.
2010-10-15 22:26:43 -07:00
Paul Eggert
502abd93bd tests: port to NFS file servers with clock skew
Several of the tests assumed that a newly created file cannot
have a time stamp dated in the future.  This assumption is not
true when files are served by a remote host whose clock is
slightly in advance of ours.  Fix the problems that I observed
when running "make check" a couple of times on such a server.

* tests/backup01.at: Use --warning=no-timestamp to suppress
clock-skew warnings.
* tests/chtype.at, tests/comprec.at, tests/exclude06.at:
* tests/extrac01.at, tests/extrac03.at, tests/extrac05.at:
* tests/extrac06.at, tests/extrac08.at, tests/extrac13.at:
* tests/extrac14.at, tests/incr01.at, tests/incr03.at, tests/link01.at:
* tests/multiv01.at, tests/multiv02.at, tests/multiv03.at:
* tests/pipe.at, tests/rename02.at, tests/rename03.at:
* tests/rename05.at, tests/same-order01.at, tests/same-order02.at:
* tests/sparse01.at:
Likewise.
2010-10-15 21:53:37 -07:00
Paul Eggert
241b72ffad gnulib: sync from latest gnulib, notably bootstrap and parse-datetime
* bootstrap: Sync from gnulib.
* doc/.gitignore: Rename getdate.texi to parse-datetime.texi.
* doc/Makefile.am (tar_TEXINFOS): Likewise.
* doc/tar.texi (Top): Adjust to renaming of getdate to parse-datetime.
* gnulib.modules: Likewise.  Also, remove ftruncate (now obsolete).
And add inttostr (we missed this dependency).
* src/tar.c: Include parse-datetime.h, not getdate.h.  All calls
to get_date replaced with parse_datetime.
2010-10-11 16:25:32 -07:00
Paul Eggert
c5c196310e tar: -x -C symlink fix
* src/misc.c (chdir_do): Don't use O_NOFOLLOW when opening the
argument to -C.  This is for consistency with "tar -c -C FOO", and
matches the new documentation.
* tests/extrac14.at: New file.
* tests/Makefile.am (TESTSUITE_AT): Add it.
* tests/testsuite.at: Include it.
2010-09-24 13:13:47 -07:00
Paul Eggert
14efeb9f95 tar: --dereference consistency
This closes another race condition, that occurs when overwriting a
symlink with a regular file.
* NEWS (--dereference consistency): New section.
* doc/tar.texi (Option Summary): Describe new --deference behavior.
(dereference): Likewise.  Remove discussion that I didn't follow,
even before --dereference was changed.
* src/common.h (deref_stat, set_file_atime): Adjust signatures.
* src/compare.c (diff_file, diff_multivol): Respect open_read_flags
instead of rolling our own flags.  This implements the new behavior
for --dereference.
(diff_file, diff_dumpdir): Likewise, for fstatat_flags.
* src/create.c: Adjust to set_file_atime signature change.
* src/extract.c (mark_after_links, file_newer_p, extract_dir):
Likewise.
* src/incremen.c (try_purge_directory): Likewise.
* src/misc.c (maybe_backup_file): Likewise.
* src/extract.c (file_newer_p): New arg STP.  All callers changed.
(maybe_recoverable): New arg REGULAR.  All callers changed.
Handle the case of overwriting a symlink with a regular file,
when --overwrite is specified but --dereference is not.
(open_output_file): Add O_CLOEXEC, O_NOCTTY, O_NONBLOCK for
consistency with file creation.  Add O_NOFOLLOW if
overwriting_old_files && ! dereference_option.
* src/incremen.c (update_parent_directory): Use fstat, not fstatat;
there's less to go wrong.
* src/misc.c (deref_stat): Remove DEREF arg.  All callers changed.
Instead, use fstatat_flags.
(set_file_atime): Remove ATFLAG arg.  All callers changed.
Instead, use fstatat_flags.
* src/names.c, src/update.c: Adjust to deref_stat signature change.
* src/tar.c (get_date_or_file): Use stat, not deref_stat, as this
is not a file to be archived.
* tests/Makefile.am (TESTSUITE_AT): Add extrac13.at.
* tests/extrac13.at: New file.
* tests/testsuite.at: Include it.
2010-09-23 19:41:47 -07:00
Paul Eggert
efe26f98ec tar: do not crash with --listed-incremental
Problem reported by Frantisek Hanzlik in
<https://bugzilla.redhat.com/635318> via Kamil Dudka in
<http://lists.gnu.org/archive/html/bug-tar/2010-09/msg00066.html>.
I don't understand this code either, but Sergey can take a look at
this patch, and perhaps install a better one, when he has the time.
* src/incremen.c (append_incremental_renames): Don't actually append
anything to DIR if DIR is null.
2010-09-20 11:35:04 -07:00
Paul Eggert
4bde4f39d0 tar: prefer openat-style functions
This change replaces traditional functions like 'open' with the
POSIX.1-2008 functions like 'openat'.  Mostly this is an internal
refactoring change, in preparation for further changes to close
some races.
* gnulib.modules: Add faccessat, linkat, mkfifoat, renameat, symlinkat.
Remove save-cwd.
* src/Makefile.am (tar_LDADD): Add $(LIB_EACCESS).
* tests/Makefile.am (LDADD): Likewise.
* src/common.h (chdir_fd): New extern var.
* src/compare.c (diff_file, diff_multivol): Use openat instead of open.
* src/create.c (create_archive, restore_parent_fd): Likewise.
* src/extract.c (create_placeholder_file): Likewise.
* src/names.c (collect_and_sort_names): Likewise.
* src/update.c (append_file): Likewise.
* src/compare.c (diff_symlink): Use readlinkat instead of readlink.
* src/compare.c (diff_file): Use chdir_fd instead of AT_FDCWD.
* src/create.c (subfile_open, dump_file0): Likewise.
* src/extract.c (fd_chmod, fd_chown, fd_stat, set_stat):
(repair_delayed_set_stat, apply_nonancestor_delayed_set_stat):
Likewise.
* src/extract.c (mark_after_links, file_newer_p, extract_dir):
(extract_link, apply_delayed_links):
Use fstatat rather than stat or lstat.
* src/misc.c (maybe_backup_file, deref_stat): Likewise.
* src/extract.c (make_directories): Use mkdirat rather than mkdir.
Use faccessat rather than access.  This fixes a minor permissions
bug when tar is running setuid (who would want to do that?!).
(open_output_file): Use openat rather than open.
In the process, this removes support for Masscomp's O_CTG files,
which aren't compatible with openat's signature.  Masscomp!  Wow!
That's a blast from the past.  As far as I know, that operating
system hasn't been supported for more than 20 years.
(extract_link, apply_delayed_links):
Use linkat rather than link.
(extract_symlink, apply_delayed_links):
Use symlinkat rather than symlink.
(extract_node): Use mknodat rather than mknod.
(extract_fifo): Use mkfifoat rather than mkfifo.
(apply_delayed_links): Use unlinkat rather than unlink or rmdir.
* src/misc.c (safer_rmdir, remove_any_file): Likewise.
* src/unlink.c (flush_deferred_unlinks): Likewise.
* src/extract.c (rename_directory): Use renameat rather than rename.
* src/misc.c (maybe_backup_file, undo_last_backup): Likewise.
* src/misc.c: Don't include <save-cwd.h>; no longer needed now
that we're using openat etc.
(struct wd): Add member fd.  Remove members err and fd.  All uses
changed.
(CHDIR_CACHE_SIZE): New constant.
(wdcache, wdcache_count, chdir_fd): New vars.
(chdir_do): Use openat rather than save_cwd.  Keep the cache up
to date.  This code won't scale well, but is good enough for now.
* src/update.c (update_archive): Use openat + fdopendir +
streamsavedir rather than savedir.

This file is a placeholder. It will be replaced with the actual ChangeLog
by make dist.  Run make ChangeLog if you wish to create it earlier.
2010-09-18 23:42:54 -07:00
Paul Eggert
fc5e44c99c tar: add utimens.h includes
* src/extract.c: Include <utimens.h>, needed for fdutimens prototype.
* src/misc.c: Likewise.
2010-09-18 00:40:16 -07:00
Paul Eggert
098ad10c71 tar: switch to gnulib fdutimensat module
* gnulib.modules: Add fdutimensat.
* src/common.h (fd_utimensat): Remove decl.
* src/extract.c (set_stat): Call fdutimensat, not fd_utimensat.
* src/misc.c (set_file_atime): Likewise.
(fd_utimensat): Remove.
2010-09-17 14:24:04 -07:00
Paul Eggert
6e08ab7694 tar: extract permissions for . last
* src/common.h (must_be_dot_or_slash): New decl.
* src/extract.c (mark_after_links): New function, taking code
that used to be in create_placeholder_file.
(create_placeholder_file): Use it.
(delay_set_stat): Always delay setting status for . and /.
* src/misc.c (must_be_dot_or_slash): Now extern.
* tests/extrac12.at: New file.
* tests/Makefile.am (TESTSUITE_AT): Add it.
* tests/testsuite.at: Likewise.
2010-09-17 12:28:25 -07:00
Paul Eggert
cecb7ac8e6 tar: don't check for getdtablesize; use AC_CHECK_FUNCS_ONCE
* configure.ac: Don't check for getdtablesize; no longer needed.
Use AC_CHECK_FUNCS_ONCE rather than AC_CHECK_FUNCS, for efficiency.
2010-09-17 10:48:03 -07:00
Paul Eggert
ea964cce81 tar: extract symlink attributes, close some symlink-related races
* NEWS: Describe symlink-extraction improvements.
* src/extract.c (enum permstatus): Remove.
(fchmod, fchown): Define dummy replacement macros if the system
does not supply them.
(implemented): New function.
(struct delayed_set_stat): Remove members invert_permissions,
permstatus.  They were too confusing, and tried to do too much
in too-little space.  Instead, add members current_mode,
current_mode_mask, interdir, atflag.  All users changed.
(struct delayed_link): Add members mode, atime, mtime, to support
platforms such as BSD where symlinks have these attributes.
All users changed.
(fd_chmod): Renamed from fdchmod.  New argument atflag.  Check for
operation not supported at run-time, not at configure-time.  Put
fd argument first.  All callers changed.
(fd_chown): Likewise, renaming from fdchown.
(fd_stat): Likewise, renaming from fdstat.
(set_mode): Remove args stat_info, cur_info, invert_permissions,
permstatus.  Add args mode, mode_mask, current_mode, current_mode_mask,
atflag.  All callers changed.  Close some races.  Use an easier-to
understand method for computing permissions.  Work around POSIX
incompatibility in Linux fchmodat.  Support extraction of symlink
modes, if the OS allows it.
(set_stat): Remove args cur_info, invert_permissions, permstatus.
Add args current_mode, current_mode_mask, interdir, atflag.
All callers changed.  Close some races.  Support extraction of
attributes on symlinks, if the OS allows it.
(delay_set_stat): Remove args invert_permissions, permstatus.
Add args current_mode, current_mode_mask, mode, atflag.
The ST arg can be null now, indicating that it's an intermediate
directory.  All callers changed.
(repair_delayed_set_stat, apply_nonancestor_delayed_set_stat):
Close some races.
(extract_dir): Also be paranoid if only --same-permissions, due
to semantics of setgid and setuid directories on some hosts.
This closes a race on those hosts.  Simplify calculation of
delay_set_stat arguments; the old code was truly strange and
probably wrong in some border cases.
(extract_dir, extract_file, extract_node, extract_fifo): Don't rely on
unspecified behavior in mode arg of open, mknod, etc.  Instead,
mask out those bits when creating the file, and add them later via
fchmod or chmodat.
(open_output_file): file_name is now const.  Add arg current_mode,
current_mode_mask.  All callers changed.  When overwriting old files,
refuse to overwrite something that is not a regular file, since
we're extracting a regular file.
(extract_file): Remove the FIXME comment.  Whatever the protection
issues were, they should be fixed now.  As a result of all the other
API changes, we now use fchmod etc. rather than chmod etc., closing
some races.
(create_placeholder_file, apply_delayed_links): Record desired
mode and times for symlinks, for OSes that support that.
2010-09-17 10:44:13 -07:00
Paul Eggert
e3fdb78d4b tar: tar -x without --incremental no longer sets atime again
* src/extract.c (set_stat): Use UTIME_OMIT rather than UTIME_NOW.
The UTIME_NOW was there only to emulate the previous behavior of
using the current time, and the previous behavior was there only
because before we started assuming POSIX.1-2008 there was no
portable way to get the effect of UTIME_NOW.
2010-09-16 11:02:26 -07:00
Paul Eggert
d945888643 tar: another --atime-preserve race fix
* src/common.h (set_file_atime): Add parentfd arg.
* src/compare.c (diff_file): Use it.
* src/create.c (dump_file0): Likewise.  This closes yet another
race condition with symbolic links.
* src/misc.c (set_file_atime): Add parentfd arg.
2010-09-16 10:47:07 -07:00
Paul Eggert
ecbcb7b6d7 tar: --atime-preserve fixes for races etc.
This patch fixes a race condition in the --atime-preserve=replace
option, which might cause tar to improperly follow a symbolic link.

It also drops the use of the _FIOSATIME ioctl of Solaris 2.x
and later, which loses resolution on time stamps.  Modern Solaris
systems support full-resolution time stamps in the kernel, and
it's not worth the hassle of testing this call, useful only in
no-longer-supported Solaris variants.

Also, it undoes a change I recently introduced to the --compare
option, which caused it to not follow symbolic links unless the
--dereference option was also used.  Quite possibly this change is
a good idea, but the old behavior was documented and the change
should not have been installed casually.

* configure.ac: Don't check for stropts.h and sys/filio.h.
* gnulib.modules: Add futimens, utimensat.  Remove futimens.
* src/common.h (fd_utimensat): New decl.
* src/compare.c (diff_file, diff_multivol):
Don't use open_read_flags: those are for --create only.
* src/create.c (dump_file0): Adjust to set_file_atime changes.
Pass fstatat_flags to set_file_atime, so that symbolic links are
not followed inadvertantly.
* src/extract.c: Don't include utimens.h.
(set_stat): Use fd_utimensat ant UTIME_NOW rather than fdutimens.
* src/misc.c: Don't include utimens.h, stropts.h, sys/filio.h.
(fd_utimensat): New function.
(set_file_atime): Use it.  New arg atflag, controlling symlink
handling.  All callers changed.
2010-09-16 10:17:04 -07:00
Paul Eggert
59146768ef * configure.ac: tar: close some race conditions when extracting
* configure.ac: Check for fchmod and fchown.  Don't check for utimes.
* src/extract.c (fdchmod, fdchown, fdstat): New functions.
(set_mode, set_stat): New arg FD.  All callers changed.
This avoids some race conditions between closing a regular file
and setting its metadata, and it's a bit faster.
2010-09-14 13:34:25 -07:00
Paul Eggert
0fb3020da0 tar: don't worry about fdopendir closing its argument
* NEWS: Don't mention dirfd; no longer needed.
* gnulib.modules: Remove dirfd.
* src/create.c (get_directory_entries): Remove the code dealing
with dirfd failures, as the new fdopendir replacement doesn't
close its argument so we don't need to call dirfd.  See
<http://lists.gnu.org/archive/html/bug-gnulib/2010-09/msg00208.html>
and gnulib commit 970c9038e4cca46e1b037ae0a6d574dfae6a7327.
2010-09-13 13:13:08 -07:00
Paul Eggert
d7db30d0e8 * NEWS: Fix wording typo in previous change.
Reported by Jim Meyering.
2010-09-13 00:22:53 -07:00
Paul Eggert
8da503cad6 tar: live within system-supplied limits on file descriptors
* NEWS: Note the change.  Mention dirfd and fdopendir.
* gnulib.modules: Add dirfd and fdopendir.  The code was already
using fdopendir; dirfd is a new need.
* src/common.h (open_searchdir_flags, get_directory_entries):
(subfile_open, restore_parent_fd, tar_stat_close): New decls.
(check_exclusion_tags): Adjust signature to match code change.
* src/create.c (IMPOSTOR_ERRNO): New constant.
(check_exclusion_tags): First arg is now a struct tar_stat_info
const *, not an fd.  All callers changed.
(dump_regular_file, dump_file0): A zero fd represents an unused
slot, so play it safe if the fd member is zero here.  A negative
fd represents the negation of an errno value, so play it safe and
do not assign -1 to fd merely because an open fails.
(open_failure_recover, get_directory_entries, restore_parent_fd):
(subfile_open): New functions.  These help to recover from file
descriptor exhaustion.
(dump_dir, dump_file0): Use them.
(dump_file0): Use tar_stat_close instead of rolling our own close.
* src/incremen.c (scan_directory): Use get_directory_entries,
subfile_open, etc., to recover from file descriptor exhaustion.
* src/names.c (add_hierarchy_to_namelist): Likewise.
(collect_and_sort_names): A negative fd represents the negation
of an errno value, so play it safe and do not assign -1 to fd.
* src/tar.c (decode_options): Set open_searchdir_flags.
Add O_CLOEXEC to all the open flags.
(tar_stat_close): New function, which knows how to deal with
new convention for directory streams and file descriptors.
Diagnose 'close' failures.
(tar_stat_destroy): Use it.
* src/tar.h (struct tar_stat_info): New member dirstream.
fd now has the negative of an errno value, not merely -1, if
the file could not be opened, so that failures to reopen directories
are better-diagnosed later.
* tests/Makefile.am (TESTSUITE_AT): Add extrac11.at.
* tests/testsuite.at: Likewise.
* tests/extrac11.at: New file.
2010-09-12 14:27:13 -07:00
Paul Eggert
c743301494 tar: improve documentation of reliability and security issues
* doc/tar.texi (Reliability and security, Reliability):
(Permissions problems, Data corruption and repair, Race conditions):
(Security, Privacy, Integrity, Live untrusted data):
(Security rules of thumb): New nodes.
2010-09-08 13:40:27 -07:00
Paul Eggert
de328a580a tar: more reliable directory traversal when creating archives
* NEWS: Document this.
* gnulib.modules: Add openat, readlinkat.
* src/common.h (open_read_flags, fstatat_flags): New global variables.
(cachedir_file_p, dump_file, check_exclusion_tags, scan_directory):
Adjust to new signatures, described below.
(name_fill_directory): Remove.
* src/compare.c (diff_file, diff_multivol): Use open_read_flags.
* src/create.c (struct exclusion_tag): Exclusion predicates now take
a file descriptor, not a file name.
(add_exclusion_tag): Likewise.  All uses changed.
(cachedir_file_p): Likewise.
(check_exclusion_tags): The directory is now a file descriptor,
not a file name.  All uses changed.  Use openat for better traversal.
(file_dumpable_p): Arg is now a struct stat, not a struct
tar_stat_info.  All uses changed.  Check the arg's file types too.
(dump_dir0, dump_dir, dump_file0, dump_file): Omit top_level and
parent_device args, since st->parent tells us that now.  All uses
changed.
(dump_dir): Likewise.  Also, omit fd arg for similar reasons.
Apply fdsavedir to a dup of the file descriptor, since we need a
file descriptor for openat etc. as well, and fdsavedir (perhaps
unwisely) consumes its file descriptor when successful.
Do not consume st->fd when successful; this simplifies the caller.
(create_archive): Allocate a file descriptor when retraversing
a directory, during incremental dumps.
(dump_file0): Use fstatat, openat, and readlinkat for better traversal.
When opening a file, use the result of fstat on the file descriptor
rather than the fstatat on the directory entry, to avoid some race
conditions.  No need to reopen the directory since we now no longer
close it.  Change "did we open the file?" test from 0 <= fd to
0 < fd since fd == 0 now represents uninitialized.
(dump_file): Now accepts struct tar_stat_info describing parent,
not parent_device.  Also, accept basename and fullname of entry.
All uses changed.
* src/incremen.c (update_parent_directory): Accept struct
tar_stat_info for parent, not name.  All callers changed.
Use fstatat for safer directory traversal.
(procdir): Accept struct tar_stat_info, not struct stat and
dev_t, for info about directory.  All callers changed.
(scan_directory): Accept struct tar_stat_info, not name,
device, and cmdline, for info about directory.  All callers
changed.  Do not consume the file descriptor, since caller
might need it.  Use fstatat and openat for safer directory
traversal; also, use fstat after opening to double-check.
(name_fill_directory): Remove.
* src/names.c (add_hierarchy_to_namelist): Accept struct
tar_stat_info instead of device and cmdline.  All callers changed.
When descending into a subdirectory, use openat and fstat for
safer directory traversal.
(collect_and_sort_names): Use open and fstat for safer directory
traversal.  Set up struct tar_stat_info for callee's new API.
* src/tar.c (decode_options): Initialize open_read_flags
and fstatat_flags.
(tar_stat_destroy): Close st->fd if it is positive (not zero!).
* src/tar.h (struct tar_stat_info): New members parent, fd.
* src/update.c (update_archive): Adjust to dump_file's API change.
* tests/filerem02.at: Ignore stderr since its contents now depend
on the file system implementation.
2010-09-06 13:39:21 -07:00
Paul Eggert
bad4b0006c tar: remove lint discovered by Sun C compiler
* src/common.h (WARN_ALL): Don't mask with 0xffffffff; on a 32-bit
host, 0xffffffff is of type 'unsigned int', which makes WARN_ALL
an unsigned int value that is too large to fit into an int, and
the C standard says that this has undefined behavior.  The mask is
not needed, so omit it.
2010-09-04 23:53:23 -07:00
Paul Eggert
e985feb292 tar: restore macros that are used in some cases
* src/tar.c (LOW_DENSITY_NUM, MID_DENSITY_NUM, HIGH_DENSITY_NUM):
Restore these macros, undoing the previous change to this file.
The macros are used after all, in some cases.  Sorry about that.
2010-09-04 00:09:30 -07:00
Paul Eggert
fbc54fa337 tar: remove unused macros
* src/create.c (UINTMAX_TO_CHARS): Remove; no longer used.
* src/tar.c (LOW_DENSITY_NUM, MID_DENSITY_NUM, HIGH_DENSITY_NUM):
Likewise.
* src/incremen.c (DIR_IS_NEW): Comment out; not used.
Mark this with a FIXME, since it looks like it should be used.
2010-09-02 20:46:25 -07:00
Sergey Poznyakoff
45a574151a Fix --remove-files in update/append mode.
* src/update.c (update_archive): Call finish_deferred_unlinks when
done.
2010-08-27 15:36:24 +03:00
Paul Eggert
0adf4027f5 tar: avoid assumptions about root access and chmod -w in test cases
* tests/extrac07.at, tests/extrac09.at, tests/listed03.at: Use
AT_UNPRIVILEGED_PREREQ, since this test requires non-root
privileges.
* tests/extrac07.at: Don't use "chmod -w", as POSIX says it's not
portable to start a chmod permissions-list with "-" as it may be
confused with an option.  Use "chmod a-w" instead.
2010-08-26 10:23:06 -07:00
Paul Eggert
fce1c1c8cb tar: fix bug with -C and delayed setting of metadata
* src/common.h (chdir_current): New decl.
* src/extract.c (struct delayed_set_stat, struct delayed_link):
New member change_dir.
(delay_set_stat, create_placeholder_file): Set it.
(apply_nonancestor_delayed_set_stat, apply_delayed_links): Use it.
(extract_link): Check that the links are all relative to the same
directory.
(extract_archive): Restore the current directory after
apply_nonancestor_delayed_set_stat has possibly changed it.
* src/misc.c (chdir_current): New external var; this used to
be the private static variable 'previous' inside chdir_dir.
All uses changed.
* tests/Makefile.am (TESTSUITE_AT): New test extrac10.at.
* tests/extrac10.at: New file.
* tests/testsuite.at: Include it.
2010-08-25 17:09:59 -07:00
Sergey Poznyakoff
372ac37d01 Don't apply file transformations to volume names.
* src/list.c (decode_header): Don't apply file transformations to volume names.
* tests/xform01.at: New testcase.
* tests/xform-h.at (xform): Rename macro to xformtest. Use pushdef/popdef.
* tests/Makefile.am, tests/testsuite.at: Add xform01.at
2010-08-25 10:54:45 +03:00
Paul Eggert
a9895fd20c tar: optimize -c --sparse when file is entirely sparse
* src/sparse.c (sparse_scan_file): If the file is entirely sparse,
that is, if ST_NBLOCKS is zero, don't bother scanning for nonzero
blocks.  Idea by Kit Westneat, communicated by Bernd Schubert in
<http://lists.gnu.org/archive/html/bug-tar/2010-08/msg00038.html>.
Also, omit unnecessary lseek at start of file.
2010-08-24 17:29:06 -07:00
Paul Eggert
a59c819beb tar: don't assume size of a sparse file chunk fits in size_t
* src/tar.h (struct sp_array): Change numbytes from size_t to off_t.
All uses changed.
* scripts/xsparse.c (struct sp_array): Likewise.
Include <stdint.h>, for SIZE_MAX.
(expand_sparse): Don't try to allocate a buffer bigger than
SIZE_MAX bytes.
* src/common.h (SIZE_TO_CHARS, size_to_chars, SIZE_FROM_HEADER):
(size_from_header): Remove decls.
* src/create.c (size_to_chars): Remove.
* src/list.c (size_from_header): Remove.
* src/sparse.c (sparse_extract_region, check_data_region):
(oldgnu_add_sparse, oldgnu_store_sparse_info, pax_decode_header):
Don't assume chunk sizes fit in size_t.
(oldgnu_add_sparse): Check for off_t overflow.
* src/xheader.c (sparse_numbytes_decoder, sparse_map_decoder):
Likewise.
2010-08-24 16:50:49 -07:00
Paul Eggert
57b11473b0 tar: use ctime, not mtime, when checking placeholders
* src/extract.c (struct delayed_link): Rename member mtime to ctime.
All uses changed to use ctime rather than mtime.
2010-08-24 15:44:25 -07:00
Paul Eggert
fbcadc9592 tar: add comment to link04.at test
* tests/link04.at: Add explanatory comment at head.
2010-08-24 08:18:37 -07:00
Paul Eggert
3b219f943e tar: fix 1.23 Solaris regression related to PRIV_SYS_LINKDIR
The idea was suggested by Petr Sumbera in the thread starting here:
http://lists.gnu.org/archive/html/bug-tar/2010-08/msg00000.html
* src/extract.c (set_mode): Save the errno of the chmod that
failed, for the benefit of chmod_error_details.  Do not bother
retrying chmod unless the mode suggests setuid is the issue.
(extract_archive): Remove redundant call to priv_set_remove_linkdir.
* src/system.c: Include priv-set.h.
(sys_spawn_shell, sys_child_open_for_compress):
(sys_child_open_for_uncompress, sys_exec_command):
(sys_exec_info_script, sys_exec_checkpoint_script):
Invoke priv_set_restore_linkdir before execv or execlp, so that
the subprocess has the same privileges that tar originally did.
2010-08-24 00:07:50 -07:00
Paul Eggert
37ddfb0b7e tar: handle files that occur multiple times but have link count 1
This patch was inspired by the following patch that addressed a
similar problem in GNU coreutils du:
http://git.savannah.gnu.org/gitweb/?p=coreutils.git;h=efe53cc72b599979ea292754ecfe8abf7c839d22
* src/common.h (name_count): New decl.
* src/create.c (trivial_link_count): New static var.
(create_archive): Initialize it.
(dump_hard_link, file_count_links): Use it, so that files with
link count 1 are handled correctly when they are found multiple times.
* src/names.c (allocated_entries): Renamed from allocated_names,
since the identifier's name was misleading.  All uses changed.
(entries): Renamed from names.  All uses changed.
(scanned): Renamed from name_index.  All uses changed.
(name_count): New var.
(name_add_name): Increment it.
* tests/link04.at: New file.
* tests/testsuite.at: Add it.
* tests/Makefile.am (TESTSUITE_AT): Likewise.
2010-08-23 19:13:12 -07:00
Paul Eggert
09f039050e tar: use nlink_t for link counts
* src/create.c (struct link): nlink is now of type nlink_t, not size_t.
2010-08-23 13:49:49 -07:00
Paul Eggert
34795cedb7 tar: don't export names that aren't used elsewhere
* src/common.h (file_dumpable_p, gid_to_chars, major_to_chars):
(minor_to_chars, mode_to_chars, uid_to_chars, uintmax_to_chars):
(string_to_chars, dumpdir_creat0, dumpdir_create, dumpdir_free):
(dumpdir_locate, dumpdir_next, dumpdir_first, gid_from_header):
(major_from_header, minor_from_header, mode_from_header):
(time_from_header, uid_from_header, quote_copy_string, request_stdin):
(xheader_init, transform_header_name):
Remove declarations; these are no longer exported from their modules.
(GID_TO_CHARS, MAJOR_TO_CHARS, MINOR_TO_CHARS, MODE_TO_CHARS):
(UID_TO_CHARS, UINTMAX_TO_CHARS, UNAME_TO_CHARS, GNAME_TO_CHARS):
Move to src/create.c, since no other module uses these.
(GID_FROM_HEADER, MAJOR_FROM_HEADER, MINOR_FROM_HEADER):
(MODE_FROM_HEADER, TIME_FROM_HEADER, UID_FROM_HEADER):
Move to src/extract.c, since no other module uses these.
(dumpdir_t, dumpdir_iter_t): Remove; no longer used.
* src/create.c (gid_to_chars, major_to_chars, minor_to_chars):
(mode_to_chars, uid_to_chars, uintmax_to_chars, string_to_chars):
(file_dumpable_p): Now static.
* src/incremen.c (dumpdir_create0, dumpdir_create, dumpdir_free):
(dumpdir_locate, dumpdir_next, dumpdir_first): Now static.
(scan_directory, write_directory_file_entry):
Use struct dumpdir_iter * rather than dumpdir_iter_t.
* src/list.c (gid_from_header, major_from_header, minor_from_header):
(mode_from_header, time_from_header, uid_from_header):
(transform_member_name): Now static.
* src/misc.c (quote_copy_string): #if 0 out, as it's not used
anywhere.
* src/system.c (wait_for_grandchild): Now static.
* src/tar.c (request_stdin): Now static.
* src/xheader.c (xheader_init): Now static.
2010-08-23 13:27:36 -07:00
Paul Eggert
9764a6b1d3 tar: fix misspelled identifier "set_comression_program_by_suffix"
* src/suffix.c (set_compression_program_by_suffix): Renamed from
set_comression_program_by_suffix.
* src/buffer.c, src/common.h, src/tar.c: All uses changed.
2010-08-23 11:37:19 -07:00
Paul Eggert
a1a15e3202 tar: change interdir_made from int to bool
* src/extract.c (maybe_recoverable, create_placeholder_file):
Change interdir_made from int * to bool *, since the flag has just
two values 0 and 1.  All uses changed.  This does not affect tar's
behavior.
2010-08-20 01:09:17 -07:00
Paul Eggert
0ab5e64ac0 tar: remove trailing white space from source files
* ChangeLog.1, ChangeLog.CVS, Makefile.am, NEWS, README:
* README-hacking, directory, doc/Makefile.am, doc/dumpdir.texi:
* doc/gendocs_template, doc/intern.texi, doc/mastermenu.el:
* doc/snapshot.texi, doc/sparse.texi, doc/tar-snapshot-edit.texi:
* doc/value.texi, lib/Makefile.am, scripts/backup-specs:
* scripts/dump-remind.in, scripts/tar-snapshot-edit, scripts/tarcat:
* scripts/xsparse.c, src/arith.h, src/buffer.c, src/compare.c:
* src/create.c, src/delete.c, src/exit.c, src/suffix.c, src/tar.c:
* src/tar.h, src/update.c, src/warning.c, src/xheader.c:
* tests/append01.at, tests/append02.at, tests/atlocal.in:
* tests/delete03.at, tests/exclude.at, tests/exclude06.at:
* tests/extrac04.at, tests/extrac05.at, tests/extrac06.at:
* tests/extrac07.at, tests/filerem01.at, tests/filerem02.at:
* tests/incr01.at, tests/incr02.at, tests/incr03.at, tests/incr06.at:
* tests/label02.at, tests/label03.at, tests/label04.at:
* tests/label05.at, tests/link02.at, tests/link03.at:
* tests/listed01.at, tests/listed02.at, tests/long01.at:
* tests/longv7.at, tests/multiv01.at, tests/multiv02.at:
* tests/multiv03.at, tests/multiv05.at, tests/multiv06.at:
* tests/multiv07.at, tests/multiv08.at, tests/options.at:
* tests/options02.at, tests/remfiles03.at, tests/rename01.at:
* tests/rename02.at, tests/rename03.at, tests/rename04.at:
* tests/rename05.at, tests/same-order01.at, tests/same-order02.at:
* tests/shortfile.at, tests/shortupd.at, tests/sparse01.at:
* tests/sparse02.at, tests/sparsemv.at, tests/sparsemvp.at:
* tests/star/README, tests/star/gtarfail2.at:
* tests/star/multi-fail.at:
* tests/star/pax-big-10g.at, tests/star/quicktest.sh:
* tests/star/ustar-big-2g.at, tests/star/ustar-big-8g.at:
* tests/update01.at, tests/update02.at, tests/volsize.at:
* tests/volume.at:
Remove trailing spaces and tabs from lines, and remove
trailing empty lines from files.  This makes it a bit easier
to share code among coreutils and other projects that do this.
2010-08-19 15:50:07 -07:00
Paul Eggert
0a694a16e5 tar: update licenses to latest versions from www.gnu.org
* COPYING: Update to latest version; this is just minor formatting.
* doc/fdl.texi: Update from GFDL 1.2 to 1.3.
* doc/tar.texi: Adjust to new format of fdl.texi.  Omit trailing
white space.
2010-08-19 04:15:42 -07:00
Paul Eggert
b3b15f7cbc * src/misc.c (struct wd): Fix comment to match code. 2010-07-18 12:34:13 -07:00
Paul R. Eggert
8c662c9f29 tar: no need to report getcwd error if never using the result
* src/misc.c (struct wd): Rename 'saved' to 'err', with new semantics.
(chdir_arg, chdir_do): Adjust to new semantics.  Do not report an
error merely because save_cwd fails; report an error only if
save_cwd's result is needed later.
* tests/extrac09.at: New file, to test for bug that was fixed.
* tests/testsuite.at: Include it.
* tests/Makefile.am (TESTSUITE_AT): Add it.
2010-07-18 12:20:47 -07:00
Paul R. Eggert
427b3b8c79 tar: go back to absolutifying filenames in normalize_filename for now
* src/misc.c (normalize_filename): For now, go back to making
filenames absolute, even though this causes 'tar' to fail when
getcwd fails.  However, do not attempt to resolve ".." as this
does not work with symlinks.  Also, do the right thing with
leading file system prefixes and on hosts where // != /.
2010-07-17 15:47:46 -07:00
Sergey Poznyakoff
c1b30c268f Allow for size suffixes in -L and --record-size options.
* src/tar.c (TAR_SIZE_SUFFIXES): New define.
(parse_opt): Allow for size suffixes in arguments to
-L and --record-size options.
* NEWS, doc/tar.texi: Update.
2010-07-17 11:38:08 +03:00
Paul R. Eggert
cc40c57a37 tar: don't crash if getcwd fails
* src/extract.c: Don't include xgetcwd.h.
(extract_dir): stat "." rather than statting getcwd's output.
* src/misc.c (normalize_filename_x): Rewrite so as not to resolve
/../, which can't be done reliably in the presence of symlinks.
Don't reject valid names such as ".".
(normalize_filename): Don't make it absolute; that way, we don't
have to invoke xgetcwd which might fail.  Don't bother to realloc
at the end, since that uses time and now saves little space.
(chdir_do): Don't crash if xgetcwd fails.
* tests/Makefile.am (TESTSUITE_AT): Add listed03.at.
* tests/listed03.at: New file.
* tests/testsuite.at: Include listed03.at.
2010-07-15 11:25:15 -07:00
Sergey Poznyakoff
ab6dd4948d Keep a detailed map of archive members stored in the record buffer.
A separate map (bufmap) provides information for creating
multi-volume continuation headers.

* src/buffer.c (bufmap): New struct.
(bufmap_head, bufmap_tail, inhibit_map): New variables.
(mv_begin_write): New function.
(mv_begin): Rename to mv_begin_read. Rewrite using mv_begin_write.
All callers changed.
(mv_total_size): Remove.
(bufmap_locate, bufmap_free, bufmap_reset): New functions.
(_flush_write): Update bufmap.
(close_archive): Free bufmap.
(add_chunk_header): Take a bufmap argument.
(gnu_add_multi_volume_header): Likewise.
(add_multi_volume_header): Likewise.
(_gnu_flush_write): Rewrite using bufmap.
(real_s_name, real_s_totsize)
(real_s_sizeleft)
(save_name, save_totsize, save_sizeleft): Removed. All
uses updated.
(mv_size_left): Update bufmap_head.
(mv_end): Rewrite.
(multi_volume_sync): Remove.

* src/common.h (mv_begin_write): New prototype.
(mv_begin): Rename to mv_begin_read.
* src/create.c: Use mv_begin_write instead of mv_begin.
Remove calls to mv_size_left and mv_end.
* src/sparse.c: Likewise.

* tests/multiv07.at: Close stdin.
* tests/spmvp00.at: Update AT_KEYWORDS.
* tests/spmvp10.at: Likewise.

* tests/multiv08.at: New testcase.
* tests/Makefile.am, tests/testsuite.at: Add multiv08.at.
2010-07-11 22:57:17 +03:00
Sergey Poznyakoff
b4bcb97e38 Version 1.23.90
* NEWS, configure.ac: Version 1.23.90
* doc/tar.texi: Document the use of lbzip2.
2010-07-11 19:36:43 +03:00
Sergey Poznyakoff
9c194c9942 Fix exclusion of long file names when extracting from pax format archives.
* src/list.c (read_and): Call decode_header before attempting
name_match.
(list_archive): Remove call to decode_header.

* src/compare.c (diff_archive): Remove call to decode_header.
* src/extract.c (extract_archive): Likewise.

* test/exclude06.at: New test case.
* tests/testsuite.at: Include exclude06.at.
* tests/Makefile.am (TESTSUITE_AT): Add exclude06.at.
2010-06-28 16:56:54 +03:00
Sergey Poznyakoff
80a6ef7d94 Minor fix.
* src/buffer.c (magic): Split the character constant to help
cc recognize character boundaries (7 is a valid hex character).
2010-06-28 00:04:49 +03:00
Sergey Poznyakoff
9b31db388e Minor fix.
* src/buffer.c (magic): Fix xz magic.
2010-06-27 23:47:20 +03:00
Paul Eggert
f6edb92580 Remove some lint, found by gcc -W etc.
* src/common.h (label_notfound): New decl.
* src/buffer.c (set_volume_start_time, compress_type):
(guess_seekable_archive, open_compressed_archive, init_buffer):
(_flush_write, archive_is-dev, increase_volume_number):
(change_tape_menu, try_new_volume, add_chunk_header):
(multi_volume_sync):
Declare as 'static' if it's not exported.
Use function prototype (void) rather than old-style ().
* src/checkpoint.c (expand_checkpoint_string): Likewise.
* src/incremen.c (dirlist_replace_prefix, makedumpdir, read_incr_db_2):
Likewise.
* src/list.c (print_volume_label): Likewise.
* src/misc.c (normalize_filename_x): Likewise.
* src/names.c (make_name, free_name, check_name_alloc, name_next_elt):
Likewise.
* src/tar.c (tar_list_quoting_style, add_exclude_array):
(set_stat_signal): Likewise.
* src/transform.c (new_transform, _single_transform_name_to_obstack):
(_transform_name_to_obstack): Likewise.
* src/unlink.c (dunlink_alloc): Likewise.

* src/buffer.c (struct zip_magic): Use const when appropriate.
* src/incremen.c (obstack_code_rename, write_directory_file_entry):
Likewise.
* src/sparse.c (COPY_STRING): Likewise.
* src/system.c (dec_to_env, time_to_env, oct_to_env, str_to_env):
(chr_to_env): Likewise.
* src/tar.c (tar_list_quoting_style, set_stat_signal): Likewise.

* src/extract.c (extract_node): Don't return garbage.

* src/names.c: Remove old-style declarations of getgrnam etc.
All modern systems declare these, and it's not worth the hassle
of ignoring the warnings on modern systems for old-style decls.
2010-06-16 13:04:12 -07:00
Sergey Poznyakoff
e21d54e8cd Bugfix.
* src/incremen.c (make_directory): Retain the slash if it is the
only character in a filename.
2010-05-17 20:22:16 +03:00
Sergey Poznyakoff
c79f0d06bc Recode NEWS back to UTF-8 2010-04-02 14:24:58 +03:00
Sergey Poznyakoff
2c97cb7ea2 Fix the gzip.at test case.
* tests/gzip.at: Suppress gzip error output, as it can differ
depending on its version etc. Bug reported by Ludovic Courtès.
2010-04-01 00:03:51 +03:00
Sergey Poznyakoff
fc61c17410 New option --full-time.
* src/common.h (full_time_option): New global.
* src/tar.c (FULL_TIME_OPTION): New constant.
(options): New option --full-time.
(parse_opt): Handle the --full-time option.
* src/list.c (simple_print_header): Pass full_time_option
as the 2nd argument to tartime.
* doc/tar.texi: Update.
* NEWS: Update.
2010-03-28 12:26:37 +03:00
Sergey Poznyakoff
2981fcc5cb Minor fixes in the testsuite.
* tests/extrac07.at: Fix a typo (invalid number
of arguments before format list).
* tests/link02.at: Use `ln' instead of `link'.
* tests/link03.at: Likewise.
2010-03-27 22:46:18 +02:00
Sergey Poznyakoff
40dea1ae7f Fix coredump.
* src/names.c (collect_and_sort_names): Remove
entry from the table before freeing it.
2010-03-27 22:24:19 +02:00
Sergey Poznyakoff
b60e56fdb6 Fix dead loop on extracting existing symlinks with the -k option.
* src/extract.c (create_placeholder_file)
(extract_link, extract_symlink)
(extract_node, extract_fifo): Handle all possible
return values from maybe_recoverable. This complements
8f390db92f. Reported by Ico Doornekamp <bug-tar@zevv.nl>.
* NEWS: Update.
2010-03-27 22:02:28 +02:00
Sergey Poznyakoff
340dbf5aab Fix undesired error exit on receiving SIGPIPE.
* src/tar.c: Do not ignore SIGPIPE.
* tests/sigpipe.at: New testcase.
* tests/Makefile.am, tests/testsuite.at: Add sigpipe.at
* tests/remfiles01.at: Fix error code expectation.
* NEWS: Update.
2010-03-20 13:20:30 +02:00
Sergey Poznyakoff
c1d3d13493 Fix --remove-files.
Tar --remove-files relied on canonicalize_file_name,
which replaces symlinks in file name components with
the directories they point to. Due to this, tar
effectively ignored existence of symbolic links and
was unable to remove a directory that contained any
(Alexander Kozlov <akozlov@nada.kth.se>, 2010-03-15).

* gnulib.modules: Remove canonicalize.
* src/misc.c (normalize_filename): Rewrite
from scratch. The function operates only on
its input string, it makes no attempt to test
components for existence or to resolve symbolic
links.
* tests/Makefile.am (TESTSUITE_AT): Add remfiles03.at.
* tests/testsuite.at: Likewise.
* tests/remfiles03.at: New test case.
* NEWS: Update.
2010-03-17 11:52:40 +02:00
Sergey Poznyakoff
67b4f3519d Bugfixes.
* src/buffer.c (check_label_pattern): Initialize result.
* tests/remfiles01.at: Skip if run with root privileges.
2010-03-12 09:48:46 +02:00
Sergey Poznyakoff
0ba8bdf5f3 Fix --test-label' and --label -r' behavior.
* doc/tar.texi (Including a Label in the Archive): Revise
the section.
* NEWS: Update

* src/buffer.c (open_archive): Check volume label on
ACCESS_UPDATE as well.
* src/list.c (test_archive_label): Rewrite to match the
documentation.
* src/names.c (regex_usage_warning): Return int.
(names_notfound): Rewrite the conditional.
(label_notfound): New function.

* tests/label03.at: New testcase.
* tests/label04.at: New testcase.
* tests/label05.at: New testcase.
* tests/Makefile.am: Add new testcases.
* tests/testsuite.at: Likewise.
2010-03-11 17:41:23 +02:00
Sergey Poznyakoff
8d3cc6c3cf Doc fixes.
* doc/tar.texi: Consistently use lowercase `see' within sentences.
More fixes spotted by Denis Excoffier.
* THANKS: Update.
2010-03-11 15:06:18 +02:00
Sergey Poznyakoff
3f4a6d83f0 Shut up a gcc warning message.
* src/tar.c (tar_help_filter): Use a separate const
variable to hold returns from gettext. Reported by
Peter Breitenlohner.
2010-03-11 15:05:57 +02:00
Sergey Poznyakoff
a3f1d933cc Bugfix.
* src/names.c (collect_and_sort_names): Initialize prev_name.
Reported by Dmitry V. Levin.
2010-03-11 12:19:32 +02:00
150 changed files with 4980 additions and 2293 deletions

18
COPYING
View File

@@ -1,12 +1,11 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
@@ -69,7 +68,7 @@ patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
TERMS AND CONDITIONS
0. Definitions.
@@ -77,7 +76,7 @@ modification follow.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
@@ -510,7 +509,7 @@ actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
@@ -619,9 +618,9 @@ an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -673,4 +672,3 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -1,4 +1,4 @@
Currently there is just one ChangeLog file for tar, but
Currently there is just one ChangeLog file for tar, but
there used to be separate ChangeLog files for each subdirectory.
This file records what used to be in those separate files.

View File

@@ -5,7 +5,7 @@
2009-03-04 Sergey Poznyakoff <gray@gnu.org.ua>
Add xz support.
* src/buffer.c, src/suffix.c: Add support for xz compression.
* src/tar.c: New option --xz, for compression/decompression using xz.
Re-assign -J as a short equivalent of --xz.
@@ -34,8 +34,8 @@
2008-11-25 Sergey Poznyakoff <gray@gnu.org.ua>
Do not try to drain the input pipe before closing the
archive.
archive.
* src/buffer.c (close_archive): Remove call to
sys_drain_input_pipe. Pass hit_eof as the second
argument to sys_wait_for_child.
@@ -63,7 +63,7 @@
* 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.
argument.
(transform_member_name): 2nd arg is int.
(decode_header): Transform file name and link target names.
* src/tar.c: Remove --transform-symlinks.
@@ -73,7 +73,7 @@
set global flags using `flags=' syntax.
(_transform_name_to_obstack, transform_name_fp)
(transform_name): Take an additional argument, specifying scope
flags.
flags.
2008-10-19 Sergey Poznyakoff <gray@gnu.org.ua>
@@ -86,7 +86,7 @@
* tests/sparsemvp.at: Likewise.
* tests/volsize.at: Likewise.
* NEWS: Update.
2008-10-16 Sergey Poznyakoff <gray@gnu.org.ua>
* src/common.h (transform_symlinks_option): New global.
@@ -99,11 +99,11 @@
* doc/tar.texi: Document --transform-symlinks
* NEWS: Update.
* THANKS: Update.
* src/names.c (name_gather): Use xzalloc.
* src/buffer.c (short_read): Move record size detection before
the loop.
2008-10-07 Sergey Poznyakoff <gray@gnu.org.ua>
* src/tar.c (options): Add --lzop option.
@@ -111,7 +111,7 @@
2008-10-05 Xavier Hienne <xavier.hienne@free.fr> (tiny change)
* src/checkpoint.c (checkpoint_compile_action): Add missing
`else'.
`else'.
2008-09-24 Sergey Poznyakoff <gray@gnu.org.ua>
@@ -157,7 +157,7 @@
* tests/atlocal.in (decho): New function.
* tests/multiv06.at: Use decho instead of echo2.
* tests/incremental.at: Raise wait interval to 2 seconds.
2008-07-24 Sergey Poznyakoff <gray@gnu.org.ua>
* src/tar.c (decode_options): Do not allow volume length less
@@ -193,21 +193,21 @@
tests/longv7.at, tests/lustar01.at, tests/lustar02.at,
tests/shortfile.at: Update to match new diagnostic wording
(see 2008-05-06).
* NEWS: Update.
2008-06-14 Sergey Poznyakoff <gray@gnu.org.ua>
* doc/tar.texi (exclude): Document support for new VCS.
* THANKS: Update.
* NEWS: Update.
* NEWS: Update.
* tests/multiv05.at: Fix typos.
* tests/volsize.at: Remove a TZ dependency.
2008-06-14 Dan Drake <dan@dandrake.org> (tiny change)
* src/tar.c (exclude_vcs_files): Support for Bazaar, Mercurial and
Darcs.
Darcs.
2008-05-06 Sergey Poznyakoff <gray@gnu.org.ua>
@@ -231,23 +231,23 @@
* tests/incr03.at, tests/incr04.at, tests/rename02.at,
tests/rename03.at: Insert calls to sleep between creation of files
and adding them to the archive.
2008-03-31 Sergey Poznyakoff <gray@gnu.org.ua>
* src/create.c (dump_file0): Count links only for actually dumped
files.
files.
2008-03-27 Sergey Poznyakoff <gray@gnu.org.ua>
* NEWS: Document --no-check-device and --check-device.
* doc/rendition.texi: Change the way FIXME-*refs are handled in
!PROOF.
!PROOF.
* doc/intern.texi, doc/tar.texi: Update.
* doc/untabify.el: New file.
* doc/Makefile.am (EXTRA_DIST): Add untabify.el
(untabify, final, check-format, check-refs, check-fixmes)
(check-unrevised, all-check-docs, check-docs): New rules.
* src/common.h (check_device_option): New global.
* src/incremen.c (procdir): Use boolean and instead of bitwise
one. Patch by Jean-Louis Martineau.
@@ -256,7 +256,7 @@
--check-device. Proposed by Jean-Louis Martineau.
(parse_opt): Hanlde new options.
(decode_options): Initialize check_device_option to true.
* THANKS: Update
2008-03-06 Sergey Poznyakoff <gray@gnu.org.ua>
@@ -267,7 +267,7 @@
* po/.cvsignore: Update
* src/system.c: Remove include setenv.h.
* tests/atlocal.in (STAR_DATA_URL): Update.
* tests/star/README: Update URL.
* tests/star/README: Update URL.
2008-02-09 Sergey Poznyakoff <gray@gnu.org.ua>
@@ -303,7 +303,7 @@
Exit with nonzero status if a close fails on an archive.
Problem (and initial trivial fix)
* src/buffer.c (close_archive, new_volume): close_error, not
close_warn.
close_warn.
2007-12-05 Sergey Poznyakoff <gray@gnu.org.ua>

View File

@@ -22,7 +22,7 @@ ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = ChangeLog.1 Make.rules
SUBDIRS = doc gnu lib rmt src scripts po tests
dist-hook:
dist-hook:
$(MAKE) changelog_dir=$(distdir) ChangeLog
-rm -f $(distdir).cpio
find $(distdir) | cpio -Hcrc -o | \
@@ -36,5 +36,3 @@ include Make.rules
gen_start_date = 2009-03-06
prev_change_log = ChangeLog.CVS
changelog_dir = .

169
NEWS
View File

@@ -1,6 +1,147 @@
GNU tar NEWS - User visible changes. 2010-03-10
GNU tar NEWS - User visible changes. 2011-03-12
Please send GNU tar bug reports to <bug-tar@gnu.org>
version 1.26 - Sergey Poznyakoff, 2011-03-12
* Bugfixes
** Fix the --verify option, which broke in version 1.24.
** Fix storing long sparse file names in PAX archives.
** Fix correctness of --atime-preserve=replace
tar --atime-preserve=replace no longer tries to restore atime of
zero-sized files.
** Work around POSIX incompatibilities on FreeBSD, NetBSD and Tru64
** Fix bug with --one-file-system --listed-incremental
When invoked with these two options, tar 1.25 would add only the
top-level directory to the archive, but not its contents.
version 1.25 - Sergey Poznyakoff, 2010-11-07
* Fix extraction of empty directories with the -C option in effect.
* Fix extraction of device nodes.
* Make sure name matching occurs before eventual name transformation.
Tar 1.24 changed the ordering of name matching and name transformation
so that the former saw already transformed file names. This made it
impossible to match file names in certain cases. It is fixed now.
* Fix the behavior of tar -x --overwrite on hosts lacking O_NOFOLLOW.
* Improve the testsuite.
* Alternative decompression programs.
If extraction from a compressed archive fails because the corresponding
compression program is not installed and the following two conditions
are met, tar retries extraction using an alternative decompressor:
1. Another compression program supported by tar is able to handle this
compression format.
2. The compression program was not explicitly requested in the command
line by the use of such options as -z, -j, etc.
For example, if `compress' is not available, tar will try `gzip'.
version 1.24 - Sergey Poznyakoff, 2010-10-24
* The --full-time option.
New command line option `--full-time' instructs tar to output file
time stamps to the full resolution.
* Bugfixes.
** More reliable directory traversal when creating archives
Tar now checks for inconsistencies caused when a file system is
modified while tar is creating an archive. In the new approach, tar
maintains a cache of file descriptors to directories, so it uses more
file descriptors than before, but it adjusts to system limits on
the number of file descriptors. Tar also takes more care when
a file system is modified while tar is extracting from an archive.
The new checks are implemented via the openat and related calls
standardized by POSIX.1-2008. On an older system where these calls do
not exist or do not return useful results, tar emulates the calls at
some cost in efficiency and reliability.
** Symbolic link attributes
When extracting symbolic links, tar now restores attributes such as
last-modified time and link permissions, if the operating system
supports this. For example, recent versions of the Linux kernel
support setting times on symlinks, and some BSD kernels also support
symlink permissions.
** --dereference consistency
The --dereference (-h) option now applies to files that are copied
into or out of archives, independently of other options. For example,
if F is a symbolic link and archive.tar contains a regular-file member
also named F, "tar --overwrite -x -f archive.tar F" now overwrites F
itself, rather than the file that F points to. (To overwrite the file
that F points to, add the --dereference (-h) option.) Formerly,
--dereference was intended to apply only when using the -c option, but
the implementation was not consistent.
Also, the --dereference option no longer affects accesses to other
files, such as archives and time stamp files. Symbolic links to these
files are always followed. Previously, the links were usually but not
always followed.
** 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.
** --record-size and --tape-length (-L) options
Usual size suffixes are allowed for these options. For example,
-L10k stands for a 10 kilobyte tape length.
** Fix dead loop on extracting existing symlinks with the -k option.
version 1.23 - Sergey Poznyakoff, 2010-03-10
@@ -80,7 +221,7 @@ the Epoch or a `Time reference' (see below).
* Time references in --pax-option argument.
Any value from the --pax-option argument that is enclosed in a pair
of curly braces represents a time reference. The string between the
of curly braces represents a time reference. The string between the
braces is understood either as a textual time representation, as described in
chapter 7, "Date input formats", of the Tar manual, or as a name of
an existing file, starting with `/' or `.'. In the latter
@@ -114,14 +255,14 @@ version 1.22 - Sergey Poznyakoff, 2009-03-05
* Support for xz compression
Tar uses xz for compression if one of the following conditions is met:
Tar uses xz for compression if one of the following conditions is met:
1. The option --xz or -J (see below) is used.
2. The xz binary is set as compressor using --use-compress-program option.
3. The file name of the archive being created ends in `.xz' and
auto-compress option (-a) is used.
Xz is used for decompression if one of the following conditions is met:
Xz is used for decompression if one of the following conditions is met:
1. The option --xz or -J is used.
2. The xz binary is set as compressor using --use-compress-program option.
@@ -174,7 +315,7 @@ control type of archive members affected by them. The flags are:
- s
Apply transformation to symbolic link targets.
- h
- h
Apply transformation to hard link targets.
Corresponding upper-case letters negate the meaning, so that
@@ -196,10 +337,10 @@ can be changed using `flags=' statement before the expressions, e.g.:
** The --null option disabled handling of tar options in list files. This
is fixed.
** 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.
** Fixed record size autodetection. If the detected record size differs from
the expected value (either default one, or the one set from 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.
@@ -253,7 +394,7 @@ during both creation and extraction. Tar 1.19 used them only
during extraction.
For a detailed description, see chapter 6.7 "Modifying File and Member
Names".
Names".
* Info (end-of-volume) scripts
@@ -280,8 +421,8 @@ control systems, e.g. "CVS/", ".svn/", etc.
The following options now work with incremental archives as well:
--exclude-caches
--exclude-caches-all
--exclude-caches
--exclude-caches-all
--exclude-tag
--exclude-tag-all
--exclude-tag-under
@@ -292,14 +433,14 @@ Previous versions always stored absolute file names in rename
records, even if -P was not used. This is fixed: rename records
contain file names processed in accordance with the command line
settings.
* Fix --version output.
* Recognition of broken archives.
When supplied an archive smaller than 512 bytes in reading mode (-x,
-t), the previous version of tar silently ignored it, exiting with
code 0. It is fixed. Tar now issues the following diagnostic message:
code 0. It is fixed. Tar now issues the following diagnostic message:
'This does not look like a tar archive', and exits with code 2.
* Fix double-dot recognition in archive member names in case of duplicate '/.'.

7
README
View File

@@ -180,19 +180,19 @@ the `lchown' call will be used if available, but that's all.
GNU `tar' is able to create archive in the following formats:
*** The format of UNIX version 7
*** POSIX.1-1988 format, also known as "ustar format"
*** POSIX.1-1988 format, also known as "ustar format"
*** POSIX.1-2001 format, also known as "pax format"
*** Old GNU format (described below)
In addition to those, GNU `tar' is also able to read archives
produced by `star' archiver.
produced by `star' archiver.
A so called `Old GNU' format is based on an early draft of the
POSIX 1003.1 `ustar' standard which is different from the final
standard. It defines its extensions (such as incremental backups
and handling of the long file names) in a way incompatible with
any existing tar archive format, therefore the use of old GNU
format is strongly discouraged.
format is strongly discouraged.
Please read the file NEWS for more information about POSIX compliance
and new `tar' features.
@@ -248,4 +248,3 @@ mode: outline
paragraph-separate: "[ ]*$"
version-control: never
End:

View File

@@ -6,20 +6,20 @@ this package.
You need the following packages to build the Git version of GNU
tar. We do not make any efforts to accommodate older versions of
these packages, so please make sure that you have the latest stable
version.
version.
- Automake <http://www.gnu.org/software/automake/>
- Autoconf <http://www.gnu.org/software/autoconf/>
- M4 <http://www.gnu.org/software/m4/>
- Texinfo <http://www.gnu.org/software/texinfo>
- Gnulib <http://www.gnu.org/software/gnulib>
- Gnulib <http://www.gnu.org/software/gnulib>
- Git <http://git.or.cz>
* Bootstrapping
Obviously, if you are reading these notes, you did manage to clone
tar from Git. The next step is to get other files needed to build,
which are extracted from other source packages:
which are extracted from other source packages:
1. Change to the source tree directory
@@ -27,7 +27,7 @@ which are extracted from other source packages:
2. Run
./bootstrap
./bootstrap
Once done, proceed as described in the file README (section
INSTALLATION).
@@ -43,7 +43,7 @@ contents:
Replace `$HOME/gnulib' with the actual directory where the Gnulib
sources reside.
For more information about `bootstrap', run `bootstrap --help'.
@@ -67,5 +67,3 @@ mode: outline
paragraph-separate: "[ ^L]*$"
version-control: never
End:

2
THANKS
View File

@@ -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

509
bootstrap
View File

@@ -1,8 +1,10 @@
#! /bin/sh
# Print a version string.
scriptversion=2010-10-24.18; # UTC
# Bootstrap this package from checked-out sources.
# Copyright (C) 2003-2008, 2009 Free Software Foundation, Inc.
# Copyright (C) 2003-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
@@ -17,7 +19,15 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Written by Paul Eggert and Sergey Poznyakoff.
# Originally written by Paul Eggert. The canonical version of this
# script is maintained as build-aux/bootstrap in gnulib, however, to
# be useful to your project, you should place a copy of it under
# version control in the top-level directory of your project. The
# intent is that all customization can be done with a bootstrap.conf
# file also maintained in your version control; gnulib comes with a
# template build-aux/bootstrap.conf to get you started.
# Please report bugs or propose patches to bug-gnulib@gnu.org.
nl='
'
@@ -34,7 +44,7 @@ bt_regex=`echo "$bt"| sed 's/\./[.]/g'`
bt2=${bt}2
usage() {
echo >&2 "\
cat <<EOF
Usage: $0 [OPTION]...
Bootstrap this package from the checked-out sources.
@@ -48,7 +58,7 @@ Options:
sources reside. Use this if you already
have gnulib sources on your machine, and
do not want to waste your bandwidth downloading
them again.
them again. Defaults to \$GNULIB_SRCDIR.
--copy Copy files instead of creating symbolic links.
--force Attempt to bootstrap even if the sources seem
not to have been checked out.
@@ -57,8 +67,11 @@ Options:
If the file $0.conf exists in the same directory as this script, its
contents are read as shell variables to configure the bootstrap.
For build prerequisites, environment variables like \$AUTOCONF and \$AMTAR
are honored.
Running without arguments will suffice in most cases.
"
EOF
}
# Configuration.
@@ -72,13 +85,22 @@ gnulib_modules=
# Any gnulib files needed that are not in modules.
gnulib_files=
# A function to be called to edit gnulib.mk right after it's created.
# Override it via your own definition in bootstrap.conf.
gnulib_mk_hook() { :; }
# A function to be called after everything else in this script.
# Override it via your own definition in bootstrap.conf.
bootstrap_epilogue() { :; }
# The command to download all .po files for a specified domain into
# a specified directory. Fill in the first %s is the domain name, and
# the second with the destination directory. Use rsync's -L and -r
# options because the latest/%s directory and the .po files within are
# all symlinks.
po_download_command_format=\
"rsync -Lrtvz 'translationproject.org::tp/latest/%s/' '%s'"
"rsync --delete --exclude '*.s1' -Lrtvz \
'translationproject.org::tp/latest/%s/' '%s'"
extract_package_name='
/^AC_INIT(/{
@@ -108,14 +130,14 @@ tests_base=tests
# Extra files from gnulib, which override files from other sources.
gnulib_extra_files="
$build_aux/install-sh
$build_aux/missing
$build_aux/mdate-sh
$build_aux/texinfo.tex
$build_aux/depcomp
$build_aux/config.guess
$build_aux/config.sub
doc/INSTALL
$build_aux/install-sh
$build_aux/missing
$build_aux/mdate-sh
$build_aux/texinfo.tex
$build_aux/depcomp
$build_aux/config.guess
$build_aux/config.sub
doc/INSTALL
"
# Additional gnulib-tool options to use. Use "\newline" to break lines.
@@ -131,7 +153,8 @@ XGETTEXT_OPTIONS='\\\
--flag=error:3:c-format --flag=error_at_line:5:c-format\\\
'
# Package bug report address for gettext files
# Package bug report address and copyright holder for gettext files
COPYRIGHT_HOLDER='Free Software Foundation, Inc.'
MSGID_BUGS_ADDRESS=bug-$package@gnu.org
# Files we don't want to import.
@@ -150,6 +173,44 @@ copy=false
# on which version control system (if any) is used in the source directory.
vc_ignore=auto
# find_tool ENVVAR NAMES...
# -------------------------
# Search for a required program. Use the value of ENVVAR, if set,
# otherwise find the first of the NAMES that can be run (i.e.,
# supports --version). If found, set ENVVAR to the program name,
# die otherwise.
find_tool ()
{
find_tool_envvar=$1
shift
find_tool_names=$@
eval "find_tool_res=\$$find_tool_envvar"
if test x"$find_tool_res" = x; then
for i
do
if ($i --version </dev/null) >/dev/null 2>&1; then
find_tool_res=$i
break
fi
done
else
find_tool_error_prefix="\$$find_tool_envvar: "
fi
if test x"$find_tool_res" = x; then
echo >&2 "$0: one of these is required: $find_tool_names"
exit 1
fi
($find_tool_res --version </dev/null) >/dev/null 2>&1 || {
echo >&2 "$0: ${find_tool_error_prefix}cannot run $find_tool_res --version"
exit 1
}
eval "$find_tool_envvar=\$find_tool_res"
eval "export $find_tool_envvar"
}
# Find sha1sum, named gsha1sum on MacPorts, and shasum on MacOS 10.6.
find_tool SHA1SUM sha1sum gsha1sum shasum
# Override the default configuration, if necessary.
# Make sure that bootstrap.conf is sourced from the current directory
# if we were invoked as "sh bootstrap".
@@ -202,7 +263,7 @@ insert_sorted_if_absent() {
file=$1
str=$2
test -f $file || touch $file
echo "$str" | sort -u - $file | cmp -s - $file \
echo "$str" | sort -u - $file | cmp - $file > /dev/null \
|| echo "$str" | sort -u - $file -o $file \
|| exit 1
}
@@ -229,6 +290,128 @@ if test ! -d $build_aux; then
done
fi
# Note this deviates from the version comparison in automake
# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
# but this should suffice as we won't be specifying old
# version formats or redundant trailing .0 in bootstrap.conf.
# If we did want full compatibility then we should probably
# use m4_version_compare from autoconf.
sort_ver() { # sort -V is not generally available
ver1="$1"
ver2="$2"
# split on '.' and compare each component
i=1
while : ; do
p1=$(echo "$ver1" | cut -d. -f$i)
p2=$(echo "$ver2" | cut -d. -f$i)
if [ ! "$p1" ]; then
echo "$1 $2"
break
elif [ ! "$p2" ]; then
echo "$2 $1"
break
elif [ ! "$p1" = "$p2" ]; then
if [ "$p1" -gt "$p2" ] 2>/dev/null; then # numeric comparison
echo "$2 $1"
elif [ "$p2" -gt "$p1" ] 2>/dev/null; then # numeric comparison
echo "$1 $2"
else # numeric, then lexicographic comparison
lp=$(printf "$p1\n$p2\n" | LANG=C sort -n | tail -n1)
if [ "$lp" = "$p2" ]; then
echo "$1 $2"
else
echo "$2 $1"
fi
fi
break
fi
i=$(($i+1))
done
}
get_version() {
app=$1
$app --version >/dev/null 2>&1 || return 1
$app --version 2>&1 |
sed -n '# extract version within line
s/.*[v ]\{1,\}\([0-9]\{1,\}\.[.a-z0-9-]*\).*/\1/
t done
# extract version at start of line
s/^\([0-9]\{1,\}\.[.a-z0-9-]*\).*/\1/
t done
d
:done
#the following essentially does s/5.005/5.5/
s/\.0*\([1-9]\)/.\1/g
p
q'
}
check_versions() {
ret=0
while read app req_ver; do
# We only need libtoolize from the libtool package.
if test "$app" = libtool; then
app=libtoolize
fi
# Honor $APP variables ($TAR, $AUTOCONF, etc.)
appvar=`echo $app | tr '[a-z]-' '[A-Z]_'`
test "$appvar" = TAR && appvar=AMTAR
eval "app=\${$appvar-$app}"
inst_ver=$(get_version $app)
if [ ! "$inst_ver" ]; then
echo "Error: '$app' not found" >&2
ret=1
elif [ ! "$req_ver" = "-" ]; then
latest_ver=$(sort_ver $req_ver $inst_ver | cut -d' ' -f2)
if [ ! "$latest_ver" = "$inst_ver" ]; then
echo "Error: '$app' version == $inst_ver is too old" >&2
echo " '$app' version >= $req_ver is required" >&2
ret=1
fi
fi
done
return $ret
}
print_versions() {
echo "Program Min_version"
echo "----------------------"
printf %s "$buildreq"
echo "----------------------"
# can't depend on column -t
}
use_libtool=0
# We'd like to use grep -E, to see if any of LT_INIT,
# AC_PROG_LIBTOOL, AM_PROG_LIBTOOL is used in configure.ac,
# but that's not portable enough (e.g., for Solaris).
grep '^[ ]*A[CM]_PROG_LIBTOOL' configure.ac >/dev/null \
&& use_libtool=1
grep '^[ ]*LT_INIT' configure.ac >/dev/null \
&& use_libtool=1
if test $use_libtool = 1; then
find_tool LIBTOOLIZE glibtoolize libtoolize
fi
if ! printf "$buildreq" | check_versions; then
echo >&2
if test -f README-prereq; then
echo "See README-prereq for how to get the prerequisite programs" >&2
else
echo "Please install the prerequisite programs" >&2
fi
exit 1
fi
echo "$0: Bootstrapping from checked-out $package sources..."
# See if we can use gnulib's git-merge-changelog merge driver.
@@ -245,13 +428,13 @@ if test -d .git && (git --version) >/dev/null 2>/dev/null ; then
fi
cleanup() {
status=$?
rm -fr $1
exit $status
status=$?
rm -fr $1
exit $status
}
git_modules_config () {
GIT_CONFIG_LOCAL=.gitmodules git config "$@"
cleanup_gnulib() {
cleanup "$gnulib_path"
}
# Get paxutils files.
@@ -276,6 +459,12 @@ if [ -r $PAXUTILS_SRCDIR/gnulib.modules ]; then
`
fi
git_modules_config () {
test -f .gitmodules && git config --file .gitmodules "$@"
}
gnulib_path=`git_modules_config submodule.gnulib.path`
: ${gnulib_path:=gnulib}
# Get gnulib files.
case ${GNULIB_SRCDIR--} in
@@ -285,30 +474,44 @@ case ${GNULIB_SRCDIR--} in
git submodule init || exit $?
git submodule update || exit $?
elif [ ! -d gnulib ]; then
elif [ ! -d "$gnulib_path" ]; then
echo "$0: getting gnulib files..."
trap cleanup_gnulib 1 2 13 15
git clone --help|grep depth > /dev/null && shallow='--depth 2' || shallow=
git clone $shallow git://git.sv.gnu.org/gnulib ||
"cleanup $1"
shallow=
git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2'
git clone $shallow git://git.sv.gnu.org/gnulib "$gnulib_path" ||
cleanup_gnulib
trap - 1 2 13 15
fi
GNULIB_SRCDIR=gnulib
GNULIB_SRCDIR=$gnulib_path
;;
*)
# Redirect the gnulib submodule to the directory on the command line
# if possible.
# Use GNULIB_SRCDIR as a reference.
if test -d "$GNULIB_SRCDIR"/.git && \
git_modules_config submodule.gnulib.url >/dev/null; then
git submodule init
GNULIB_SRCDIR=`cd $GNULIB_SRCDIR && pwd`
git config --replace-all submodule.gnulib.url $GNULIB_SRCDIR
git_modules_config submodule.gnulib.url >/dev/null; then
echo "$0: getting gnulib files..."
git submodule update || exit $?
GNULIB_SRCDIR=gnulib
if git submodule -h|grep -- --reference > /dev/null; then
# Prefer the one-liner available in git 1.6.4 or newer.
git submodule update --init --reference "$GNULIB_SRCDIR" \
"$gnulib_path" || exit $?
else
# This fallback allows at least git 1.5.5.
if test -f "$gnulib_path"/gnulib-tool; then
# Since file already exists, assume submodule init already complete.
git submodule update || exit $?
else
# Older git can't clone into an empty directory.
rmdir "$gnulib_path" 2>/dev/null
git clone --reference "$GNULIB_SRCDIR" \
"$(git_modules_config submodule.gnulib.url)" "$gnulib_path" \
&& git submodule init && git submodule update \
|| exit $?
fi
fi
GNULIB_SRCDIR=$gnulib_path
fi
;;
esac
@@ -326,22 +529,24 @@ download_po_files() {
eval "$cmd"
}
# Download .po files to $po_dir/.reference and copy only the new
# Mirror .po files to $po_dir/.reference and copy only the new
# or modified ones into $po_dir. Also update $po_dir/LINGUAS.
# Note po files that exist locally only are left in $po_dir but will
# not be included in LINGUAS and hence will not be distributed.
update_po_files() {
# Directory containing primary .po files.
# Overwrite them only when we're sure a .po file is new.
po_dir=$1
domain=$2
# Download *.po files into this dir.
# Mirror *.po files into this dir.
# Usually contains *.s1 checksum files.
ref_po_dir="$po_dir/.reference"
test -d $ref_po_dir || mkdir $ref_po_dir || return
download_po_files $ref_po_dir $domain \
&& ls "$ref_po_dir"/*.po 2>/dev/null |
sed 's|.*/||; s|\.po$||' > "$po_dir/LINGUAS"
sed 's|.*/||; s|\.po$||' > "$po_dir/LINGUAS" || return
langs=`cd $ref_po_dir && echo *.po|sed 's/\.po//g'`
test "$langs" = '*' && langs=x
@@ -350,10 +555,12 @@ update_po_files() {
new_po="$ref_po_dir/$po.po"
cksum_file="$ref_po_dir/$po.s1"
if ! test -f "$cksum_file" ||
! test -f "$po_dir/$po.po" ||
! sha1sum -c --status "$cksum_file" < "$new_po" > /dev/null; then
! test -f "$po_dir/$po.po" ||
! $SHA1SUM -c --status "$cksum_file" \
< "$new_po" > /dev/null; then
echo "updated $po_dir/$po.po..."
cp "$new_po" "$po_dir/$po.po" && sha1sum < "$new_po" > "$cksum_file"
cp "$new_po" "$po_dir/$po.po" \
&& $SHA1SUM < "$new_po" > "$cksum_file"
fi
done
}
@@ -387,46 +594,46 @@ symlink_to_dir()
# FIXME: for now, this does only one level
parent=`dirname "$dst_dir"`
for dot_ig in x $vc_ignore; do
test $dot_ig = x && continue
ig=$parent/$dot_ig
insert_sorted_if_absent $ig `echo "$dst_dir"|sed 's,.*/,,'`
test $dot_ig = x && continue
ig=$parent/$dot_ig
insert_sorted_if_absent $ig `echo "$dst_dir"|sed 's,.*/,,'`
done
fi
if $copy; then
{
test ! -h "$dst" || {
echo "$0: rm -f $dst" &&
rm -f "$dst"
}
test ! -h "$dst" || {
echo "$0: rm -f $dst" &&
rm -f "$dst"
}
} &&
test -f "$dst" &&
cmp -s "$src" "$dst" || {
echo "$0: cp -fp $src $dst" &&
cp -fp "$src" "$dst"
echo "$0: cp -fp $src $dst" &&
cp -fp "$src" "$dst"
}
else
test -h "$dst" &&
src_ls=`ls -diL "$src" 2>/dev/null` && set $src_ls && src_i=$1 &&
dst_ls=`ls -diL "$dst" 2>/dev/null` && set $dst_ls && dst_i=$1 &&
test "$src_i" = "$dst_i" || {
dot_dots=
case $src in
/*) ;;
*)
case /$dst/ in
/./*) ;;
*//* | */../* | */./* | /*/*/*/*/*/)
echo >&2 "$0: invalid symlink calculation: $src -> $dst"
exit 1;;
/*/*/*/*/) dot_dots=../../../;;
/*/*/*/) dot_dots=../../;;
/*/*/) dot_dots=../;;
esac;;
esac
dot_dots=
case $src in
/*) ;;
*)
case /$dst/ in
/./*) ;;
*//* | */../* | */./* | /*/*/*/*/*/)
echo >&2 "$0: invalid symlink calculation: $src -> $dst"
exit 1;;
/*/*/*/*/) dot_dots=../../../;;
/*/*/*/) dot_dots=../../;;
/*/*/) dot_dots=../;;
esac;;
esac
echo "$0: ln -fs $dot_dots$src $dst" &&
ln -fs "$dot_dots$src" "$dst"
echo "$0: ln -fs $dot_dots$src $dst" &&
ln -fs "$dot_dots$src" "$dst"
}
fi
}
@@ -456,28 +663,28 @@ cp_mark_as_generated()
if test -z "$c1"; then
cmp -s "$cp_src" "$cp_dst" || {
# Copy the file first to get proper permissions if it
# doesn't already exist. Then overwrite the copy.
echo "$0: cp -f $cp_src $cp_dst" &&
rm -f "$cp_dst" &&
cp "$cp_src" "$cp_dst-t" &&
sed "s!$bt_regex/!!g" "$cp_src" > "$cp_dst-t" &&
mv -f "$cp_dst-t" "$cp_dst"
# Copy the file first to get proper permissions if it
# doesn't already exist. Then overwrite the copy.
echo "$0: cp -f $cp_src $cp_dst" &&
rm -f "$cp_dst" &&
cp "$cp_src" "$cp_dst-t" &&
sed "s!$bt_regex/!!g" "$cp_src" > "$cp_dst-t" &&
mv -f "$cp_dst-t" "$cp_dst"
}
else
# Copy the file first to get proper permissions if it
# doesn't already exist. Then overwrite the copy.
cp "$cp_src" "$cp_dst-t" &&
(
echo "$c1-*- buffer-read-only: t -*- vi: set ro:$c2" &&
echo "${c1}DO NOT EDIT! GENERATED AUTOMATICALLY!$c2" &&
sed "s!$bt_regex/!!g" "$cp_src"
echo "$c1-*- buffer-read-only: t -*- vi: set ro:$c2" &&
echo "${c1}DO NOT EDIT! GENERATED AUTOMATICALLY!$c2" &&
sed "s!$bt_regex/!!g" "$cp_src"
) > $cp_dst-t &&
if cmp -s "$cp_dst-t" "$cp_dst"; then
rm -f "$cp_dst-t"
rm -f "$cp_dst-t"
else
echo "$0: cp $cp_src $cp_dst # with edits" &&
mv -f "$cp_dst-t" "$cp_dst"
echo "$0: cp $cp_src $cp_dst # with edits" &&
mv -f "$cp_dst-t" "$cp_dst"
fi
fi
fi
@@ -489,7 +696,7 @@ version_controlled_file() {
found=no
if test -d CVS; then
grep -F "/$file/" $dir/CVS/Entries 2>/dev/null |
grep '^/[^/]*/[0-9]' > /dev/null && found=yes
grep '^/[^/]*/[0-9]' > /dev/null && found=yes
elif test -d .git; then
git rm -n "$dir/$file" > /dev/null 2>&1 && found=yes
elif test -d .svn; then
@@ -507,39 +714,42 @@ slurp() {
for file in `ls -a $1/$dir`; do
case $file in
.|..) continue;;
.*) continue;; # FIXME: should all file names starting with "." be ignored?
# FIXME: should all file names starting with "." be ignored?
.*) continue;;
esac
test -d $1/$dir/$file && continue
for excluded_file in $excluded_files; do
test "$dir/$file" = "$excluded_file" && continue 2
test "$dir/$file" = "$excluded_file" && continue 2
done
if test $file = Makefile.am; then
if test $file = Makefile.am && test "X$gnulib_mk" != XMakefile.am; then
copied=$copied${sep}$gnulib_mk; sep=$nl
remove_intl='/^[^#].*\/intl/s/^/#/;'"s!$bt_regex/!!g"
sed "$remove_intl" $1/$dir/$file | cmp -s - $dir/$gnulib_mk || {
echo "$0: Copying $1/$dir/$file to $dir/$gnulib_mk ..." &&
rm -f $dir/$gnulib_mk &&
sed "$remove_intl" $1/$dir/$file >$dir/$gnulib_mk
}
remove_intl='/^[^#].*\/intl/s/^/#/;'"s!$bt_regex/!!g"
sed "$remove_intl" $1/$dir/$file |
cmp - $dir/$gnulib_mk > /dev/null || {
echo "$0: Copying $1/$dir/$file to $dir/$gnulib_mk ..." &&
rm -f $dir/$gnulib_mk &&
sed "$remove_intl" $1/$dir/$file >$dir/$gnulib_mk &&
gnulib_mk_hook $dir/$gnulib_mk
}
elif { test "${2+set}" = set && test -r $2/$dir/$file; } ||
version_controlled_file $dir $file; then
echo "$0: $dir/$file overrides $1/$dir/$file"
version_controlled_file $dir $file; then
echo "$0: $dir/$file overrides $1/$dir/$file"
else
copied=$copied$sep$file; sep=$nl
if test $file = gettext.m4; then
echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
rm -f $dir/$file
sed '
/^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
AC_DEFUN([AM_INTL_SUBDIR], [
/^AC_DEFUN(\[gt_INTL_SUBDIR_CORE],/,/^]/c\
AC_DEFUN([gt_INTL_SUBDIR_CORE], [])
$a\
AC_DEFUN([gl_LOCK_EARLY], [])
' $1/$dir/$file >$dir/$file
else
cp_mark_as_generated $1/$dir/$file $dir/$file
fi
copied=$copied$sep$file; sep=$nl
if test $file = gettext.m4; then
echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
rm -f $dir/$file
sed '
/^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
AC_DEFUN([AM_INTL_SUBDIR], [])
/^AC_DEFUN(\[gt_INTL_SUBDIR_CORE],/,/^]/c\
AC_DEFUN([gt_INTL_SUBDIR_CORE], [])
$a\
AC_DEFUN([gl_LOCK_EARLY], [])
' $1/$dir/$file >$dir/$file
else
cp_mark_as_generated $1/$dir/$file $dir/$file
fi
fi || exit
done
@@ -547,18 +757,25 @@ slurp() {
test $dot_ig = x && continue
ig=$dir/$dot_ig
if test -n "$copied"; then
insert_sorted_if_absent $ig "$copied"
# If an ignored file name ends with .in.h, then also add
# the name with just ".h". Many gnulib headers are generated,
# e.g., stdint.in.h -> stdint.h, dirent.in.h ->..., etc.
# Likewise for .gperf -> .h, .y -> .c, and .sin -> .sed
f=`echo "$copied"|sed 's/\.in\.h$/.h/;s/\.sin$/.sed/;s/\.y$/.c/;s/\.gperf$/.h/'`
insert_sorted_if_absent $ig "$f"
insert_sorted_if_absent $ig "$copied"
# If an ignored file name ends with .in.h, then also add
# the name with just ".h". Many gnulib headers are generated,
# e.g., stdint.in.h -> stdint.h, dirent.in.h ->..., etc.
# Likewise for .gperf -> .h, .y -> .c, and .sin -> .sed
f=`echo "$copied" |
sed '
s/\.in\.h$/.h/
s/\.sin$/.sed/
s/\.y$/.c/
s/\.gperf$/.h/
'
`
insert_sorted_if_absent $ig "$f"
# For files like sys_stat.in.h and sys_time.in.h, record as
# ignorable the directory we might eventually create: sys/.
f=`echo "$copied"|sed 's/sys_.*\.in\.h$/sys/'`
insert_sorted_if_absent $ig "$f"
# For files like sys_stat.in.h and sys_time.in.h, record as
# ignorable the directory we might eventually create: sys/.
f=`echo "$copied"|sed 's/sys_.*\.in\.h$/sys/'`
insert_sorted_if_absent $ig "$f"
fi
done
done
@@ -583,6 +800,12 @@ gnulib_tool_options="\
--local-dir $local_gl_dir\
$gnulib_tool_option_extras\
"
if test $use_libtool = 1; then
case "$gnulib_tool_options " in
*' --libtool '*) ;;
*) gnulib_tool_options="$gnulib_tool_options --libtool" ;;
esac
fi
echo "$0: $gnulib_tool $gnulib_tool_options --import ..."
$gnulib_tool $gnulib_tool_options --import $gnulib_modules &&
slurp $bt || exit
@@ -598,9 +821,9 @@ grep '^[ ]*AM_GNU_GETTEXT_VERSION(' configure.ac >/dev/null || \
with_gettext=no
if test $with_gettext = yes; then
echo "$0: (cd $bt2; autopoint) ..."
echo "$0: (cd $bt2; ${AUTOPOINT-autopoint}) ..."
cp configure.ac $bt2 &&
(cd $bt2 && autopoint && rm configure.ac) &&
(cd $bt2 && ${AUTOPOINT-autopoint} && rm configure.ac) &&
slurp $bt2 $bt || exit
fi
rm -fr $bt $bt2 || exit
@@ -617,6 +840,8 @@ find "$m4_base" "$source_base" \
-depth \( -name '*.m4' -o -name '*.[ch]' \) \
-type l -xtype l -delete > /dev/null 2>&1
# Reconfigure, getting other files.
# copy_files srcdir dstdir
copy_files() {
for file in `cat $1/DISTFILES`
@@ -661,27 +886,22 @@ done
copy_files ${PAXUTILS_SRCDIR}/paxlib lib pax
# Reconfigure, getting other files.
# Skip autoheader if it's not needed.
grep -E '^[ ]*AC_CONFIG_HEADERS?\>' configure.ac >/dev/null ||
AUTOHEADER=true
for command in \
libtool \
'aclocal --force -I m4' \
'autoconf --force' \
'autoheader --force' \
'automake --add-missing --copy --force-missing';
"${ACLOCAL-aclocal} --force -I m4 $ACLOCAL_FLAGS" \
"${AUTOCONF-autoconf} --force" \
"${AUTOHEADER-autoheader} --force" \
"${AUTOMAKE-automake} --add-missing --copy --force-missing"
do
if test "$command" = libtool; then
use_libtool=0
# We'd like to use grep -E, to see if any of LT_INIT,
# AC_PROG_LIBTOOL, AM_PROG_LIBTOOL is used in configure.ac,
# but that's not portable enough (e.g., for Solaris).
grep '^[ ]*A[CM]_PROG_LIBTOOL' configure.ac >/dev/null \
&& use_libtool=1
grep '^[ ]*LT_INIT' configure.ac >/dev/null \
&& use_libtool=1
test $use_libtool = 0 \
&& continue
command='libtoolize -c -f'
command="${LIBTOOLIZE-libtoolize} -c -f"
fi
echo "$0: $command ..."
$command || exit
@@ -704,13 +924,14 @@ if test $with_gettext = yes; then
rm -f po/Makevars
sed '
/^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/
/^MSGID_BUGS_ADDRESS *=/s/=.*/= '"$MSGID_BUGS_ADDRESS"'/
/^COPYRIGHT_HOLDER *=/s/=.*/= '"$COPYRIGHT_HOLDER"'/
/^MSGID_BUGS_ADDRESS *=/s|=.*|= '"$MSGID_BUGS_ADDRESS"'|
/^XGETTEXT_OPTIONS *=/{
s/$/ \\/
a\
'"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
'"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
}
' po/Makevars.template >po/Makevars
' po/Makevars.template >po/Makevars || exit 1
if test -d runtime-po; then
# Similarly for runtime-po/Makevars, but not quite the same.
@@ -720,15 +941,25 @@ if test $with_gettext = yes; then
/^subdir *=.*/s/=.*/= runtime-po/
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
/^XGETTEXT_OPTIONS *=/{
s/$/ \\/
a\
'"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
s/$/ \\/
a\
'"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
}
' <po/Makevars.template >runtime-po/Makevars
' po/Makevars.template >runtime-po/Makevars || exit 1
# Copy identical files from po to runtime-po.
(cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po)
fi
fi
bootstrap_epilogue
echo "$0: done. Now you can run './configure'."
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -19,12 +19,12 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
AC_INIT([GNU tar], [1.23], [bug-tar@gnu.org])
AC_INIT([GNU tar], [1.26], [bug-tar@gnu.org])
AC_CONFIG_SRCDIR([src/tar.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_PREREQ([2.63])
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-shar std-options silent-rules])
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-xz dist-shar std-options silent-rules])
# Enable silent rules by default:
AM_SILENT_RULES([yes])
@@ -40,8 +40,8 @@ AC_ISC_POSIX
AC_C_INLINE
AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h memory.h net/errno.h \
sgtty.h string.h stropts.h \
sys/param.h sys/device.h sys/filio.h sys/gentape.h \
sgtty.h string.h \
sys/param.h sys/device.h sys/gentape.h \
sys/inet.h sys/io/trioctl.h \
sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
unistd.h locale.h)
@@ -90,7 +90,7 @@ gl_INIT
# paxutils modules
tar_PAXUTILS
AC_CHECK_FUNCS(fsync getdtablesize lstat mkfifo readlink symlink setlocale utimes)
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
AC_CHECK_DECLS([time],,, [#include <time.h>])

View File

@@ -65,7 +65,7 @@ programs (using pipes); tar can even access remote devices or files
%%contributors: Jay Fenlason,
Joy Kendall,
Francois Pinard <pinard@iro.umontreal.ca>
%%source-tarball: ftp://ftp.gnu.org/pub/gnu/tar/tar-1.15.1.tar.gz
%%source-info: http://savannah.gnu.org/projects/tar
@@ -84,4 +84,3 @@ programs (using pipes); tar can even access remote devices or files
%%bug-list: bug-tar@gnu.org bug-tar@gnu.org http://mail.gnu.org/mailman/listinfo/bug-tar
%%entry-written-by: Sergey Poznyakoff <gray@gnu.org>

2
doc/.gitignore vendored
View File

@@ -1,7 +1,7 @@
genfile.texi
getdate.texi
header.texi
manual
parse-datetime.texi
stamp-vti
tar.aux
tar.cp

View File

@@ -24,9 +24,9 @@ tar_TEXINFOS = \
fdl.texi\
freemanuals.texi\
genfile.texi\
getdate.texi\
header.texi\
intern.texi\
parse-datetime.texi\
rendition.texi\
snapshot.texi\
sparse.texi\
@@ -124,7 +124,7 @@ check-unrevised:
all-check-docs: check-format check-options check-refs check-fixmes check-unrevised
check-docs:
check-docs:
$(MAKE) -k all-check-docs
#
@@ -144,4 +144,3 @@ manual:
MAKEINFO="$(MAKEINFO) $(MAKEINFOFLAGS)" \
TEXI2DVI="$(TEXI2DVI) -t @finalout" \
$(GENDOCS) --texi2html tar 'GNU tar manual'

View File

@@ -16,7 +16,7 @@ dumped directory in special data blocks called @dfn{dumpdirs}.
@noindent
where @var{C} is one of the @dfn{control codes} described below,
@var{filename} is the name of the file @var{C} operates upon, and
@samp{\0} represents a nul character (ASCII 0). The white space
@samp{\0} represents a nul character (ASCII 0). The white space
characters were added for readability, real dumpdirs do not contain
them.
@@ -68,7 +68,7 @@ directory}. For example, consider the following scenario:
@enumerate 1
@item
Previous run dumped a directory @file{foo} which contained the
following three directories:
following three directories:
@smallexample
a
@@ -93,7 +93,7 @@ New incremental dump was made.
renaming @file{a} to @file{b} will destroy the existing directory.
To correctly process it, @GNUTAR{} needs a temporary directory, so
it creates the following dumpdir (newlines have been added for
readability):
readability):
@smallexample
@group
@@ -114,7 +114,7 @@ work as usual, and, finally, the last command, @samp{R\0Tfoo/a\0}
tells tar to rename the temporary directory to @file{foo/a}.
The exact placement of a dumpdir in the archive depends on the
archive format (@pxref{Formats}):
archive format (@pxref{Formats}):
@itemize
@item PAX archives

View File

@@ -1,13 +1,12 @@
@c The GNU Free Documentation License.
@center Version 1.3, 3 November 2008
@node GNU Free Documentation License
@appendixsec GNU Free Documentation License
@cindex FDL, GNU Free Documentation License
@center Version 1.2, November 2002
@c This file is intended to be included within another document,
@c hence no sectioning command or @node.
@display
Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
@uref{http://fsf.org/}
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -93,16 +92,16 @@ An image format is not Transparent if used for any substantial amount
of text. A copy that is not ``Transparent'' is called ``Opaque''.
Examples of suitable formats for Transparent copies include plain
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
format, @acronym{SGML} or @acronym{XML} using a publicly available
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
PostScript or @acronym{PDF} designed for human modification. Examples
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
@acronym{JPG}. Opaque formats include proprietary formats that can be
read and edited only by proprietary word processors, @acronym{SGML} or
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
not generally available, and the machine-generated @acronym{HTML},
PostScript or @acronym{PDF} produced by some word processors for
ASCII without markup, Texinfo input format, La@TeX{} input
format, SGML or XML using a publicly available
DTD, and standard-conforming simple HTML,
PostScript or PDF designed for human modification. Examples
of transparent image formats include PNG, XCF and
JPG. Opaque formats include proprietary formats that can be
read and edited only by proprietary word processors, SGML or
XML for which the DTD and/or processing tools are
not generally available, and the machine-generated HTML,
PostScript or PDF produced by some word processors for
output purposes only.
The ``Title Page'' means, for a printed book, the title page itself,
@@ -112,6 +111,9 @@ formats which do not have any title page as such, ``Title Page'' means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
The ``publisher'' means any person or entity that distributes copies
of the Document to the public.
A section ``Entitled XYZ'' means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
@@ -380,13 +382,30 @@ title.
@item
TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
You may not copy, modify, sublicense, or distribute the Document
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense, or distribute it is void, and
will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license
from a particular copyright holder is reinstated (a) provisionally,
unless and until the copyright holder explicitly and finally
terminates your license, and (b) permanently, if the copyright holder
fails to notify you of the violation by some reasonable means prior to
60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, receipt of a copy of some or all of the same material does
not give you any rights to use it.
@item
FUTURE REVISIONS OF THIS LICENSE
@@ -404,11 +423,46 @@ following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
as a draft) by the Free Software Foundation. If the Document
specifies that a proxy can decide which future versions of this
License can be used, that proxy's public statement of acceptance of a
version permanently authorizes you to choose that version for the
Document.
@item
RELICENSING
``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
World Wide Web server that publishes copyrightable works and also
provides prominent facilities for anybody to edit those works. A
public wiki that anybody can edit is an example of such a server. A
``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
site means any set of copyrightable works thus published on the MMC
site.
``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
license published by Creative Commons Corporation, a not-for-profit
corporation with a principal place of business in San Francisco,
California, as well as future copyleft versions of that license
published by that same organization.
``Incorporate'' means to publish or republish a Document, in whole or
in part, as part of another Document.
An MMC is ``eligible for relicensing'' if it is licensed under this
License, and if all works that were first published under this License
somewhere other than this MMC, and subsequently incorporated in whole
or in part into the MMC, (1) had no cover texts or invariant sections,
and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site
under CC-BY-SA on the same site at any time before August 1, 2009,
provided the MMC is eligible for relicensing.
@end enumerate
@page
@appendixsubsec ADDENDUM: How to use this License for your documents
@heading ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
@@ -418,7 +472,7 @@ license notices just after the title page:
@group
Copyright (C) @var{year} @var{your name}.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
@@ -427,7 +481,7 @@ license notices just after the title page:
@end smallexample
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the ``with...Texts.'' line with this:
replace the ``with@dots{}Texts.'' line with this:
@smallexample
@group

View File

@@ -36,7 +36,7 @@
<p>The manual for %%PACKAGE%% is available in the following formats:</p>
<ul>
<li><a href="%%PACKAGE%%.html">HTML
<li><a href="%%PACKAGE%%.html">HTML
(%%HTML_MONO_SIZE%%K bytes)</a> - entirely on one web page.</li>
<li><a href="html_node/index.html">HTML</a> - with one web page per
node.</li>
@@ -49,7 +49,7 @@
chapter.</li>
%%ENDIF HTML_CHAPTER%%
<li><a href="%%PACKAGE%%.html.gz">HTML compressed
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
one web page.</li>
<li><a href="%%PACKAGE%%.html_node.tar.gz">HTML compressed
(%%HTML_NODE_TGZ_SIZE%%K gzipped tar file)</a> -
@@ -96,9 +96,9 @@ Return to the <a href="/home.html">GNU Project home page</a>.
</p>
<p>
Please send FSF &amp; GNU inquiries to
Please send FSF &amp; GNU inquiries to
<a href="mailto:gnu@gnu.org"><em>gnu@gnu.org</em></a>.
There are also <a href="/home.html#ContactInfo">other ways to contact</a>
There are also <a href="/home.html#ContactInfo">other ways to contact</a>
the FSF.
<br />
Please send broken links and other corrections (or suggestions) to

View File

@@ -107,10 +107,10 @@ group permission could be copied from the @emph{other} permission.
The @code{uid} and @code{gid} fields are the numeric user and group
@acronym{ID} of the file owners, respectively. If the operating system does
not support numeric user or group @acronym{ID}s, these fields should
be ignored.
be ignored.
The @code{size} field is the size of the file in bytes; linked files
are archived with this field specified as zero.
are archived with this field specified as zero.
The @code{mtime} field is the data modification time of the file at
the time it was archived. It is the ASCII representation of the octal
@@ -330,4 +330,3 @@ checksum error.
@node Dumpdir
@unnumberedsec Dumpdir
@include dumpdir.texi

View File

@@ -27,11 +27,11 @@
;; This file redefines texinfo-master-menu-list so that it takes into
;; account included files.
;; Known bugs: @menu without previous sectioning command will inherit
;; Known bugs: @menu without previous sectioning command will inherit
;; documentation string from the previous menu. However, since such a
;; menu is illegal in a texinfo file, we can live with it.
(require 'texinfo)
(require 'texinfo)
(require 'texnfo-upd)
(defun texinfo-master-menu-list-recursive (title)

View File

@@ -137,4 +137,3 @@ previous versions it is not quoted;
@end enumerate
@c End of snapshot.texi

View File

@@ -232,4 +232,3 @@ into a separate directory. Then, using a simple program it would be
possible to expand the file to its original form even without @GNUTAR{}.
@xref{Sparse Recovery}, for the detailed information on how to extract
sparse members without @GNUTAR{}.

View File

@@ -55,4 +55,3 @@ file version 2
$ @kbd{tar-snapshot-edit -b -r 0x0306-0x4500 /var/backup/snap.a}
file version 2
@end smallexample

File diff suppressed because it is too large Load Diff

View File

@@ -18,5 +18,3 @@
@end ifclear
@xopindex{\option\, summary}
@end macro

View File

@@ -6,19 +6,19 @@ argmatch
argp
argp-version-etc
backupfile
canonicalize
closeout
configmake
dirname
error
exclude
exitfail
fdopendir
fdutimensat
fileblocks
fnmatch-gnu
fseeko
ftruncate
full-write
getdate
futimens
getline
getopt-gnu
getpagesize
@@ -27,19 +27,25 @@ gettime
gitlog-to-changelog
hash
human
inttostr
inttypes
lchown
linkat
localcharset
mkdtemp
mkfifoat
modechange
obstack
openat
parse-datetime
priv-set
progname
quote
quotearg
readlinkat
renameat
rpmatch
safe-read
save-cwd
savedir
setenv
snprintf
@@ -51,10 +57,11 @@ strdup-posix
strerror
strtol
strtoul
symlinkat
timespec
unlinkdir
unlocked-io
utimens
utimensat
version-etc-fsf
xalloc
xalloc-die

View File

@@ -26,14 +26,13 @@ rmt-command.h : Makefile
$(AM_V_at)mv $@-t $@
BUILT_SOURCES = rmt-command.h
CLEANFILES = rmt-command.h rmt-command.h-t
INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu
INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu
noinst_HEADERS = system.h system-ioctl.h rmt.h paxlib.h stdopen.h
libtar_a_SOURCES = \
paxerror.c paxexit.c paxlib.h paxnames.c \
paxerror.c paxexit-status.c paxlib.h paxnames.c \
prepargs.c prepargs.h \
rtapelib.c \
rmt.h \
stdopen.c stdopen.h \
system.h system-ioctl.h

View File

@@ -37,7 +37,6 @@ gnu/version-etc.c
gnu/xalloc-die.c
lib/paxerror.c
lib/paxexit.c
lib/paxnames.c
lib/rtapelib.c

View File

@@ -65,9 +65,9 @@ XLIST=exclude_files
SLEEP_TIME=15
# Script to be run when it's time to insert a new tape in for the next
# volume. Administrators may want to tailor this script for their site.
# volume. Administrators may want to tailor this script for their site.
# If this variable isn't set, tar will use some default behavior which is
# probably defined in the manual.
# probably defined in the manual.
#DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind'
# Message to display on the terminal while waiting for dump time. Usually
@@ -75,7 +75,7 @@ SLEEP_TIME=15
# entertaining than this. The awk script here saves some redundant
# repetition, but is not really all that desirable.
SLEEP_MESSAGE="`awk '
BEGIN {
BEGIN {
for (i = 0; i < 30; i++)
print \" \" \
\"D O N O T T O U C H T H I S T E R M I N A L !!!!!\"

View File

@@ -72,8 +72,9 @@ do
--l=*|--le=*|--lev=*|--leve=*|--level=*)
DUMP_LEVEL=$optarg
;;
-l?*) DUMP_LEVEL=`expr $option : '-l\(.*\)'`;;
-l|--l|--le|--lev|--leve|--level)
prev=$option
prev=--level
;;
--verb=*|--verbo=*|--verbos=*|--verbose=*)
VERBOSE=$optarg
@@ -81,14 +82,13 @@ do
-v|--verb|--verbo|--verbos|--verbose)
VERBOSE=100
;;
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
-v*) VERBOSE=`expr $option : '-v\(.*\)'`;;
--t=*|--ti=*|--tim=*|--time=*)
TIME=$optarg
;;
-t) prev=--t;;
-t*) TIME=`expr $option : "-t\(.*\)"`;;
--t|--ti|--tim|--time)
prev=$option
-t?*) TIME=`expr $option : '-t\(.*\)'`;;
-t|--t|--ti|--tim|--time)
prev=--time
;;
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "backup (@PACKAGE_NAME@) @VERSION@"

View File

@@ -2,14 +2,14 @@
# This file is included in the GNU tar distribution as an example. It is
# not used by default unless the proper line is uncommented in backup-specs.
# System administrators will probably want to customize this and
# backup-specs for their site.
# backup-specs for their site.
#
# This script should be run by tar with --info-script (-F) to inform
# interested parties that a tape for the next volume of the backup needs to
# be put in the tape drive.
# be put in the tape drive.
#
# Include location of `sendmail' and GNU finger.
# Include location of `sendmail' and GNU finger.
PATH="/usr/lib:/usr/local/gnubin:${PATH}"
export PATH
@@ -27,7 +27,7 @@ MT_OFFLINE
#
# Certain users (like `root') aren't real users, and shouldn't be notified.
# Neither should `zippy', `elvis', etc. (on the GNU machines) since they're
# just test accounts.
# just test accounts.
recipients="`
finger .clients 2> /dev/null \
| sed -ne '
@@ -69,8 +69,8 @@ Cc: ${ADMINISTRATOR}
Subject: Backup needs new tape for volume ${TAR_VOLUME}
Reply-To: ${ADMINISTRATOR}
This is an automated report from the backup script running on
`hostname`.
This is an automated report from the backup script running on
`hostname`.
Volume ${TAR_VOLUME} of the backup needs to be put in the tape drive.
Usually whoever prepared the backup leaves labeled tapes on top of the
@@ -92,8 +92,8 @@ Cc: ${ADMINISTRATOR}
Subject: Volume ${TAR_VOLUME} for backup has been added
Reply-To: ${ADMINISTRATOR}
This is an automated report from the backup script running on
`hostname`.
This is an automated report from the backup script running on
`hostname`.
The backup has been continued, so for now no further attention is required.
__EOF__

View File

@@ -60,8 +60,9 @@ do
--l=*|--le=*|--lev=*|--leve=*|--level=*)
DUMP_LEVEL=$optarg
;;
-l?*) DUMP_LEVEL=`expr $option : '-l\(.*\)'`;;
-l|--l|--le|--lev|--leve|--level)
prev=$option
prev=--level
;;
--verb=*|--verbo=*|--verbos=*|--verbose=*)
VERBOSE=$optarg
@@ -69,7 +70,7 @@ do
-v|--verb|--verbo|--verbos|--verbose)
VERBOSE=100
;;
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
-v*) VERBOSE=`expr $option : '-v\(.*\)'`;;
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "restore (@PACKAGE_NAME@) @VERSION@"
license

View File

@@ -211,7 +211,7 @@ sub write_incr_db ($$) {
sub write_incr_db_0 ($$) {
my $info = shift;
my $file = shift;
my $timestamp_sec = $info->[1];
print $file "$timestamp_sec\n";
@@ -226,7 +226,7 @@ sub write_incr_db_0 ($$) {
sub write_incr_db_1 ($$) {
my $info = shift;
my $file = shift;
print $file "GNU tar-1.15-1\n";
my $timestamp_sec = $info->[1];
@@ -246,7 +246,7 @@ sub write_incr_db_1 ($$) {
sub write_incr_db_2 ($$) {
my $info = shift;
my $file = shift;
print $file "GNU tar-1.16-2\n";
my $timestamp_sec = $info->[1];

View File

@@ -35,8 +35,7 @@ do
fi
if [ "$T" = "M" ]; then
SKIP=$(($SKIP + 1))
fi
fi
fi
dd skip=$SKIP if="$f"
dd skip=$SKIP if="$f"
done

View File

@@ -1,10 +1,10 @@
/* xsparse - expands compressed sparse file images extracted from GNU tar
archives.
Copyright (C) 2006, 2007 Free Software Foundation, Inc.
Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
Written by Sergey Poznyakoff
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
@@ -20,6 +20,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@@ -39,7 +40,7 @@
struct sp_array
{
off_t offset;
size_t numbytes;
off_t numbytes;
};
char *progname;
@@ -129,12 +130,12 @@ get_var (FILE *fp, char **name, char **value)
static char *buffer;
static size_t bufsize = OFF_T_STRSIZE_BOUND;
char *p, *q;
buffer = emalloc (bufsize);
do
{
size_t len, s;
if (!fgets (buffer, bufsize, fp))
return 0;
len = strlen (buffer);
@@ -186,12 +187,12 @@ read_xheader (char *name)
if (verbose)
printf ("Reading extended header file\n");
while (get_var (fp, &kw, &val))
{
if (verbose)
printf ("Found variable GNU.sparse.%s = %s\n", kw, val);
if (expect && strcmp (kw, expect))
die (1, "bad keyword sequence: expected `%s' but found `%s'",
expect, kw);
@@ -226,7 +227,7 @@ read_xheader (char *name)
}
else if (strcmp (kw, "numbytes") == 0)
{
sparse_map[i++].numbytes = string_to_size (val, NULL);
sparse_map[i++].numbytes = string_to_off (val, NULL);
}
else if (strcmp (kw, "map") == 0)
{
@@ -236,7 +237,7 @@ read_xheader (char *name)
if (*val != ',')
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
*val);
sparse_map[i].numbytes = string_to_size (val+1, &val);
sparse_map[i].numbytes = string_to_off (val+1, &val);
if (*val != ',')
{
if (!(*val == 0 && i == sparse_map_size-1))
@@ -267,7 +268,7 @@ read_map (FILE *ifp)
if (verbose)
printf ("Reading v.1.0 sparse map\n");
get_line (nbuf, sizeof nbuf, ifp);
sparse_map_size = string_to_size (nbuf, NULL);
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
@@ -277,31 +278,34 @@ read_map (FILE *ifp)
get_line (nbuf, sizeof nbuf, ifp);
sparse_map[i].offset = string_to_off (nbuf, NULL);
get_line (nbuf, sizeof nbuf, ifp);
sparse_map[i].numbytes = string_to_size (nbuf, NULL);
sparse_map[i].numbytes = string_to_off (nbuf, NULL);
}
fseeko (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
SEEK_SET);
}
}
void
expand_sparse (FILE *sfp, int ofd)
{
size_t i;
size_t maxbytes = 0;
off_t max_numbytes = 0;
size_t maxbytes;
char *buffer;
for (i = 0; i < sparse_map_size; i++)
if (maxbytes < sparse_map[i].numbytes)
maxbytes = sparse_map[i].numbytes;
if (max_numbytes < sparse_map[i].numbytes)
max_numbytes = sparse_map[i].numbytes;
maxbytes = max_numbytes < SIZE_MAX ? max_numbytes : SIZE_MAX;
for (buffer = malloc (maxbytes); !buffer; maxbytes /= 2)
if (maxbytes == 0)
die (1, "not enough memory");
for (i = 0; i < sparse_map_size; i++)
{
size_t size = sparse_map[i].numbytes;
off_t size = sparse_map[i].numbytes;
if (size == 0)
ftruncate (ofd, sparse_map[i].offset);
@@ -342,13 +346,13 @@ guess_outname (char *name)
{
char *p;
char *s;
if (name[0] == '.' && name[1] == '/')
name += 2;
p = name + strlen (name) - 1;
s = NULL;
for (; p > name && *p != '/'; p--)
;
if (*p == '/')
@@ -358,7 +362,7 @@ guess_outname (char *name)
for (p--; p > name && *p != '/'; p--)
;
}
if (*p != '/')
{
if (s)
@@ -389,7 +393,7 @@ main (int argc, char **argv)
FILE *ifp;
struct stat st;
int ofd;
progname = argv[0];
while ((c = getopt (argc, argv, "hnvx:")) != EOF)
{
@@ -408,7 +412,7 @@ main (int argc, char **argv)
case 'v':
verbose++;
break;
default:
exit (1);
}
@@ -429,17 +433,17 @@ main (int argc, char **argv)
if (stat (inname, &st))
die (1, "cannot stat %s (%d)", inname, errno);
ifp = fopen (inname, "r");
if (ifp == NULL)
die (1, "cannot open file %s (%d)", inname, errno);
if (!xheader_file || version_major == 1)
read_map (ifp);
if (!outname)
guess_outname (inname);
ofd = open (outname, O_RDWR|O_CREAT|O_TRUNC, st.st_mode);
if (ofd == -1)
die (1, "cannot open file %s (%d)", outname, errno);
@@ -452,7 +456,7 @@ main (int argc, char **argv)
printf ("Finished dry run\n");
return 0;
}
expand_sparse (ifp, ofd);
fclose (ifp);
@@ -460,7 +464,7 @@ main (int argc, char **argv)
if (verbose)
printf ("Done\n");
if (outsize)
{
if (stat (outname, &st))
@@ -468,7 +472,6 @@ main (int argc, char **argv)
if (st.st_size != outsize)
die (1, "expanded file has wrong size");
}
return 0;
}

View File

@@ -48,4 +48,4 @@ INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)

View File

@@ -22,6 +22,6 @@
blocked in 1 kB boundaries. We'll need arbitrary precision
arithmetic anyway once we get into the 2**64 range, so there's no
point doing anything fancy before then. */
#define TARLONG_FORMAT "%.0f"
typedef double tarlong;

View File

@@ -54,7 +54,7 @@ enum access_mode access_mode; /* how do we handle the archive */
off_t records_read; /* number of records read from this archive */
off_t records_written; /* likewise, for records written */
extern off_t records_skipped; /* number of records skipped at the start
of the archive, defined in delete.c */
of the archive, defined in delete.c */
static off_t record_start_block; /* block ordinal at record_start */
@@ -77,7 +77,6 @@ static bool read_full_records = false;
/* We're reading, but we just read the last block and it's time to update.
Declared in update.c
As least EXTERN like this one as possible. (?? --gray)
FIXME: Either eliminate it or move it to common.h.
*/
extern bool time_to_start_writing;
@@ -101,19 +100,94 @@ static int global_volno = 1; /* volume number to print in external
bool write_archive_to_stdout;
/* Used by flush_read and flush_write to store the real info about saved
names. */
static char *real_s_name;
static off_t real_s_totsize;
static off_t real_s_sizeleft;
/* Multi-volume tracking support */
static char *save_name; /* name of the file we are currently writing */
static off_t save_totsize; /* total size of file we are writing, only
valid if save_name is nonzero */
static off_t save_sizeleft; /* where we are in the file we are writing,
only valid if save_name is nonzero */
/* When creating a multi-volume archive, each `bufmap' represents
a member stored (perhaps partly) in the current record buffer.
After flushing the record to the output media, all bufmaps that
represent fully written members are removed from the list, then
the sizeleft and start numbers in the remaining bufmaps are updated.
When reading from a multi-volume archive, the list degrades to a
single element, which keeps information about the member currently
being read.
*/
struct bufmap
{
struct bufmap *next; /* Pointer to the next map entry */
size_t start; /* Offset of the first data block */
char *file_name; /* Name of the stored file */
off_t sizetotal; /* Size of the stored file */
off_t sizeleft; /* Size left to read/write */
};
static struct bufmap *bufmap_head, *bufmap_tail;
/* This variable, when set, inhibits updating the bufmap chain after
a write. This is necessary when writing extended POSIX headers. */
static int inhibit_map;
void
mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft)
{
if (multi_volume_option)
{
struct bufmap *bp = xmalloc (sizeof bp[0]);
if (bufmap_tail)
bufmap_tail->next = bp;
else
bufmap_head = bp;
bufmap_tail = bp;
bp->next = NULL;
bp->start = current_block - record_start;
bp->file_name = xstrdup (file_name);
bp->sizetotal = totsize;
bp->sizeleft = sizeleft;
}
}
static struct bufmap *
bufmap_locate (size_t off)
{
struct bufmap *map;
for (map = bufmap_head; map; map = map->next)
{
if (!map->next
|| off < map->next->start * BLOCKSIZE)
break;
}
return map;
}
static void
bufmap_free (struct bufmap *mark)
{
struct bufmap *map;
for (map = bufmap_head; map && map != mark; )
{
struct bufmap *next = map->next;
free (map->file_name);
free (map);
map = next;
}
bufmap_head = map;
if (!bufmap_head)
bufmap_tail = bufmap_head;
}
static void
bufmap_reset (struct bufmap *map, ssize_t fixup)
{
bufmap_free (map);
if (map)
{
for (; map; map = map->next)
map->start += fixup;
}
}
static struct tar_stat_info dummy;
@@ -125,32 +199,23 @@ buffer_write_global_xheader ()
}
void
mv_begin (struct tar_stat_info *st)
mv_begin_read (struct tar_stat_info *st)
{
if (multi_volume_option)
{
assign_string (&save_name, st->orig_file_name);
save_totsize = save_sizeleft = st->stat.st_size;
}
mv_begin_write (st->orig_file_name, st->stat.st_size, st->stat.st_size);
}
void
mv_end ()
{
if (multi_volume_option)
assign_string (&save_name, 0);
}
void
mv_total_size (off_t size)
{
save_totsize = size;
bufmap_free (NULL);
}
void
mv_size_left (off_t size)
{
save_sizeleft = size;
if (bufmap_head)
bufmap_head->sizeleft = size;
}
@@ -175,8 +240,8 @@ set_start_time ()
last_stat_time = start_time;
}
void
set_volume_start_time ()
static void
set_volume_start_time (void)
{
gettime (&volume_start_time);
last_stat_time = volume_start_time;
@@ -196,8 +261,8 @@ compute_duration ()
/* Compression detection */
enum compress_type {
ct_tar, /* Plain tar file */
ct_none, /* Unknown compression type */
ct_tar, /* Plain tar file */
ct_compress,
ct_gzip,
ct_bzip2,
@@ -207,34 +272,105 @@ enum compress_type {
ct_xz
};
static enum compress_type archive_compression_type = ct_none;
struct zip_magic
{
enum compress_type type;
size_t length;
char *magic;
char *program;
char *option;
char const *magic;
};
struct zip_program
{
enum compress_type type;
char const *program;
char const *option;
};
static struct zip_magic const magic[] = {
{ ct_tar },
{ ct_none, },
{ ct_compress, 2, "\037\235", COMPRESS_PROGRAM, "-Z" },
{ ct_gzip, 2, "\037\213", GZIP_PROGRAM, "-z" },
{ ct_bzip2, 3, "BZh", BZIP2_PROGRAM, "-j" },
{ ct_lzip, 4, "LZIP", LZIP_PROGRAM, "--lzip" },
{ ct_lzma, 6, "\xFFLZMA", LZMA_PROGRAM, "--lzma" },
{ ct_lzop, 4, "\211LZO", LZOP_PROGRAM, "--lzop" },
{ ct_xz, 6, "\0xFD7zXZ", XZ_PROGRAM, "-J" },
{ ct_tar },
{ ct_compress, 2, "\037\235" },
{ ct_gzip, 2, "\037\213" },
{ ct_bzip2, 3, "BZh" },
{ ct_lzip, 4, "LZIP" },
{ ct_lzma, 6, "\xFFLZMA" },
{ ct_lzop, 4, "\211LZO" },
{ ct_xz, 6, "\xFD" "7zXZ" },
};
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
#define compress_option(t) magic[t].option
#define compress_program(t) magic[t].program
static struct zip_program zip_program[] = {
{ ct_compress, COMPRESS_PROGRAM, "-Z" },
{ ct_compress, GZIP_PROGRAM, "-z" },
{ ct_gzip, GZIP_PROGRAM, "-z" },
{ ct_bzip2, BZIP2_PROGRAM, "-j" },
{ ct_bzip2, "lbzip2", "-j" },
{ ct_lzip, LZIP_PROGRAM, "--lzip" },
{ ct_lzma, LZMA_PROGRAM, "--lzma" },
{ ct_lzma, XZ_PROGRAM, "-J" },
{ ct_lzop, LZOP_PROGRAM, "--lzop" },
{ ct_xz, XZ_PROGRAM, "-J" },
{ ct_none }
};
static struct zip_program const *
find_zip_program (enum compress_type type, int *pstate)
{
int i;
for (i = *pstate; zip_program[i].type != ct_none; i++)
{
if (zip_program[i].type == type)
{
*pstate = i + 1;
return zip_program + i;
}
}
*pstate = i;
return NULL;
}
const char *
first_decompress_program (int *pstate)
{
struct zip_program const *zp;
if (use_compress_program_option)
return use_compress_program_option;
if (archive_compression_type == ct_none)
return NULL;
*pstate = 0;
zp = find_zip_program (archive_compression_type, pstate);
return zp ? zp->program : NULL;
}
const char *
next_decompress_program (int *pstate)
{
struct zip_program const *zp;
if (use_compress_program_option)
return NULL;
zp = find_zip_program (archive_compression_type, pstate);
return zp ? zp->program : NULL;
}
static const char *
compress_option (enum compress_type type)
{
struct zip_program const *zp;
int i = 0;
zp = find_zip_program (type, &i);
return zp ? zp->option : NULL;
}
/* Check if the file ARCHIVE is a compressed archive. */
enum compress_type
static enum compress_type
check_compressed_archive (bool *pshort)
{
struct zip_magic const *p;
@@ -243,14 +379,14 @@ check_compressed_archive (bool *pshort)
if (!pshort)
pshort = &temp;
/* Prepare global data needed for find_next_block: */
record_end = record_start; /* set up for 1st record = # 0 */
sfr = read_full_records;
read_full_records = true; /* Suppress fatal error on reading a partial
record */
*pshort = find_next_block () == 0;
/* Restore global values */
read_full_records = sfr;
@@ -267,7 +403,7 @@ check_compressed_archive (bool *pshort)
/* Guess if the archive is seekable. */
static void
guess_seekable_archive ()
guess_seekable_archive (void)
{
struct stat st;
@@ -288,7 +424,7 @@ guess_seekable_archive ()
seekable_archive = !!seek_option;
return;
}
if (!multi_volume_option && !use_compress_program_option
&& fstat (archive, &st) == 0)
seekable_archive = S_ISREG (st.st_mode);
@@ -299,8 +435,8 @@ guess_seekable_archive ()
/* Open an archive named archive_name_array[0]. Detect if it is
a compressed archive of known type and use corresponding decompression
program if so */
int
open_compressed_archive ()
static int
open_compressed_archive (void)
{
archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
MODE_RW, rsh_command_option);
@@ -320,24 +456,24 @@ open_compressed_archive ()
if (shortfile)
ERROR ((0, 0, _("This does not look like a tar archive")));
return archive;
case ct_none:
if (shortfile)
ERROR ((0, 0, _("This does not look like a tar archive")));
set_comression_program_by_suffix (archive_name_array[0], NULL);
set_compression_program_by_suffix (archive_name_array[0], NULL);
if (!use_compress_program_option)
return archive;
break;
default:
use_compress_program_option = compress_program (type);
archive_compression_type = type;
break;
}
}
/* FD is not needed any more */
rmtclose (archive);
hit_eof = false; /* It might have been set by find_next_block in
check_compressed_archive */
@@ -486,7 +622,7 @@ xclose (int fd)
}
static void
init_buffer ()
init_buffer (void)
{
if (! record_buffer_aligned[record_index])
record_buffer_aligned[record_index] =
@@ -511,8 +647,6 @@ _open_archive (enum access_mode wanted_access)
FATAL_ERROR ((0, 0, _("No archive name given")));
tar_stat_destroy (&current_stat_info);
save_name = 0;
real_s_name = 0;
record_index = 0;
init_buffer ();
@@ -657,7 +791,7 @@ _open_archive (enum access_mode wanted_access)
}
/* Perform a write to flush the buffer. */
ssize_t
static ssize_t
_flush_write (void)
{
ssize_t status;
@@ -672,7 +806,21 @@ _flush_write (void)
status = record_size;
else
status = sys_write_archive_buffer ();
if (status && multi_volume_option && !inhibit_map)
{
struct bufmap *map = bufmap_locate (status);
if (map)
{
size_t delta = status - map->start * BLOCKSIZE;
if (delta > map->sizeleft)
delta = map->sizeleft;
map->sizeleft -= delta;
if (map->sizeleft == 0)
map = map->next;
bufmap_reset (map, map ? (- map->start) : 0);
}
}
return status;
}
@@ -713,7 +861,7 @@ archive_read_error (void)
}
static bool
archive_is_dev ()
archive_is_dev (void)
{
struct stat st;
@@ -861,7 +1009,7 @@ seek_archive (off_t size)
if (size <= skipped)
return 0;
/* Compute number of records to skip */
nrec = (size - skipped) / record_size;
if (nrec == 0)
@@ -907,12 +1055,9 @@ close_archive (void)
sys_wait_for_child (child_pid, hit_eof);
tar_stat_destroy (&current_stat_info);
if (save_name)
free (save_name);
if (real_s_name)
free (real_s_name);
free (record_buffer[0]);
free (record_buffer[1]);
bufmap_free (NULL);
}
/* Called to initialize the global volume number. */
@@ -956,7 +1101,7 @@ closeout_volume_number (void)
static void
increase_volume_number ()
increase_volume_number (void)
{
global_volno++;
if (global_volno < 0)
@@ -964,13 +1109,13 @@ increase_volume_number ()
volno++;
}
void
static void
change_tape_menu (FILE *read_file)
{
char *input_buffer = NULL;
size_t size = 0;
bool stop = false;
while (!stop)
{
fputc ('\007', stderr);
@@ -1088,7 +1233,7 @@ new_volume (enum access_mode mode)
assign_string (&continued_file_name, NULL);
continued_file_size = continued_file_offset = 0;
current_block = record_start;
if (rmtclose (archive) != 0)
close_error (*archive_name_cursor);
@@ -1177,13 +1322,13 @@ read_header0 (struct tar_stat_info *info)
return false;
}
bool
try_new_volume ()
static bool
try_new_volume (void)
{
size_t status;
union block *header;
enum access_mode acc;
switch (subcommand_option)
{
case APPEND_SUBCOMMAND:
@@ -1199,7 +1344,7 @@ try_new_volume ()
if (!new_volume (acc))
return true;
while ((status = rmtread (archive, record_start->buffer, record_size))
== SAFE_READ_ERROR)
archive_read_error ();
@@ -1222,10 +1367,10 @@ try_new_volume ()
ERROR ((0, 0, _("This does not look like a tar archive")));
return false;
}
xheader_decode (&dummy); /* decodes values from the global header */
tar_stat_destroy (&dummy);
/* The initial global header must be immediately followed by
an extended PAX header for the first member in this volume.
However, in some cases tar may split volumes in the middle
@@ -1237,7 +1382,7 @@ try_new_volume ()
HEADER_FAILURE, which is ignored.
See also tests/multiv07.at */
switch (read_header (&header, &dummy, read_header_auto))
{
case HEADER_SUCCESS:
@@ -1280,30 +1425,30 @@ try_new_volume ()
break;
}
if (real_s_name)
if (bufmap_head)
{
uintmax_t s;
if (!continued_file_name
|| strcmp (continued_file_name, real_s_name))
|| strcmp (continued_file_name, bufmap_head->file_name))
{
if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)
&& strlen (real_s_name) >= NAME_FIELD_SIZE
&& strncmp (continued_file_name, real_s_name,
&& strlen (bufmap_head->file_name) >= NAME_FIELD_SIZE
&& strncmp (continued_file_name, bufmap_head->file_name,
NAME_FIELD_SIZE) == 0)
WARN ((0, 0,
_("%s is possibly continued on this volume: header contains truncated name"),
quote (real_s_name)));
quote (bufmap_head->file_name)));
else
{
WARN ((0, 0, _("%s is not continued on this volume"),
quote (real_s_name)));
quote (bufmap_head->file_name)));
return false;
}
}
s = continued_file_size + continued_file_offset;
if (real_s_totsize != s || s < continued_file_offset)
if (bufmap_head->sizetotal != s || s < continued_file_offset)
{
char totsizebuf[UINTMAX_STRSIZE_BOUND];
char s1buf[UINTMAX_STRSIZE_BOUND];
@@ -1311,23 +1456,24 @@ try_new_volume ()
WARN ((0, 0, _("%s is the wrong size (%s != %s + %s)"),
quote (continued_file_name),
STRINGIFY_BIGINT (save_totsize, totsizebuf),
STRINGIFY_BIGINT (bufmap_head->sizetotal, totsizebuf),
STRINGIFY_BIGINT (continued_file_size, s1buf),
STRINGIFY_BIGINT (continued_file_offset, s2buf)));
return false;
}
if (real_s_totsize - real_s_sizeleft != continued_file_offset)
if (bufmap_head->sizetotal - bufmap_head->sizeleft !=
continued_file_offset)
{
char totsizebuf[UINTMAX_STRSIZE_BOUND];
char s1buf[UINTMAX_STRSIZE_BOUND];
char s2buf[UINTMAX_STRSIZE_BOUND];
WARN ((0, 0, _("This volume is out of sequence (%s - %s != %s)"),
STRINGIFY_BIGINT (real_s_totsize, totsizebuf),
STRINGIFY_BIGINT (real_s_sizeleft, s1buf),
STRINGIFY_BIGINT (bufmap_head->sizetotal, totsizebuf),
STRINGIFY_BIGINT (bufmap_head->sizeleft, s1buf),
STRINGIFY_BIGINT (continued_file_offset, s2buf)));
return false;
}
}
@@ -1348,7 +1494,7 @@ drop_volume_label_suffix (const char *label)
if (len < 1)
return NULL;
for (p = label + len - 1; p > label && isdigit ((unsigned char) *p); p--)
;
if (p > label && p - (VOLUME_TEXT_LEN - 1) > label)
@@ -1365,7 +1511,7 @@ drop_volume_label_suffix (const char *label)
return NULL;
}
/* Check LABEL against the volume label, seen as a globbing
pattern. Return true if the pattern matches. In case of failure,
retry matching a volume sequence number before giving up in
@@ -1374,7 +1520,7 @@ static bool
check_label_pattern (const char *label)
{
char *string;
bool result;
bool result = false;
if (fnmatch (volume_label_option, label, 0) == 0)
return true;
@@ -1399,7 +1545,7 @@ match_volume_label (void)
if (!volume_label)
{
union block *label = find_next_block ();
if (!label)
FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
quote (volume_label_option)));
@@ -1425,11 +1571,11 @@ match_volume_label (void)
tar_stat_destroy (&st);
}
}
if (!volume_label)
FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
quote (volume_label_option)));
if (!check_label_pattern (volume_label))
FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),
quote_n (0, volume_label),
@@ -1477,26 +1623,24 @@ add_volume_label (void)
}
static void
add_chunk_header ()
add_chunk_header (struct bufmap *map)
{
if (archive_format == POSIX_FORMAT)
{
off_t block_ordinal;
union block *blk;
struct tar_stat_info st;
static size_t real_s_part_no; /* FIXME */
real_s_part_no++;
memset (&st, 0, sizeof st);
st.orig_file_name = st.file_name = real_s_name;
st.orig_file_name = st.file_name = map->file_name;
st.stat.st_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
st.stat.st_uid = getuid ();
st.stat.st_gid = getgid ();
st.orig_file_name = xheader_format_name (&st,
"%d/GNUFileParts.%p/%f.%n",
real_s_part_no);
volno);
st.file_name = st.orig_file_name;
st.archive_file_size = st.stat.st_size = real_s_sizeleft;
st.archive_file_size = st.stat.st_size = map->sizeleft;
block_ordinal = current_block_ordinal ();
blk = start_header (&st);
@@ -1520,27 +1664,23 @@ write_volume_label (void)
/* Write GNU multi-volume header */
static void
gnu_add_multi_volume_header (void)
gnu_add_multi_volume_header (struct bufmap *map)
{
int tmp;
union block *block = find_next_block ();
if (strlen (real_s_name) > NAME_FIELD_SIZE)
if (strlen (map->file_name) > NAME_FIELD_SIZE)
WARN ((0, 0,
_("%s: file name too long to be stored in a GNU multivolume header, truncated"),
quotearg_colon (real_s_name)));
quotearg_colon (map->file_name)));
memset (block, 0, BLOCKSIZE);
/* FIXME: Michael P Urban writes: [a long name file] is being written
when a new volume rolls around [...] Looks like the wrong value is
being preserved in real_s_name, though. */
strncpy (block->header.name, real_s_name, NAME_FIELD_SIZE);
strncpy (block->header.name, map->file_name, NAME_FIELD_SIZE);
block->header.typeflag = GNUTYPE_MULTIVOL;
OFF_TO_CHARS (real_s_sizeleft, block->header.size);
OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
OFF_TO_CHARS (map->sizeleft, block->header.size);
OFF_TO_CHARS (map->sizetotal - map->sizeleft,
block->oldgnu_header.offset);
tmp = verbose_option;
@@ -1553,40 +1693,17 @@ gnu_add_multi_volume_header (void)
/* Add a multi volume header to the current archive. The exact header format
depends on the archive format. */
static void
add_multi_volume_header (void)
add_multi_volume_header (struct bufmap *map)
{
if (archive_format == POSIX_FORMAT)
{
off_t d = real_s_totsize - real_s_sizeleft;
xheader_store ("GNU.volume.filename", &dummy, real_s_name);
xheader_store ("GNU.volume.size", &dummy, &real_s_sizeleft);
off_t d = map->sizetotal - map->sizeleft;
xheader_store ("GNU.volume.filename", &dummy, map->file_name);
xheader_store ("GNU.volume.size", &dummy, &map->sizeleft);
xheader_store ("GNU.volume.offset", &dummy, &d);
}
else
gnu_add_multi_volume_header ();
}
/* Synchronize multi-volume globals */
static void
multi_volume_sync ()
{
if (multi_volume_option)
{
if (save_name)
{
assign_string (&real_s_name,
safer_name_suffix (save_name, false,
absolute_names_option));
real_s_totsize = save_totsize;
real_s_sizeleft = save_sizeleft;
}
else
{
assign_string (&real_s_name, 0);
real_s_totsize = 0;
real_s_sizeleft = 0;
}
}
gnu_add_multi_volume_header (map);
}
@@ -1599,7 +1716,7 @@ simple_flush_read (void)
size_t status; /* result from system call */
checkpoint_run (false);
/* Clear the count of errors. This only applies to a single call to
flush_read. */
@@ -1658,7 +1775,7 @@ _gnu_flush_read (void)
size_t status; /* result from system call */
checkpoint_run (false);
/* Clear the count of errors. This only applies to a single call to
flush_read. */
@@ -1673,8 +1790,6 @@ _gnu_flush_read (void)
archive_write_error (status);
}
multi_volume_sync ();
for (;;)
{
status = rmtread (archive, record_start->buffer, record_size);
@@ -1726,36 +1841,36 @@ _gnu_flush_write (size_t buffer_level)
char *copy_ptr;
size_t copy_size;
size_t bufsize;
tarlong wrt;
struct bufmap *map;
status = _flush_write ();
if (status != record_size && !multi_volume_option)
archive_write_error (status);
else
{
if (status)
records_written++;
records_written++;
bytes_written += status;
}
if (status == record_size)
{
multi_volume_sync ();
return;
}
map = bufmap_locate (status);
if (status % BLOCKSIZE)
{
ERROR ((0, 0, _("write did not end on a block boundary")));
archive_write_error (status);
}
/* In multi-volume mode. */
/* ENXIO is for the UNIX PC. */
if (status < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO)
archive_write_error (status);
real_s_sizeleft -= status;
if (!new_volume (ACCESS_WRITE))
return;
@@ -1767,25 +1882,28 @@ _gnu_flush_write (size_t buffer_level)
copy_ptr = record_start->buffer + status;
copy_size = buffer_level - status;
/* Switch to the next buffer */
record_index = !record_index;
init_buffer ();
inhibit_map = 1;
if (volume_label_option)
add_volume_label ();
if (real_s_name)
add_multi_volume_header ();
if (map)
add_multi_volume_header (map);
write_extended (true, &dummy, find_next_block ());
tar_stat_destroy (&dummy);
if (real_s_name)
add_chunk_header ();
wrt = bytes_written;
if (map)
add_chunk_header (map);
header = find_next_block ();
bufmap_reset (map, header - record_start);
bufsize = available_space_after (header);
inhibit_map = 0;
while (bufsize < copy_size)
{
memcpy (header->buffer, copy_ptr, bufsize);
@@ -1798,16 +1916,6 @@ _gnu_flush_write (size_t buffer_level)
memcpy (header->buffer, copy_ptr, copy_size);
memset (header->buffer + copy_size, 0, bufsize - copy_size);
set_next_block_after (header + (copy_size - 1) / BLOCKSIZE);
if (multi_volume_option && wrt < bytes_written)
{
/* The value of bytes_written has changed while moving data;
that means that flush_archive was executed at least once in
between, and, as a consequence, copy_size bytes were not written
to disk. We need to update sizeleft variables to compensate for
that. */
save_sizeleft += copy_size;
multi_volume_sync ();
}
find_next_block ();
}
@@ -1841,6 +1949,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 +1959,6 @@ open_archive (enum access_mode wanted_access)
if (volume_label_option)
write_volume_label ();
break;
default:
break;
}
set_volume_start_time ();
}

View File

@@ -77,7 +77,7 @@ void
checkpoint_compile_action (const char *str)
{
struct checkpoint_action *act;
if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
alloc_action (cop_dot);
else if (strcmp (str, "bell") == 0)
@@ -119,14 +119,14 @@ checkpoint_finish_compile ()
{
if (!checkpoint_action)
/* Provide a historical default */
checkpoint_compile_action ("echo");
checkpoint_compile_action ("echo");
}
else if (checkpoint_action)
/* Otherwise, set default checkpoint rate */
checkpoint_option = DEFAULT_CHECKPOINT;
}
char *
static char *
expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
{
const char *opstr = do_write ? gettext ("write") : gettext ("read");
@@ -147,7 +147,7 @@ expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
case 'u':
outlen += cpslen - 2;
break;
case 's':
outlen += opstrlen - 2;
}
@@ -164,11 +164,11 @@ expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
case 'u':
op = stpcpy (op, cps);
break;
case 's':
op = stpcpy (op, opstr);
break;
default:
*op++ = '%';
*op++ = *ip;
@@ -188,7 +188,7 @@ run_checkpoint_actions (bool do_write)
{
struct checkpoint_action *p;
FILE *tty = NULL;
for (p = checkpoint_action; p; p = p->next)
{
switch (p->opcode)
@@ -207,7 +207,7 @@ run_checkpoint_actions (bool do_write)
fflush (tty);
}
break;
case cop_echo:
{
char *tmp;
@@ -232,7 +232,7 @@ run_checkpoint_actions (bool do_write)
free (tmp);
}
break;
case cop_ttyout:
if (!tty)
tty = fopen ("/dev/tty", "w");
@@ -245,11 +245,11 @@ run_checkpoint_actions (bool do_write)
free (tmp);
}
break;
case cop_sleep:
sleep (p->v.time);
break;
case cop_exec:
sys_exec_checkpoint_script (p->v.command,
archive_name_cursor[0],
@@ -266,5 +266,4 @@ checkpoint_run (bool do_write)
{
if (checkpoint_option && !(++checkpoint % checkpoint_option))
run_checkpoint_actions (do_write);
}
}

View File

@@ -1,7 +1,7 @@
/* Common declarations for the tar program.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify it
@@ -105,6 +105,8 @@ GLOBAL bool absolute_names_option;
/* Display file times in UTC */
GLOBAL bool utc_option;
/* Output file timestamps to the full resolution */
GLOBAL bool full_time_option;
/* This variable tells how to interpret newer_mtime_option, below. If zero,
files get archived if their mtime is not less than newer_mtime_option.
@@ -335,12 +337,12 @@ struct name
int matching_flags; /* wildcard flags if name is a pattern */
bool cmdline; /* true if this name was given in the
command line */
int change_dir; /* Number of the directory to change to.
Set with the -C option. */
uintmax_t found_count; /* number of times a matching file has
been found */
/* The following members are used for incremental dumps only,
if this struct name represents a directory;
see incremen.c */
@@ -355,6 +357,11 @@ struct name
GLOBAL dev_t ar_dev;
GLOBAL ino_t ar_ino;
/* Flags for reading, searching, and fstatatting files. */
GLOBAL int open_read_flags;
GLOBAL int open_searchdir_flags;
GLOBAL int fstatat_flags;
GLOBAL int seek_option;
GLOBAL bool seekable_archive;
@@ -425,13 +432,17 @@ void archive_read_error (void);
off_t seek_archive (off_t size);
void set_start_time (void);
void mv_begin (struct tar_stat_info *st);
void mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft);
void mv_begin_read (struct tar_stat_info *st);
void mv_end (void);
void mv_total_size (off_t size);
void mv_size_left (off_t size);
void buffer_write_global_xheader (void);
const char *first_decompress_program (int *pstate);
const char *next_decompress_program (int *pstate);
/* Module create.c. */
enum dump_status
@@ -443,13 +454,14 @@ enum dump_status
};
void add_exclusion_tag (const char *name, enum exclusion_tag_type type,
bool (*)(const char*));
bool cachedir_file_p (const char *name);
bool (*predicate) (int));
bool cachedir_file_p (int fd);
char *get_directory_entries (struct tar_stat_info *st);
bool file_dumpable_p (struct tar_stat_info *st);
void create_archive (void);
void pad_archive (off_t size_left);
void dump_file (const char *st, bool top_level, dev_t parent_device);
void dump_file (struct tar_stat_info *parent, char const *name,
char const *fullname);
union block *start_header (struct tar_stat_info *st);
void finish_header (struct tar_stat_info *st, union block *header,
off_t block_ordinal);
@@ -459,33 +471,18 @@ union block * write_extended (bool global, struct tar_stat_info *st,
union block *start_private_header (const char *name, size_t size, time_t t);
void write_eot (void);
void check_links (void);
int subfile_open (struct tar_stat_info const *dir, char const *file, int flags);
void restore_parent_fd (struct tar_stat_info const *st);
void exclusion_tag_warning (const char *dirname, const char *tagname,
const char *message);
enum exclusion_tag_type check_exclusion_tags (const char *dirname,
enum exclusion_tag_type check_exclusion_tags (struct tar_stat_info const *st,
const char **tag_file_name);
#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where))
#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
bool gid_to_chars (gid_t gid, char *buf, size_t size);
bool major_to_chars (major_t m, char *buf, size_t size);
bool minor_to_chars (minor_t m, char *buf, size_t size);
bool mode_to_chars (mode_t m, char *buf, size_t size);
#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
bool off_to_chars (off_t off, char *buf, size_t size);
bool size_to_chars (size_t v, char *buf, size_t size);
bool time_to_chars (time_t t, char *buf, size_t size);
bool uid_to_chars (uid_t uid, char *buf, size_t size);
bool uintmax_to_chars (uintmax_t v, char *buf, size_t size);
void string_to_chars (char const *s, char *buf, size_t size);
/* Module diffarch.c. */
@@ -507,18 +504,8 @@ bool rename_directory (char *src, char *dst);
void delete_archive_members (void);
/* Module incremen.c. */
typedef struct dumpdir *dumpdir_t;
typedef struct dumpdir_iter *dumpdir_iter_t;
dumpdir_t dumpdir_create0 (const char *contents, const char *cmask);
dumpdir_t dumpdir_create (const char *contents);
void dumpdir_free (dumpdir_t);
char *dumpdir_locate (dumpdir_t dump, const char *name);
char *dumpdir_next (dumpdir_iter_t itr);
char *dumpdir_first (dumpdir_t dump, int all, dumpdir_iter_t *pitr);
struct directory *scan_directory (char *dir, dev_t device, bool cmdline);
void name_fill_directory (struct name *name, dev_t device, bool cmdline);
struct directory *scan_directory (struct tar_stat_info *st);
const char *directory_contents (struct directory *dir);
const char *safe_directory_contents (struct directory *dir);
@@ -531,7 +518,7 @@ void read_directory_file (void);
void write_directory_file (void);
void purge_directory (char const *directory_name);
void list_dumpdir (char *buffer, size_t size);
void update_parent_directory (const char *name);
void update_parent_directory (struct tar_stat_info *st);
size_t dumpdir_size (const char *p);
bool is_dumpdir (struct tar_stat_info *stat_info);
@@ -566,27 +553,13 @@ extern size_t recent_long_link_blocks;
void decode_header (union block *header, struct tar_stat_info *stat_info,
enum archive_format *format_pointer, int do_user_group);
void transform_stat_info (int typeflag, struct tar_stat_info *stat_info);
char const *tartime (struct timespec t, bool full_time);
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
#define MODE_FROM_HEADER(where, hbits) \
mode_from_header (where, sizeof (where), hbits)
#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where))
#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
gid_t gid_from_header (const char *buf, size_t size);
major_t major_from_header (const char *buf, size_t size);
minor_t minor_from_header (const char *buf, size_t size);
mode_t mode_from_header (const char *buf, size_t size, unsigned *hbits);
off_t off_from_header (const char *buf, size_t size);
size_t size_from_header (const char *buf, size_t size);
time_t time_from_header (const char *buf, size_t size);
uid_t uid_from_header (const char *buf, size_t size);
uintmax_t uintmax_from_header (const char *buf, size_t size);
void list_archive (void);
@@ -605,7 +578,6 @@ void skip_member (void);
/* Module misc.c. */
void assign_string (char **dest, const char *src);
char *quote_copy_string (const char *str);
int unquote_string (char *str);
char *zap_slashes (char *name);
char *normalize_filename (const char *name);
@@ -623,6 +595,8 @@ enum { BILLION = 1000000000, LOG10_BILLION = 9 };
enum { TIMESPEC_STRSIZE_BOUND =
UINTMAX_STRSIZE_BOUND + LOG10_BILLION + sizeof "-." - 1 };
bool must_be_dot_or_slash (char const *);
enum remove_option
{
ORDINARY_REMOVE_OPTION,
@@ -641,8 +615,10 @@ int remove_any_file (const char *file_name, enum remove_option option);
bool maybe_backup_file (const char *file_name, bool this_is_the_archive);
void undo_last_backup (void);
int deref_stat (bool deref, char const *name, struct stat *buf);
int deref_stat (char const *name, struct stat *buf);
extern int chdir_current;
extern int chdir_fd;
int chdir_arg (char const *dir);
void chdir_do (int dir);
int chdir_count (void);
@@ -656,8 +632,6 @@ void seek_diag_details (char const *name, off_t offset);
void stat_diag (char const *name);
void file_removed_diag (const char *name, bool top_level,
void (*diagfn) (char const *name));
void dir_removed_diag (char const *name, bool top_level,
void (*diagfn) (char const *name));
void write_error_details (char const *name, size_t status, size_t size);
void write_fatal (char const *name) __attribute__ ((noreturn));
void write_fatal_details (char const *name, ssize_t status, size_t size)
@@ -667,11 +641,12 @@ pid_t xfork (void);
void xpipe (int fd[2]);
void *page_aligned_alloc (void **ptr, size_t size);
int set_file_atime (int fd, char const *file,
struct timespec const timespec[2]);
int set_file_atime (int fd, int parentfd, char const *file,
struct timespec atime);
/* Module names.c. */
extern size_t name_count;
extern struct name *gnu_list_name;
void gid_to_gname (gid_t gid, char **gname);
@@ -690,6 +665,7 @@ struct name *addname (char const *string, int change_dir,
void remname (struct name *name);
bool name_match (const char *name);
void names_notfound (void);
void label_notfound (void);
void collect_and_sort_names (void);
struct name *name_scan (const char *name);
struct name const *name_from_list (void);
@@ -702,7 +678,6 @@ bool excluded_name (char const *name);
void add_avoided_name (char const *name);
bool is_avoided_name (char const *name);
bool is_individual_file (char const *name);
bool contains_dot_dot (char const *name);
@@ -716,9 +691,9 @@ bool contains_dot_dot (char const *name);
void usage (int);
int confirm (const char *message_action, const char *name);
void request_stdin (const char *option);
void tar_stat_init (struct tar_stat_info *st);
bool tar_stat_close (struct tar_stat_info *st);
void tar_stat_destroy (struct tar_stat_info *st);
void usage (int) __attribute__ ((noreturn));
int tar_timespec_cmp (struct timespec a, struct timespec b);
@@ -734,7 +709,6 @@ void update_archive (void);
/* Module xheader.c. */
void xheader_init (struct xheader *xhdr);
void xheader_decode (struct tar_stat_info *stat);
void xheader_decode_global (struct xheader *xhdr);
void xheader_store (char const *keyword, struct tar_stat_info *st,
@@ -800,12 +774,12 @@ bool utf8_convert (bool to_utf, char const *input, char **output);
void set_transform_expr (const char *expr);
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 *);
bool transform_program_p (void);
/* Module suffix.c */
void set_comression_program_by_suffix (const char *name, const char *defprog);
void set_compression_program_by_suffix (const char *name, const char *defprog);
/* Module checkpoint.c */
void checkpoint_compile_action (const char *str);
@@ -832,11 +806,13 @@ void checkpoint_run (bool do_write);
#define WARN_UNKNOWN_CAST 0x00010000
#define WARN_UNKNOWN_KEYWORD 0x00020000
#define WARN_XDEV 0x00040000
#define WARN_DECOMPRESS_PROGRAM 0x00080000
/* 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_ALL (0xffffffff & ~WARN_VERBOSE_WARNINGS)
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY|\
WARN_DECOMPRESS_PROGRAM)
#define WARN_ALL (~WARN_VERBOSE_WARNINGS)
void set_warning_option (const char *arg);
@@ -856,4 +832,3 @@ void finish_deferred_unlinks (void);
/* Module exit.c */
extern void (*fatal_exit_hook) (void);

View File

@@ -122,7 +122,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
size_t data_size;
off_t size = st->stat.st_size;
mv_begin (st);
mv_begin_read (st);
while (size)
{
data_block = find_next_block ();
@@ -151,7 +151,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
static int
get_stat_data (char const *file_name, struct stat *stat_data)
{
int status = deref_stat (dereference_option, file_name, stat_data);
int status = deref_stat (file_name, stat_data);
if (status != 0)
{
@@ -217,12 +217,7 @@ diff_file (void)
}
else
{
int atime_flag =
(atime_preserve_option == system_atime_preserve
? O_NOATIME
: 0);
diff_handle = open (file_name, O_RDONLY | O_BINARY | atime_flag);
diff_handle = openat (chdir_fd, file_name, open_read_flags);
if (diff_handle < 0)
{
@@ -239,12 +234,12 @@ diff_file (void)
else
read_and_process (&current_stat_info, process_rawdata);
if (atime_preserve_option == replace_atime_preserve)
if (atime_preserve_option == replace_atime_preserve
&& stat_data.st_size != 0)
{
struct timespec ts[2];
ts[0] = get_stat_atime (&stat_data);
ts[1] = get_stat_mtime (&stat_data);
if (set_file_atime (diff_handle, file_name, ts) != 0)
struct timespec atime = get_stat_atime (&stat_data);
if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
!= 0)
utime_error (file_name);
}
@@ -277,7 +272,8 @@ diff_symlink (void)
size_t len = strlen (current_stat_info.link_name);
char *linkbuf = alloca (len + 1);
int status = readlink (current_stat_info.file_name, linkbuf, len + 1);
int status = readlinkat (chdir_fd, current_stat_info.file_name,
linkbuf, len + 1);
if (status < 0)
{
@@ -331,7 +327,7 @@ static int
dumpdir_cmp (const char *a, const char *b)
{
size_t len;
while (*a)
switch (*a)
{
@@ -345,7 +341,7 @@ dumpdir_cmp (const char *a, const char *b)
a += len;
b += len;
break;
case 'D':
if (strcmp(a, b))
return 1;
@@ -353,7 +349,7 @@ dumpdir_cmp (const char *a, const char *b)
a += len;
b += len;
break;
case 'R':
case 'T':
case 'X':
@@ -369,7 +365,7 @@ diff_dumpdir (void)
dev_t dev = 0;
struct stat stat_data;
if (deref_stat (true, current_stat_info.file_name, &stat_data))
if (deref_stat (current_stat_info.file_name, &stat_data) != 0)
{
if (errno == ENOENT)
stat_warn (current_stat_info.file_name);
@@ -379,8 +375,7 @@ diff_dumpdir (void)
else
dev = stat_data.st_dev;
dumpdir_buffer = directory_contents
(scan_directory (current_stat_info.file_name, dev, false));
dumpdir_buffer = directory_contents (scan_directory (&current_stat_info));
if (dumpdir_buffer)
{
@@ -422,7 +417,8 @@ diff_multivol (void)
return;
}
fd = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
if (fd < 0)
{
@@ -452,7 +448,6 @@ diff_archive (void)
{
set_next_block_after (current_header);
decode_header (current_header, &current_stat_info, &current_format, 1);
/* Print the block from current_header and current_stat_info. */
@@ -518,13 +513,22 @@ diff_archive (void)
void
verify_volume (void)
{
int may_fail = 0;
if (removed_prefixes_p ())
{
WARN((0, 0,
_("Archive contains file names with leading prefixes removed.")));
WARN((0, 0,
_("Verification may fail to locate original files.")));
may_fail = 1;
}
if (transform_program_p ())
{
WARN((0, 0,
_("Archive contains transformed file names.")));
may_fail = 1;
}
if (may_fail)
WARN((0, 0,
_("Verification may fail to locate original files.")));
if (!diff_buffer)
diff_init ();
@@ -578,8 +582,8 @@ verify_volume (void)
flush_read ();
while (1)
{
enum read_header status = read_header (&current_header,
&current_stat_info,
enum read_header status = read_header (&current_header,
&current_stat_info,
read_header_auto);
if (status == HEADER_FAILURE)
@@ -609,7 +613,7 @@ verify_volume (void)
{
char buf[UINTMAX_STRSIZE_BOUND];
status = read_header (&current_header, &current_stat_info,
status = read_header (&current_header, &current_stat_info,
read_header_auto);
if (status == HEADER_ZERO_BLOCK)
break;
@@ -617,8 +621,10 @@ verify_volume (void)
(0, 0, _("A lone zero block at %s"),
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
}
continue;
}
decode_header (current_header, &current_stat_info, &current_format, 1);
diff_archive ();
tar_stat_destroy (&current_stat_info);
}

View File

@@ -26,11 +26,15 @@
#include "common.h"
#include <hash.h>
/* Error number to use when an impostor is discovered.
Pretend the impostor isn't there. */
enum { IMPOSTOR_ERRNO = ENOENT };
struct link
{
dev_t dev;
ino_t ino;
size_t nlink;
nlink_t nlink;
char name[1];
};
@@ -39,7 +43,7 @@ struct exclusion_tag
const char *name;
size_t length;
enum exclusion_tag_type type;
bool (*predicate) (const char *name);
bool (*predicate) (int fd);
struct exclusion_tag *next;
};
@@ -47,7 +51,7 @@ static struct exclusion_tag *exclusion_tags;
void
add_exclusion_tag (const char *name, enum exclusion_tag_type type,
bool (*predicate) (const char *name))
bool (*predicate) (int fd))
{
struct exclusion_tag *tag = xmalloc (sizeof tag[0]);
tag->next = exclusion_tags;
@@ -71,39 +75,24 @@ exclusion_tag_warning (const char *dirname, const char *tagname,
message));
}
enum exclusion_tag_type
check_exclusion_tags (const char *dirname, const char **tag_file_name)
enum exclusion_tag_type
check_exclusion_tags (struct tar_stat_info const *st, char const **tag_file_name)
{
static char *tagname;
static size_t tagsize;
struct exclusion_tag *tag;
size_t dlen = strlen (dirname);
int addslash = !ISSLASH (dirname[dlen-1]);
size_t noff = 0;
for (tag = exclusion_tags; tag; tag = tag->next)
{
size_t size = dlen + addslash + tag->length + 1;
if (size > tagsize)
int tagfd = subfile_open (st, tag->name, open_read_flags);
if (0 <= tagfd)
{
tagsize = size;
tagname = xrealloc (tagname, tagsize);
}
if (noff == 0)
{
strcpy (tagname, dirname);
noff = dlen;
if (addslash)
tagname[noff++] = '/';
}
strcpy (tagname + noff, tag->name);
if (access (tagname, F_OK) == 0
&& (!tag->predicate || tag->predicate (tagname)))
{
if (tag_file_name)
*tag_file_name = tag->name;
return tag->type;
bool satisfied = !tag->predicate || tag->predicate (tagfd);
close (tagfd);
if (satisfied)
{
if (tag_file_name)
*tag_file_name = tag->name;
return tag->type;
}
}
}
@@ -121,22 +110,13 @@ check_exclusion_tags (const char *dirname, const char **tag_file_name)
#define CACHEDIR_SIGNATURE_SIZE (sizeof CACHEDIR_SIGNATURE - 1)
bool
cachedir_file_p (const char *name)
cachedir_file_p (int fd)
{
bool tag_present = false;
int fd = open (name, O_RDONLY);
if (fd >= 0)
{
static char tagbuf[CACHEDIR_SIGNATURE_SIZE];
char tagbuf[CACHEDIR_SIGNATURE_SIZE];
if (read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE)
== CACHEDIR_SIGNATURE_SIZE
&& memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0)
tag_present = true;
close (fd);
}
return tag_present;
return
(read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE) == CACHEDIR_SIGNATURE_SIZE
&& memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0);
}
@@ -214,6 +194,14 @@ to_base256 (int negative, uintmax_t value, char *where, size_t size)
while (i);
}
#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
static bool
to_chars (int negative, uintmax_t value, size_t valsize,
@@ -263,7 +251,7 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
1. In OLDGNU_FORMAT all strings in a tar header end in \0
2. Incremental archives use oldgnu_header.
Apart from this they are completely identical. */
uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
char subbuf[UINTMAX_STRSIZE_BOUND + 1];
@@ -368,25 +356,25 @@ gid_substitute (int *negative)
return r;
}
bool
static bool
gid_to_chars (gid_t v, char *p, size_t s)
{
return to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
}
bool
static bool
major_to_chars (major_t v, char *p, size_t s)
{
return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
}
bool
static bool
minor_to_chars (minor_t v, char *p, size_t s)
{
return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
}
bool
static bool
mode_to_chars (mode_t v, char *p, size_t s)
{
/* In the common case where the internal and external mode bits are the same,
@@ -432,12 +420,6 @@ off_to_chars (off_t v, char *p, size_t s)
return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
}
bool
size_to_chars (size_t v, char *p, size_t s)
{
return to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
}
bool
time_to_chars (time_t v, char *p, size_t s)
{
@@ -460,19 +442,19 @@ uid_substitute (int *negative)
return r;
}
bool
static bool
uid_to_chars (uid_t v, char *p, size_t s)
{
return to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
}
bool
static bool
uintmax_to_chars (uintmax_t v, char *p, size_t s)
{
return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
}
void
static void
string_to_chars (char const *str, char *p, size_t s)
{
tar_copy_str (p, str, s);
@@ -480,20 +462,25 @@ string_to_chars (char const *str, char *p, size_t s)
}
/* A file is considered dumpable if it is sparse and both --sparse and --totals
/* A directory is always considered dumpable.
Otherwise, only regular and contiguous files are considered dumpable.
Such a file is dumpable if it is sparse and both --sparse and --totals
are specified.
Otherwise, it is dumpable unless any of the following conditions occur:
a) it is empty *and* world-readable, or
b) current archive is /dev/null */
bool
file_dumpable_p (struct tar_stat_info *st)
static bool
file_dumpable_p (struct stat const *st)
{
if (S_ISDIR (st->st_mode))
return true;
if (! (S_ISREG (st->st_mode) || S_ISCTG (st->st_mode)))
return false;
if (dev_null_output)
return totals_option && sparse_option && ST_IS_SPARSE (st->stat);
return !(st->archive_file_size == 0
&& (st->stat.st_mode & MODE_R) == MODE_R);
return totals_option && sparse_option && ST_IS_SPARSE (*st);
return ! (st->st_size == 0 && (st->st_mode & MODE_R) == MODE_R);
}
@@ -575,7 +562,8 @@ 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);
strcpy (header->buffer + offsetof (struct posix_header, magic),
OLDGNU_MAGIC);
header->header.typeflag = type;
finish_header (st, header, -1);
@@ -618,7 +606,7 @@ write_ustar_long_name (const char *name)
size_t length = strlen (name);
size_t i, nlen;
union block *header;
if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)
{
ERROR ((0, 0, _("%s: file name is too long (max %d); not dumped"),
@@ -713,7 +701,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header)
char *p;
int type;
time_t t;
if (st->xhdr.buffer || st->xhdr.stk == NULL)
return old_header;
@@ -912,7 +900,8 @@ start_header (struct tar_stat_info *st)
case OLDGNU_FORMAT:
case GNU_FORMAT: /*FIXME?*/
/* Overwrite header->header.magic and header.version in one blow. */
strcpy (header->header.magic, OLDGNU_MAGIC);
strcpy (header->buffer + offsetof (struct posix_header, magic),
OLDGNU_MAGIC);
break;
case POSIX_FORMAT:
@@ -1012,7 +1001,6 @@ pad_archive (off_t size_left)
union block *blk;
while (size_left > 0)
{
mv_size_left (size_left);
blk = find_next_block ();
memset (blk->buffer, 0, BLOCKSIZE);
set_next_block_after (blk);
@@ -1038,12 +1026,10 @@ dump_regular_file (int fd, struct tar_stat_info *st)
finish_header (st, blk, block_ordinal);
mv_begin (st);
mv_begin_write (st->file_name, st->stat.st_size, st->stat.st_size);
while (size_left > 0)
{
size_t bufsize, count;
mv_size_left (size_left);
blk = find_next_block ();
@@ -1058,7 +1044,7 @@ dump_regular_file (int fd, struct tar_stat_info *st)
memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
}
count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
count = (fd <= 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
if (count == SAFE_READ_ERROR)
{
read_diag_details (st->orig_file_name,
@@ -1080,7 +1066,7 @@ dump_regular_file (int fd, struct tar_stat_info *st)
size_left),
quotearg_colon (st->orig_file_name),
STRINGIFY_BIGINT (size_left, buf)));
if (! ignore_failed_read_option)
if (! ignore_failed_read_option)
set_exit_status (TAREXIT_DIFFERS);
pad_archive (size_left - (bufsize - count));
return dump_status_short;
@@ -1090,11 +1076,13 @@ dump_regular_file (int fd, struct tar_stat_info *st)
}
/* Copy info from the directory identified by ST into the archive.
DIRECTORY contains the directory's entries. */
static void
dump_dir0 (char *directory,
struct tar_stat_info *st, bool top_level, dev_t parent_device)
dump_dir0 (struct tar_stat_info *st, char const *directory)
{
dev_t our_device = st->stat.st_dev;
bool top_level = ! st->parent;
const char *tag_file_name;
union block *blk = NULL;
off_t block_ordinal = current_block_ordinal ();
@@ -1129,7 +1117,7 @@ dump_dir0 (char *directory,
size_t bufsize;
ssize_t count;
const char *buffer, *p_buffer;
block_ordinal = current_block_ordinal ();
buffer = safe_directory_contents (gnu_list_name->directory);
totsize = dumpdir_size (buffer);
@@ -1137,12 +1125,10 @@ dump_dir0 (char *directory,
finish_header (st, blk, block_ordinal);
p_buffer = buffer;
size_left = totsize;
mv_begin (st);
mv_total_size (totsize);
mv_begin_write (st->file_name, totsize, totsize);
while (size_left > 0)
{
mv_size_left (size_left);
blk = find_next_block ();
bufsize = available_space_after (blk);
if (size_left < bufsize)
@@ -1157,7 +1143,6 @@ dump_dir0 (char *directory,
p_buffer += bufsize;
set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
}
mv_end ();
}
return;
}
@@ -1167,7 +1152,7 @@ dump_dir0 (char *directory,
if (one_file_system_option
&& !top_level
&& parent_device != st->stat.st_dev)
&& st->parent->stat.st_dev != st->stat.st_dev)
{
if (verbose_option)
WARNOPT (WARN_XDEV,
@@ -1179,13 +1164,13 @@ dump_dir0 (char *directory,
{
char *name_buf;
size_t name_size;
switch (check_exclusion_tags (st->orig_file_name, &tag_file_name))
switch (check_exclusion_tags (st, &tag_file_name))
{
case exclusion_tag_all:
/* Handled in dump_file0 */
break;
case exclusion_tag_none:
{
char const *entry;
@@ -1196,7 +1181,6 @@ dump_dir0 (char *directory,
name_size = name_len = strlen (name_buf);
/* Now output all the files in the directory. */
/* FIXME: Should speed this up by cd-ing into the dir. */
for (entry = directory; (entry_len = strlen (entry)) != 0;
entry += entry_len + 1)
{
@@ -1207,9 +1191,9 @@ dump_dir0 (char *directory,
}
strcpy (name_buf + name_len, entry);
if (!excluded_name (name_buf))
dump_file (name_buf, false, our_device);
dump_file (st, entry, name_buf);
}
free (name_buf);
}
break;
@@ -1221,10 +1205,10 @@ dump_dir0 (char *directory,
name_buf = xmalloc (name_size);
strcpy (name_buf, st->orig_file_name);
strcat (name_buf, tag_file_name);
dump_file (name_buf, false, our_device);
dump_file (st, tag_file_name, name_buf);
free (name_buf);
break;
case exclusion_tag_under:
exclusion_tag_warning (st->orig_file_name, tag_file_name,
_("contents not dumped"));
@@ -1246,23 +1230,73 @@ ensure_slash (char **pstr)
(*pstr)[len] = '\0';
}
/* If we just ran out of file descriptors, release a file descriptor
in the directory chain somewhere leading from DIR->parent->parent
up through the root. Return true if successful, false (preserving
errno == EMFILE) otherwise.
Do not release DIR's file descriptor, or DIR's parent, as other
code assumes that they work. On some operating systems, another
process can claim file descriptor resources as we release them, and
some calls or their emulations require multiple file descriptors,
so callers should not give up if a single release doesn't work. */
static bool
dump_dir (int fd, struct tar_stat_info *st, bool top_level,
dev_t parent_device)
open_failure_recover (struct tar_stat_info const *dir)
{
char *directory = fdsavedir (fd);
if (!directory)
if (errno == EMFILE && dir && dir->parent)
{
struct tar_stat_info *p;
for (p = dir->parent->parent; p; p = p->parent)
if (0 < p->fd && (! p->parent || p->parent->fd <= 0))
{
tar_stat_close (p);
return true;
}
errno = EMFILE;
}
return false;
}
/* Return the directory entries of ST, in a dynamically allocated buffer,
each entry followed by '\0' and the last followed by an extra '\0'.
Return null on failure, setting errno. */
char *
get_directory_entries (struct tar_stat_info *st)
{
while (! (st->dirstream = fdopendir (st->fd)))
if (! open_failure_recover (st))
return 0;
return streamsavedir (st->dirstream);
}
/* Dump the directory ST. Return true if successful, false (emitting
diagnostics) otherwise. Get ST's entries, recurse through its
subdirectories, and clean up file descriptors afterwards. */
static bool
dump_dir (struct tar_stat_info *st)
{
char *directory = get_directory_entries (st);
if (! directory)
{
savedir_diag (st->orig_file_name);
return false;
}
dump_dir0 (directory, st, top_level, parent_device);
dump_dir0 (st, directory);
restore_parent_fd (st);
free (directory);
return true;
}
/* Number of links a file can have without having to be entered into
the link table. Typically this is 1, but in trickier circumstances
it is 0. */
static nlink_t trivial_link_count;
/* Main functions of this module. */
@@ -1271,6 +1305,8 @@ create_archive (void)
{
struct name const *p;
trivial_link_count = name_count <= 1 && ! dereference_option;
open_archive (ACCESS_WRITE);
buffer_write_global_xheader ();
@@ -1284,12 +1320,13 @@ create_archive (void)
while ((p = name_from_list ()) != NULL)
if (!excluded_name (p->name))
dump_file (p->name, p->cmdline, (dev_t) 0);
dump_file (0, p->name, p->name);
blank_name_list ();
while ((p = name_from_list ()) != NULL)
if (!excluded_name (p->name))
{
struct tar_stat_info st;
size_t plen = strlen (p->name);
if (buffer_size <= plen)
{
@@ -1300,6 +1337,7 @@ create_archive (void)
memcpy (buffer, p->name, plen);
if (! ISSLASH (buffer[plen - 1]))
buffer[plen++] = DIRECTORY_SEPARATOR;
tar_stat_init (&st);
q = directory_contents (gnu_list_name->directory);
if (q)
while (*q)
@@ -1307,6 +1345,23 @@ create_archive (void)
size_t qlen = strlen (q);
if (*q == 'Y')
{
if (! st.orig_file_name)
{
int fd = openat (chdir_fd, p->name,
open_searchdir_flags);
if (fd < 0)
{
open_diag (p->name);
break;
}
st.fd = fd;
if (fstat (fd, &st.stat) != 0)
{
stat_diag (p->name);
break;
}
st.orig_file_name = xstrdup (p->name);
}
if (buffer_size < plen + qlen)
{
while ((buffer_size *=2 ) < plen + qlen)
@@ -1314,10 +1369,11 @@ create_archive (void)
buffer = xrealloc (buffer, buffer_size);
}
strcpy (buffer + plen, q + 1);
dump_file (buffer, false, (dev_t) 0);
dump_file (&st, q + 1, buffer);
}
q += qlen + 1;
}
tar_stat_destroy (&st);
}
free (buffer);
}
@@ -1326,7 +1382,7 @@ create_archive (void)
const char *name;
while ((name = name_next (1)) != NULL)
if (!excluded_name (name))
dump_file (name, true, (dev_t) 0);
dump_file (0, name, name);
}
write_eot ();
@@ -1378,7 +1434,8 @@ static Hash_table *link_table;
static bool
dump_hard_link (struct tar_stat_info *st)
{
if (link_table && (st->stat.st_nlink > 1 || remove_files_option))
if (link_table
&& (trivial_link_count < st->stat.st_nlink || remove_files_option))
{
struct link lp;
struct link *duplicate;
@@ -1425,7 +1482,7 @@ file_count_links (struct tar_stat_info *st)
{
if (hard_dereference_option)
return;
if (st->stat.st_nlink > 1)
if (trivial_link_count < st->stat.st_nlink)
{
struct link *duplicate;
char *linkname = NULL;
@@ -1433,7 +1490,7 @@ file_count_links (struct tar_stat_info *st)
assign_string (&linkname, st->orig_file_name);
transform_name (&linkname, XFORM_LINK);
lp = xmalloc (offsetof (struct link, name)
+ strlen (linkname) + 1);
lp->ino = st->stat.st_ino;
@@ -1441,13 +1498,13 @@ file_count_links (struct tar_stat_info *st)
lp->nlink = st->stat.st_nlink;
strcpy (lp->name, linkname);
free (linkname);
if (! ((link_table
|| (link_table = hash_initialize (0, 0, hash_link,
compare_links, 0)))
&& (duplicate = hash_insert (link_table, lp))))
xalloc_die ();
if (duplicate != lp)
abort ();
lp->nlink--;
@@ -1474,26 +1531,96 @@ check_links (void)
}
}
/* Dump a single file, recursing on directories. P is the file name
to dump. TOP_LEVEL tells whether this is a top-level call; zero
means no, positive means yes, and negative means the top level
of an incremental dump. PARENT_DEVICE is the device of P's
parent directory; it is examined only if TOP_LEVEL is zero. */
/* Assuming DIR is the working directory, open FILE, using FLAGS to
control the open. A null DIR means to use ".". If we are low on
file descriptors, try to release one or more from DIR's parents to
reuse it. */
int
subfile_open (struct tar_stat_info const *dir, char const *file, int flags)
{
int fd;
static bool initialized;
if (! initialized)
{
/* Initialize any tables that might be needed when file
descriptors are exhausted, and whose initialization might
require a file descriptor. This includes the system message
catalog and tar's message catalog. */
initialized = true;
strerror (ENOENT);
gettext ("");
}
while ((fd = openat (dir ? dir->fd : chdir_fd, file, flags)) < 0
&& open_failure_recover (dir))
continue;
return fd;
}
/* Restore the file descriptor for ST->parent, if it was temporarily
closed to conserve file descriptors. On failure, set the file
descriptor to the negative of the corresponding errno value. Call
this every time a subdirectory is ascended from. */
void
restore_parent_fd (struct tar_stat_info const *st)
{
struct tar_stat_info *parent = st->parent;
if (parent && ! parent->fd)
{
int parentfd = openat (st->fd, "..", open_searchdir_flags);
struct stat parentstat;
if (parentfd < 0)
parentfd = - errno;
else if (! (fstat (parentfd, &parentstat) == 0
&& parent->stat.st_ino == parentstat.st_ino
&& parent->stat.st_dev == parentstat.st_dev))
{
close (parentfd);
parentfd = IMPOSTOR_ERRNO;
}
if (parentfd < 0)
{
int origfd = openat (chdir_fd, parent->orig_file_name,
open_searchdir_flags);
if (0 <= origfd)
{
if (fstat (parentfd, &parentstat) == 0
&& parent->stat.st_ino == parentstat.st_ino
&& parent->stat.st_dev == parentstat.st_dev)
parentfd = origfd;
else
close (origfd);
}
}
parent->fd = parentfd;
}
}
/* Dump a single file, recursing on directories. ST is the file's
status info, NAME its name relative to the parent directory, and P
its full name (which may be relative to the working directory). */
/* FIXME: One should make sure that for *every* path leading to setting
exit_status to failure, a clear diagnostic has been issued. */
static void
dump_file0 (struct tar_stat_info *st, const char *p,
bool top_level, dev_t parent_device)
dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
{
union block *header;
char type;
off_t original_size;
struct timespec original_ctime;
struct timespec restore_times[2];
off_t block_ordinal = -1;
int fd = 0;
bool is_dir;
struct tar_stat_info const *parent = st->parent;
bool top_level = ! parent;
int parentfd = top_level ? chdir_fd : parent->fd;
void (*diag) (char const *) = 0;
if (interactive_option && !confirm ("add", p))
return;
@@ -1504,14 +1631,34 @@ dump_file0 (struct tar_stat_info *st, const char *p,
transform_name (&st->file_name, XFORM_REGFILE);
if (deref_stat (dereference_option, p, &st->stat) != 0)
if (parentfd < 0 && ! top_level)
{
file_removed_diag (p, top_level, stat_diag);
errno = - parentfd;
diag = open_diag;
}
else if (fstatat (parentfd, name, &st->stat, fstatat_flags) != 0)
diag = stat_diag;
else if (file_dumpable_p (&st->stat))
{
fd = subfile_open (parent, name, open_read_flags);
if (fd < 0)
diag = open_diag;
else
{
st->fd = fd;
if (fstat (fd, &st->stat) != 0)
diag = stat_diag;
}
}
if (diag)
{
file_removed_diag (p, top_level, diag);
return;
}
st->archive_file_size = original_size = st->stat.st_size;
st->atime = restore_times[0] = get_stat_atime (&st->stat);
st->mtime = restore_times[1] = get_stat_mtime (&st->stat);
st->atime = get_stat_atime (&st->stat);
st->mtime = get_stat_mtime (&st->stat);
st->ctime = original_ctime = get_stat_ctime (&st->stat);
#ifdef S_ISHIDDEN
@@ -1529,11 +1676,11 @@ dump_file0 (struct tar_stat_info *st, const char *p,
/* See if we want only new files, and check if this one is too old to
put in the archive.
This check is omitted if incremental_option is set *and* the
requested file is not explicitely listed in the command line. */
if (!(incremental_option && !is_individual_file (p))
requested file is not explicitly listed in the command line. */
if (! (incremental_option && ! top_level)
&& !S_ISDIR (st->stat.st_mode)
&& OLDER_TAR_STAT_TIME (*st, m)
&& (!after_date_option || OLDER_TAR_STAT_TIME (*st, c)))
@@ -1562,51 +1709,31 @@ dump_file0 (struct tar_stat_info *st, const char *p,
if (is_dir || S_ISREG (st->stat.st_mode) || S_ISCTG (st->stat.st_mode))
{
bool ok;
int fd = -1;
struct stat final_stat;
if (is_dir || file_dumpable_p (st))
{
fd = open (p,
(O_RDONLY | O_BINARY
| (is_dir ? O_DIRECTORY | O_NONBLOCK : 0)
| (atime_preserve_option == system_atime_preserve
? O_NOATIME
: 0)));
if (fd < 0)
{
file_removed_diag (p, top_level, open_diag);
return;
}
}
if (is_dir)
{
const char *tag_file_name;
ensure_slash (&st->orig_file_name);
ensure_slash (&st->file_name);
if (check_exclusion_tags (st->orig_file_name, &tag_file_name)
== exclusion_tag_all)
if (check_exclusion_tags (st, &tag_file_name) == exclusion_tag_all)
{
exclusion_tag_warning (st->orig_file_name, tag_file_name,
_("directory not dumped"));
if (fd >= 0)
close (fd);
return;
}
ok = dump_dir (fd, st, top_level, parent_device);
/* dump_dir consumes FD if successful. */
if (ok)
fd = -1;
ok = dump_dir (st);
fd = st->fd;
parentfd = top_level ? chdir_fd : parent->fd;
}
else
{
enum dump_status status;
if (fd != -1 && sparse_option && ST_IS_SPARSE (st->stat))
if (fd && sparse_option && ST_IS_SPARSE (st->stat))
{
status = sparse_dump_file (fd, st);
if (status == dump_status_not_implemented)
@@ -1619,7 +1746,6 @@ dump_file0 (struct tar_stat_info *st, const char *p,
{
case dump_status_ok:
case dump_status_short:
mv_end ();
file_count_links (st);
break;
@@ -1635,21 +1761,26 @@ dump_file0 (struct tar_stat_info *st, const char *p,
if (ok)
{
/* If possible, reopen a directory if we are preserving
atimes, so that we can set just the atime on systems with
_FIOSATIME. */
if (fd < 0 && is_dir
&& atime_preserve_option == replace_atime_preserve)
fd = open (p, O_RDONLY | O_BINARY | O_DIRECTORY | O_NONBLOCK);
if ((fd < 0
? deref_stat (dereference_option, p, &final_stat)
: fstat (fd, &final_stat))
!= 0)
if (fd < 0)
{
file_removed_diag (p, top_level, stat_diag);
errno = - fd;
ok = false;
}
else if (fd == 0)
{
if (parentfd < 0 && ! top_level)
{
errno = - parentfd;
ok = false;
}
else
ok = fstatat (parentfd, name, &final_stat, fstatat_flags) == 0;
}
else
ok = fstat (fd, &final_stat) == 0;
if (! ok)
file_removed_diag (p, top_level, stat_diag);
}
if (ok)
@@ -1666,16 +1797,12 @@ 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)
&& fd && (is_dir || original_size != 0)
&& set_file_atime (fd, parentfd, name, st->atime) != 0)
utime_error (p);
}
if (0 <= fd && close (fd) != 0)
{
close_diag (p);
ok = false;
}
ok &= tar_stat_close (st);
if (ok && remove_files_option)
queue_deferred_unlink (p, is_dir);
@@ -1690,7 +1817,7 @@ dump_file0 (struct tar_stat_info *st, const char *p,
if (linklen != st->stat.st_size || linklen + 1 == 0)
xalloc_die ();
buffer = (char *) alloca (linklen + 1);
size = readlink (p, buffer, linklen + 1);
size = readlinkat (parentfd, name, buffer, linklen + 1);
if (size < 0)
{
file_removed_diag (p, top_level, readlink_diag);
@@ -1769,13 +1896,20 @@ dump_file0 (struct tar_stat_info *st, const char *p,
queue_deferred_unlink (p, false);
}
/* Dump a file, recursively. PARENT describes the file's parent
directory, NAME is the file's name relative to PARENT, and FULLNAME
its full name, possibly relative to the working directory. NAME
may contain slashes at the top level of invocation. */
void
dump_file (const char *p, bool top_level, dev_t parent_device)
dump_file (struct tar_stat_info *parent, char const *name,
char const *fullname)
{
struct tar_stat_info st;
tar_stat_init (&st);
dump_file0 (&st, p, top_level, parent_device);
if (listed_incremental_option)
update_parent_directory (p);
st.parent = parent;
dump_file0 (&st, name, fullname);
if (parent && listed_incremental_option)
update_parent_directory (parent);
tar_stat_destroy (&st);
}

View File

@@ -262,7 +262,7 @@ delete_archive_members (void)
if (current_block == record_end)
flush_archive ();
status = read_header (&current_header, &current_stat_info,
status = read_header (&current_header, &current_stat_info,
read_header_auto);
xheader_decode (&current_stat_info);
@@ -296,7 +296,7 @@ delete_archive_members (void)
set_next_block_after (current_header);
blocks_to_skip = (current_stat_info.stat.st_size
+ BLOCKSIZE - 1) / BLOCKSIZE;
while (record_end - current_block <= blocks_to_skip)
{
blocks_to_skip -= (record_end - current_block);

View File

@@ -1,4 +1,4 @@
/* This file is part of GNU tar.
/* This file is part of GNU tar.
Copyright (C) 2009 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,7 @@ enum children
#define DIR_IS_INITED(d) ((d)->flags & DIRF_INIT)
#define DIR_IS_NFS(d) ((d)->flags & DIRF_NFS)
#define DIR_IS_FOUND(d) ((d)->flags & DIRF_FOUND)
#define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW)
/* #define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW) FIXME: not used */
#define DIR_IS_RENAMED(d) ((d)->flags & DIRF_RENAMED)
#define DIR_SET_FLAG(d,f) (d)->flags |= (f)
@@ -77,14 +77,14 @@ struct directory
char *name; /* file name of directory */
};
struct dumpdir *
static struct dumpdir *
dumpdir_create0 (const char *contents, const char *cmask)
{
struct dumpdir *dump;
size_t i, total, ctsize, len;
char *p;
const char *q;
for (i = 0, total = 0, ctsize = 1, q = contents; *q; total++, q += len)
{
len = strlen (q) + 1;
@@ -108,13 +108,13 @@ dumpdir_create0 (const char *contents, const char *cmask)
return dump;
}
struct dumpdir *
static struct dumpdir *
dumpdir_create (const char *contents)
{
return dumpdir_create0 (contents, "YND");
}
void
static void
dumpdir_free (struct dumpdir *dump)
{
free (dump->elv);
@@ -131,7 +131,7 @@ compare_dirnames (const void *first, const void *second)
/* Locate NAME in the dumpdir array DUMP.
Return pointer to the slot in DUMP->contents, or NULL if not found */
char *
static char *
dumpdir_locate (struct dumpdir *dump, const char *name)
{
char **ptr;
@@ -146,16 +146,16 @@ dumpdir_locate (struct dumpdir *dump, const char *name)
struct dumpdir_iter
{
struct dumpdir *dump; /* Dumpdir being iterated */
int all; /* Iterate over all entries, not only D/N/Y */
int all; /* Iterate over all entries, not only D/N/Y */
size_t next; /* Index of the next element */
};
char *
static char *
dumpdir_next (struct dumpdir_iter *itr)
{
size_t cur = itr->next;
char *ret = NULL;
if (itr->all)
{
ret = itr->dump->contents + cur;
@@ -172,7 +172,7 @@ dumpdir_next (struct dumpdir_iter *itr)
return ret;
}
char *
static char *
dumpdir_first (struct dumpdir *dump, int all, struct dumpdir_iter **pitr)
{
struct dumpdir_iter *itr = xmalloc (sizeof (*itr));
@@ -258,7 +258,7 @@ make_directory (const char *name, char *caname)
directory->dump = directory->idump = NULL;
directory->orig = NULL;
directory->flags = false;
if (namelen && ISSLASH (name[namelen - 1]))
if (namelen > 1 && ISSLASH (name[namelen - 1]))
namelen--;
directory->name = xmalloc (namelen + 1);
memcpy (directory->name, name, namelen);
@@ -288,9 +288,9 @@ attach_directory (const char *name)
dirtail = dir;
return dir;
}
void
static void
dirlist_replace_prefix (const char *pref, const char *repl)
{
struct directory *dp;
@@ -402,26 +402,17 @@ find_directory_meta (dev_t dev, ino_t ino)
}
void
update_parent_directory (const char *name)
update_parent_directory (struct tar_stat_info *parent)
{
struct directory *directory;
char *p;
p = dir_name (name);
directory = find_directory (p);
struct directory *directory = find_directory (parent->orig_file_name);
if (directory)
{
struct stat st;
if (deref_stat (dereference_option, p, &st) != 0)
{
if (errno != ENOENT)
stat_diag (directory->name);
/* else: should have been already reported */
}
if (fstat (parent->fd, &st) != 0)
stat_diag (directory->name);
else
directory->mtime = get_stat_mtime (&st);
}
free (p);
}
#define PD_FORCE_CHILDREN 0x10
@@ -429,12 +420,12 @@ update_parent_directory (const char *name)
#define PD_CHILDREN(f) ((f) & 3)
static struct directory *
procdir (const char *name_buffer, struct stat *stat_data,
dev_t device,
procdir (const char *name_buffer, struct tar_stat_info *st,
int flag,
char *entry)
{
struct directory *directory;
struct stat *stat_data = &st->stat;
bool nfs = NFS_FILE_STAT (*stat_data);
if ((directory = find_directory (name_buffer)) != NULL)
@@ -457,14 +448,14 @@ procdir (const char *name_buffer, struct stat *stat_data,
*entry = 'N';
return directory;
}
/* With NFS, the same file can have two different devices
if an NFS directory is mounted in multiple locations,
which is relatively common when automounting.
To avoid spurious incremental redumping of
directories, consider all NFS devices as equal,
relying on the i-node to establish differences. */
if (! ((!check_device_option
|| (DIR_IS_NFS (directory) && nfs)
|| directory->device_number == stat_data->st_dev)
@@ -502,14 +493,14 @@ procdir (const char *name_buffer, struct stat *stat_data,
}
else
directory->children = CHANGED_CHILDREN;
DIR_SET_FLAG (directory, DIRF_FOUND);
}
else
{
struct directory *d = find_directory_meta (stat_data->st_dev,
stat_data->st_ino);
directory = note_directory (name_buffer,
get_stat_mtime(stat_data),
stat_data->st_dev,
@@ -548,12 +539,9 @@ procdir (const char *name_buffer, struct stat *stat_data,
}
}
/* If the directory is on another device and --one-file-system was given,
omit it... */
if (one_file_system_option && device != stat_data->st_dev
/* ... except if it was explicitely given in the command line */
&& !is_individual_file (name_buffer))
/* FIXME:
if (one_file_system_option && st->parent
&& stat_data->st_dev != st->parent->stat.st_dev)
/* FIXME:
WARNOPT (WARN_XDEV,
(0, 0,
_("%s: directory is on a different filesystem; not dumped"),
@@ -566,14 +554,14 @@ procdir (const char *name_buffer, struct stat *stat_data,
if (directory->children == NO_CHILDREN)
*entry = 'N';
}
DIR_SET_FLAG (directory, DIRF_INIT);
if (directory->children != NO_CHILDREN)
{
const char *tag_file_name;
switch (check_exclusion_tags (name_buffer, &tag_file_name))
switch (check_exclusion_tags (st, &tag_file_name))
{
case exclusion_tag_all:
/* This warning can be duplicated by code in dump_file0, but only
@@ -590,13 +578,13 @@ procdir (const char *name_buffer, struct stat *stat_data,
_("contents not dumped"));
directory->children = NO_CHILDREN;
break;
case exclusion_tag_under:
exclusion_tag_warning (name_buffer, tag_file_name,
_("contents not dumped"));
directory->tagfile = tag_file_name;
break;
case exclusion_tag_none:
break;
}
@@ -616,7 +604,7 @@ procdir (const char *name_buffer, struct stat *stat_data,
DIRECTORY->dump is replaced with the created template. Each entry is
prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
void
static void
makedumpdir (struct directory *directory, const char *dir)
{
size_t i,
@@ -682,40 +670,29 @@ makedumpdir (struct directory *directory, const char *dir)
free (array);
}
/* Recursively scan the given directory DIR.
DEVICE is the device number where DIR resides (for --one-file-system).
If CMDLINE is true, the directory name was explicitly listed in the
command line.
Unless *PDIR is NULL, store there a pointer to the struct directory
describing DIR. */
/* Recursively scan the directory identified by ST. */
struct directory *
scan_directory (char *dir, dev_t device, bool cmdline)
scan_directory (struct tar_stat_info *st)
{
char *dirp = savedir (dir); /* for scanning directory */
char const *dir = st->orig_file_name;
char *dirp = get_directory_entries (st);
dev_t device = st->stat.st_dev;
bool cmdline = ! st->parent;
namebuf_t nbuf;
char *tmp;
struct stat stat_data;
struct directory *directory;
char ch;
if (! dirp)
savedir_error (dir);
tmp = xstrdup (dir);
zap_slashes (tmp);
if (deref_stat (dereference_option, tmp, &stat_data))
{
dir_removed_diag (tmp, cmdline, stat_diag);
free (tmp);
free (dirp);
return NULL;
}
directory = procdir (tmp, &stat_data, device,
directory = procdir (tmp, st,
(cmdline ? PD_FORCE_INIT : 0),
&ch);
free (tmp);
nbuf = namebuf_create (dir);
@@ -723,7 +700,7 @@ scan_directory (char *dir, dev_t device, bool cmdline)
if (dirp && directory->children != NO_CHILDREN)
{
char *entry; /* directory entry being scanned */
dumpdir_iter_t itr;
struct dumpdir_iter *itr;
makedumpdir (directory, dirp);
@@ -739,14 +716,37 @@ scan_directory (char *dir, dev_t device, bool cmdline)
*entry = 'N';
else
{
if (deref_stat (dereference_option, full_name, &stat_data))
int fd = st->fd;
void (*diag) (char const *) = 0;
struct tar_stat_info stsub;
tar_stat_init (&stsub);
if (fd < 0)
{
file_removed_diag (full_name, false, stat_diag);
*entry = 'N';
continue;
errno = - fd;
diag = open_diag;
}
else if (fstatat (fd, entry + 1, &stsub.stat, fstatat_flags) != 0)
diag = stat_diag;
else if (S_ISDIR (stsub.stat.st_mode))
{
int subfd = subfile_open (st, entry + 1, open_read_flags);
if (subfd < 0)
diag = open_diag;
else
{
stsub.fd = subfd;
if (fstat (subfd, &stsub.stat) != 0)
diag = stat_diag;
}
}
if (S_ISDIR (stat_data.st_mode))
if (diag)
{
file_removed_diag (full_name, false, diag);
*entry = 'N';
}
else if (S_ISDIR (stsub.stat.st_mode))
{
int pd_flag = 0;
if (!recursion_option)
@@ -754,23 +754,24 @@ scan_directory (char *dir, dev_t device, bool cmdline)
else if (directory->children == ALL_CHILDREN)
pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
*entry = 'D';
procdir (full_name, &stat_data, device, pd_flag, entry);
stsub.parent = st;
procdir (full_name, &stsub, pd_flag, entry);
restore_parent_fd (&stsub);
}
else if (one_file_system_option && device != stat_data.st_dev)
else if (one_file_system_option && device != stsub.stat.st_dev)
*entry = 'N';
else if (*entry == 'Y')
/* New entry, skip further checks */;
/* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
else if (OLDER_STAT_TIME (stat_data, m)
else if (OLDER_STAT_TIME (stsub.stat, m)
&& (!after_date_option
|| OLDER_STAT_TIME (stat_data, c)))
|| OLDER_STAT_TIME (stsub.stat, c)))
*entry = 'N';
else
*entry = 'Y';
tar_stat_destroy (&stsub);
}
}
free (itr);
@@ -778,8 +779,7 @@ scan_directory (char *dir, dev_t device, bool cmdline)
namebuf_free (nbuf);
if (dirp)
free (dirp);
free (dirp);
return directory;
}
@@ -801,17 +801,11 @@ safe_directory_contents (struct directory *dir)
return ret ? ret : "\0\0\0\0";
}
void
name_fill_directory (struct name *name, dev_t device, bool cmdline)
{
name->directory = scan_directory (name->name, device, cmdline);
}
static void
obstack_code_rename (struct obstack *stk, char *from, char *to)
obstack_code_rename (struct obstack *stk, char const *from, char const *to)
{
char *s;
char const *s;
s = from[0] == 0 ? from :
safer_name_suffix (from, false, absolute_names_option);
@@ -874,7 +868,7 @@ append_incremental_renames (struct directory *dir)
size_t size;
struct directory *dp;
const char *dump;
if (dirhead == NULL)
return;
@@ -891,7 +885,8 @@ append_incremental_renames (struct directory *dir)
for (dp = dirhead; dp; dp = dp->next)
store_rename (dp, &stk);
if (obstack_object_size (&stk) != size)
/* FIXME: Is this the right thing to do when DIR is null? */
if (dir && obstack_object_size (&stk) != size)
{
obstack_1grow (&stk, 0);
dumpdir_free (dir->dump);
@@ -1217,7 +1212,7 @@ read_timespec (FILE *fp, struct timespec *pval)
/* Read incremental snapshot format 2 */
static void
read_incr_db_2 ()
read_incr_db_2 (void)
{
uintmax_t u;
struct obstack stk;
@@ -1312,7 +1307,7 @@ read_directory_file (void)
which is necessary to recreate absolute file names. */
name_from_list ();
blank_name_list ();
if (0 < getline (&buf, &bufsize, listed_incremental_stream))
{
char *ebuf;
@@ -1352,8 +1347,7 @@ read_directory_file (void)
if (ferror (listed_incremental_stream))
read_error (listed_incremental_option);
if (buf)
free (buf);
free (buf);
}
/* Output incremental data for the directory ENTRY to the file DATA.
@@ -1367,7 +1361,7 @@ write_directory_file_entry (void *entry, void *data)
if (DIR_IS_FOUND (directory))
{
char buf[UINTMAX_STRSIZE_BOUND];
char *s;
char const *s;
s = DIR_IS_NFS (directory) ? "1" : "0";
fwrite (s, 2, 1, fp);
@@ -1386,7 +1380,7 @@ write_directory_file_entry (void *entry, void *data)
if (directory->dump)
{
const char *p;
dumpdir_iter_t itr;
struct dumpdir_iter *itr;
for (p = dumpdir_first (directory->dump, 0, &itr);
p;
@@ -1452,7 +1446,7 @@ get_gnu_dumpdir (struct tar_stat_info *stat_info)
to = archive_dir;
set_next_block_after (current_header);
mv_begin (stat_info);
mv_begin_read (stat_info);
for (; size > 0; size -= copied)
{
@@ -1664,11 +1658,10 @@ try_purge_directory (char const *directory_name)
{
const char *entry;
struct stat st;
if (p)
free (p);
free (p);
p = new_name (directory_name, cur);
if (deref_stat (false, p, &st))
if (deref_stat (p, &st) != 0)
{
if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
dirs and check it here? */
@@ -1707,7 +1700,7 @@ try_purge_directory (char const *directory_name)
}
free (p);
dumpdir_free (dump);
free (current_dir);
return true;
}

View File

@@ -35,6 +35,20 @@ size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
size_t recent_long_link_blocks; /* likewise, for long link */
union block *recent_global_header; /* Recent global header block */
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
#define MODE_FROM_HEADER(where, hbits) \
mode_from_header (where, sizeof (where), hbits)
#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
static gid_t gid_from_header (const char *buf, size_t size);
static major_t major_from_header (const char *buf, size_t size);
static minor_t minor_from_header (const char *buf, size_t size);
static mode_t mode_from_header (const char *buf, size_t size, unsigned *hbits);
static time_t time_from_header (const char *buf, size_t size);
static uid_t uid_from_header (const char *buf, size_t size);
static uintmax_t from_header (const char *, size_t, const char *,
uintmax_t, uintmax_t, bool, bool);
@@ -61,6 +75,66 @@ base64_init (void)
base64_map[(int) base_64_digits[i]] = i;
}
static char *
decode_xform (char *file_name, void *data)
{
int type = *(int*)data;
switch (type)
{
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
name suffix normalization, but subject to filename transformation
proper. */
return file_name;
case XFORM_LINK:
file_name = safer_name_suffix (file_name, true, absolute_names_option);
break;
case XFORM_REGFILE:
file_name = safer_name_suffix (file_name, false, absolute_names_option);
break;
}
if (strip_name_components)
{
size_t prefix_len = stripped_prefix_len (file_name,
strip_name_components);
if (prefix_len == (size_t) -1)
prefix_len = strlen (file_name);
file_name += prefix_len;
}
return file_name;
}
static bool
transform_member_name (char **pinput, int type)
{
return transform_name_fp (pinput, type, decode_xform, &type);
}
void
transform_stat_info (int typeflag, struct tar_stat_info *stat_info)
{
if (typeflag == GNUTYPE_VOLHDR)
/* Name transformations don't apply to volume headers. */
return;
transform_member_name (&stat_info->file_name, XFORM_REGFILE);
switch (typeflag)
{
case SYMTYPE:
transform_member_name (&stat_info->link_name, XFORM_SYMLINK);
break;
case LNKTYPE:
transform_member_name (&stat_info->link_name, XFORM_LINK);
}
}
/* Main loop for reading an archive. */
void
read_and (void (*do_something) (void))
@@ -78,7 +152,7 @@ read_and (void (*do_something) (void))
prev_status = status;
tar_stat_destroy (&current_stat_info);
status = read_header (&current_header, &current_stat_info,
status = read_header (&current_header, &current_stat_info,
read_header_auto);
switch (status)
{
@@ -90,7 +164,8 @@ read_and (void (*do_something) (void))
/* Valid header. We should decode next field (mode) first.
Ensure incoming names are null terminated. */
decode_header (current_header, &current_stat_info,
&current_format, 1);
if (! name_match (current_stat_info.file_name)
|| (NEWER_OPTION_INITIALIZED (newer_mtime_option)
/* FIXME: We get mtime now, and again later; this causes
@@ -116,13 +191,12 @@ read_and (void (*do_something) (void))
quotearg_colon (current_stat_info.file_name)));
/* Fall through. */
default:
decode_header (current_header,
&current_stat_info, &current_format, 0);
skip_member ();
continue;
}
}
transform_stat_info (current_header->header.typeflag,
&current_stat_info);
(*do_something) ();
continue;
@@ -140,7 +214,7 @@ read_and (void (*do_something) (void))
{
char buf[UINTMAX_STRSIZE_BOUND];
status = read_header (&current_header, &current_stat_info,
status = read_header (&current_header, &current_stat_info,
read_header_auto);
if (status == HEADER_ZERO_BLOCK)
break;
@@ -210,8 +284,6 @@ list_archive (void)
off_t block_ordinal = current_block_ordinal ();
/* Print the header block. */
decode_header (current_header, &current_stat_info, &current_format, 0);
if (verbose_option)
print_header (&current_stat_info, current_header, block_ordinal);
@@ -361,15 +433,13 @@ read_header (union block **return_block, struct tar_stat_info *info,
if (header->header.typeflag == GNUTYPE_LONGNAME)
{
if (next_long_name)
free (next_long_name);
free (next_long_name);
next_long_name = header_copy;
next_long_name_blocks = size / BLOCKSIZE;
}
else
{
if (next_long_link)
free (next_long_link);
free (next_long_link);
next_long_link = header_copy;
next_long_link_blocks = size / BLOCKSIZE;
}
@@ -428,8 +498,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
struct posix_header const *h = &header->header;
char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
if (recent_long_name)
free (recent_long_name);
free (recent_long_name);
if (next_long_name)
{
@@ -460,8 +529,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
assign_string (&info->file_name, name);
info->had_trailing_slash = strip_trailing_slashes (info->file_name);
if (recent_long_link)
free (recent_long_link);
free (recent_long_link);
if (next_long_link)
{
@@ -484,47 +552,6 @@ read_header (union block **return_block, struct tar_stat_info *info,
}
}
static char *
decode_xform (char *file_name, void *data)
{
int type = *(int*)data;
switch (type)
{
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
name suffix normalization, but subject to filename transformation
proper. */
return file_name;
case XFORM_LINK:
file_name = safer_name_suffix (file_name, true, absolute_names_option);
break;
case XFORM_REGFILE:
file_name = safer_name_suffix (file_name, false, absolute_names_option);
break;
}
if (strip_name_components)
{
size_t prefix_len = stripped_prefix_len (file_name,
strip_name_components);
if (prefix_len == (size_t) -1)
prefix_len = strlen (file_name);
file_name += prefix_len;
}
return file_name;
}
bool
transform_member_name (char **pinput, int type)
{
return transform_name_fp (pinput, type, decode_xform, &type);
}
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
/* Decode things from a file HEADER block into STAT_INFO, also setting
@@ -547,7 +574,7 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
enum archive_format format;
unsigned hbits; /* high bits of the file mode. */
mode_t mode = MODE_FROM_HEADER (header->header.mode, &hbits);
if (strcmp (header->header.magic, TMAGIC) == 0)
{
if (header->star_header.prefix[130] == 0
@@ -561,7 +588,9 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
else
format = USTAR_FORMAT;
}
else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
else if (strcmp (header->buffer + offsetof (struct posix_header, magic),
OLDGNU_MAGIC)
== 0)
format = hbits ? OLDGNU_FORMAT : GNU_FORMAT;
else
format = V7_FORMAT;
@@ -644,19 +673,9 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|| stat_info->dumpdir)
stat_info->is_dumpdir = true;
}
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
uintmax_t. DIGS must be positive. If TYPE is nonnull, the data
are of type TYPE. The buffer must represent a value in the range
@@ -877,7 +896,7 @@ from_header (char const *where0, size_t digs, char const *type,
return -1;
}
gid_t
static gid_t
gid_from_header (const char *p, size_t s)
{
return from_header (p, s, "gid_t",
@@ -886,7 +905,7 @@ gid_from_header (const char *p, size_t s)
false, false);
}
major_t
static major_t
major_from_header (const char *p, size_t s)
{
return from_header (p, s, "major_t",
@@ -894,7 +913,7 @@ major_from_header (const char *p, size_t s)
(uintmax_t) TYPE_MAXIMUM (major_t), false, false);
}
minor_t
static minor_t
minor_from_header (const char *p, size_t s)
{
return from_header (p, s, "minor_t",
@@ -904,7 +923,7 @@ minor_from_header (const char *p, size_t s)
/* Convert P to the file mode, as understood by tar.
Store unrecognized mode bits (from 10th up) in HBITS. */
mode_t
static mode_t
mode_from_header (const char *p, size_t s, unsigned *hbits)
{
unsigned u = from_header (p, s, "mode_t",
@@ -935,14 +954,7 @@ off_from_header (const char *p, size_t s)
(uintmax_t) TYPE_MAXIMUM (off_t), false, false);
}
size_t
size_from_header (const char *p, size_t s)
{
return from_header (p, s, "size_t", (uintmax_t) 0,
(uintmax_t) TYPE_MAXIMUM (size_t), false, false);
}
time_t
static time_t
time_from_header (const char *p, size_t s)
{
return from_header (p, s, "time_t",
@@ -950,7 +962,7 @@ time_from_header (const char *p, size_t s)
(uintmax_t) TYPE_MAXIMUM (time_t), false, false);
}
uid_t
static uid_t
uid_from_header (const char *p, size_t s)
{
return from_header (p, s, "uid_t",
@@ -1146,7 +1158,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
/* Time stamp. */
time_stamp = tartime (st->mtime, false);
time_stamp = tartime (st->mtime, full_time_option);
time_stamp_len = strlen (time_stamp);
if (datewidth < time_stamp_len)
datewidth = time_stamp_len;
@@ -1292,8 +1304,8 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
}
void
print_volume_label ()
static void
print_volume_label (void)
{
struct tar_stat_info vstat;
union block vblk;
@@ -1356,7 +1368,7 @@ skip_file (off_t size)
{
union block *x;
/* FIXME: Make sure mv_begin is always called before it */
/* FIXME: Make sure mv_begin_read is always called before it */
if (seekable_archive)
{
@@ -1391,7 +1403,7 @@ skip_member (void)
char save_typeflag = current_header->header.typeflag;
set_next_block_after (current_header);
mv_begin (&current_stat_info);
mv_begin_read (&current_stat_info);
if (current_stat_info.is_sparse)
sparse_skip_file (&current_stat_info);
@@ -1412,22 +1424,23 @@ test_archive_label ()
if (read_header (&current_header, &current_stat_info, read_header_auto)
== HEADER_SUCCESS)
{
char *s = NULL;
decode_header (current_header,
&current_stat_info, &current_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 ();
}

View File

@@ -1,7 +1,7 @@
/* Miscellaneous functions, not really specific to GNU tar.
Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
2003, 2004, 2005, 2006, 2007, 2009, 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
@@ -21,17 +21,12 @@
#include <rmt.h>
#include "common.h"
#include <quotearg.h>
#include <save-cwd.h>
#include <xgetcwd.h>
#include <unlinkdir.h>
#include <utimens.h>
#include <canonicalize.h>
#if HAVE_STROPTS_H
# include <stropts.h>
#endif
#if HAVE_SYS_FILIO_H
# include <sys/filio.h>
#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
#endif
@@ -42,11 +37,13 @@
void
assign_string (char **string, const char *value)
{
if (*string)
free (*string);
free (*string);
*string = value ? xstrdup (value) : 0;
}
#if 0
/* This function is currently unused; perhaps it should be removed? */
/* Allocate a copy of the string quoted as in C, and returns that. If
the string does not have to be quoted, it returns a null pointer.
The allocated copy should normally be freed with free() after the
@@ -59,7 +56,7 @@ assign_string (char **string, const char *value)
when reading directory files. This means that we can't use
quotearg, as quotearg is locale-dependent and is meant for human
consumption. */
char *
static char *
quote_copy_string (const char *string)
{
const char *source = string;
@@ -100,6 +97,7 @@ quote_copy_string (const char *string)
}
return 0;
}
#endif
/* Takes a quoted C string (like those produced by quote_copy_string)
and turns it back into the un-quoted original. This is done in
@@ -230,10 +228,79 @@ zap_slashes (char *name)
return name;
}
/* Normalize FILE_NAME by removing redundant slashes and "."
components, including redundant trailing slashes. Leave ".."
alone, as it may be significant in the presence of symlinks and on
platforms where "/.." != "/". Destructive version: modifies its
argument. */
static void
normalize_filename_x (char *file_name)
{
char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
char *p;
char const *q;
char c;
/* Don't squeeze leading "//" to "/", on hosts where they're distinct. */
name += (DOUBLE_SLASH_IS_DISTINCT_ROOT
&& ISSLASH (*name) && ISSLASH (name[1]) && ! ISSLASH (name[2]));
/* Omit redundant leading "." components. */
for (q = p = name; (*p = *q) == '.' && ISSLASH (q[1]); p += !*q)
for (q += 2; ISSLASH (*q); q++)
continue;
/* Copy components from Q to P, omitting redundant slashes and
internal "." components. */
while ((*p++ = c = *q++) != '\0')
if (ISSLASH (c))
while (ISSLASH (q[*q == '.']))
q += (*q == '.') + 1;
/* Omit redundant trailing "." component and slash. */
if (2 < p - name)
{
p -= p[-2] == '.' && ISSLASH (p[-3]);
p -= 2 < p - name && ISSLASH (p[-2]);
p[-1] = '\0';
}
}
/* Normalize NAME by removing redundant slashes and "." components,
including redundant trailing slashes. Return a normalized
newly-allocated copy. */
char *
normalize_filename (const char *name)
{
return zap_slashes (canonicalize_filename_mode (name, CAN_MISSING));
char *copy = NULL;
if (IS_RELATIVE_FILE_NAME (name))
{
/* Set COPY to the absolute file name if possible.
FIXME: There should be no need to get the absolute file name.
getcwd is slow, it might fail, and it does not necessarily
return a canonical name even when it succeeds. Perhaps we
can use dev+ino pairs instead of names? */
copy = xgetcwd ();
if (copy)
{
size_t copylen = strlen (copy);
bool need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT
&& copylen == 2 && ISSLASH (copy[1]));
copy = xrealloc (copy, copylen + need_separator + strlen (name) + 1);
copy[copylen] = DIRECTORY_SEPARATOR;
strcpy (copy + copylen + need_separator, name);
}
else
WARN ((0, errno, _("Cannot get working directory")));
}
if (! copy)
copy = xstrdup (name);
normalize_filename_x (copy);
return copy;
}
@@ -301,7 +368,7 @@ code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
/* ignore invalid values of ns */
if (BILLION <= ns || ns < 0)
ns = 0;
if (negative && ns != 0)
{
s++;
@@ -322,7 +389,7 @@ static char *before_backup_name;
static char *after_backup_name;
/* Return 1 if FILE_NAME is obviously "." or "/". */
static bool
bool
must_be_dot_or_slash (char const *file_name)
{
file_name += FILE_SYSTEM_PREFIX_LEN (file_name);
@@ -363,7 +430,7 @@ safer_rmdir (const char *file_name)
return -1;
}
return rmdir (file_name);
return unlinkat (chdir_fd, file_name, AT_REMOVEDIR);
}
/* Remove FILE_NAME, returning 1 on success. If FILE_NAME is a directory,
@@ -383,7 +450,7 @@ remove_any_file (const char *file_name, enum remove_option option)
if (try_unlink_first)
{
if (unlink (file_name) == 0)
if (unlinkat (chdir_fd, file_name, 0) == 0)
return 1;
/* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
@@ -399,7 +466,7 @@ remove_any_file (const char *file_name, enum remove_option option)
switch (errno)
{
case ENOTDIR:
return !try_unlink_first && unlink (file_name) == 0;
return !try_unlink_first && unlinkat (chdir_fd, file_name, 0) == 0;
case 0:
case EEXIST:
@@ -476,7 +543,7 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
if (this_is_the_archive && _remdev (file_name))
return true;
if (stat (file_name, &file_stat))
if (deref_stat (file_name, &file_stat) != 0)
{
if (errno == ENOENT)
return true;
@@ -496,7 +563,8 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
if (! after_backup_name)
xalloc_die ();
if (rename (before_backup_name, after_backup_name) == 0)
if (renameat (chdir_fd, before_backup_name, chdir_fd, after_backup_name)
== 0)
{
if (verbose_option)
fprintf (stdlis, _("Renaming %s to %s\n"),
@@ -523,7 +591,8 @@ undo_last_backup (void)
{
if (after_backup_name)
{
if (rename (after_backup_name, before_backup_name) != 0)
if (renameat (chdir_fd, after_backup_name, chdir_fd, before_backup_name)
!= 0)
{
int e = errno;
ERROR ((0, e, _("%s: Cannot rename to %s"),
@@ -538,39 +607,36 @@ undo_last_backup (void)
}
}
/* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */
/* Apply either stat or lstat to (NAME, BUF), depending on the
presence of the --dereference option. NAME is relative to the
most-recent argument to chdir_do. */
int
deref_stat (bool deref, char const *name, struct stat *buf)
deref_stat (char const *name, struct stat *buf)
{
return deref ? stat (name, buf) : lstat (name, buf);
return fstatat (chdir_fd, name, buf, fstatat_flags);
}
/* Set FD's (i.e., FILE's) access time to TIMESPEC[0]. If that's not
possible to do by itself, set its access and data modification
times to TIMESPEC[0] and TIMESPEC[1], respectively. */
/* Set FD's (i.e., assuming the working directory is PARENTFD, FILE's)
access time to ATIME. */
int
set_file_atime (int fd, char const *file, struct timespec const timespec[2])
set_file_atime (int fd, int parentfd, char const *file, struct timespec atime)
{
#ifdef _FIOSATIME
if (0 <= fd)
{
struct timeval timeval;
timeval.tv_sec = timespec[0].tv_sec;
timeval.tv_usec = timespec[0].tv_nsec / 1000;
if (ioctl (fd, _FIOSATIME, &timeval) == 0)
return 0;
}
#endif
return gl_futimens (fd, file, timespec);
struct timespec ts[2];
ts[0] = atime;
ts[1].tv_nsec = UTIME_OMIT;
return fdutimensat (fd, parentfd, file, ts, fstatat_flags);
}
/* A description of a working directory. */
struct wd
{
/* The directory's name. */
char const *name;
int saved;
struct saved_cwd saved_cwd;
/* If nonzero, the file descriptor of the directory, or AT_FDCWD if
the working directory. If zero, the directory needs to be opened
to be used. */
int fd;
};
/* A vector of chdir targets. wd[0] is the initial working directory. */
@@ -582,6 +648,19 @@ static size_t wd_count;
/* The allocated size of the vector. */
static size_t wd_alloc;
/* The maximum number of chdir targets with open directories.
Don't make it too large, as many operating systems have a small
limit on the number of open file descriptors. Also, the current
implementation does not scale well. */
enum { CHDIR_CACHE_SIZE = 16 };
/* Indexes into WD of chdir targets with open file descriptors, sorted
most-recently used first. Zero indexes are unused. */
static int wdcache[CHDIR_CACHE_SIZE];
/* Number of nonzero entries in WDCACHE. */
static size_t wdcache_count;
int
chdir_count ()
{
@@ -608,7 +687,7 @@ chdir_arg (char const *dir)
if (! wd_count)
{
wd[wd_count].name = ".";
wd[wd_count].saved = 0;
wd[wd_count].fd = AT_FDCWD;
wd_count++;
}
}
@@ -625,64 +704,76 @@ chdir_arg (char const *dir)
}
wd[wd_count].name = dir;
wd[wd_count].saved = 0;
wd[wd_count].fd = 0;
return wd_count++;
}
/* Change to directory I. If I is 0, change to the initial working
directory; otherwise, I must be a value returned by chdir_arg. */
/* Index of current directory. */
int chdir_current;
/* Value suitable for use as the first argument to openat, and in
similar locations for fstatat, etc. This is an open file
descriptor, or AT_FDCWD if the working directory is current. It is
valid until the next invocation of chdir_do. */
int chdir_fd = AT_FDCWD;
/* Change to directory I, in a virtual way. This does not actually
invoke chdir; it merely sets chdir_fd to an int suitable as the
first argument for openat, etc. If I is 0, change to the initial
working directory; otherwise, I must be a value returned by
chdir_arg. */
void
chdir_do (int i)
{
static int previous;
if (previous != i)
if (chdir_current != i)
{
struct wd *prev = &wd[previous];
struct wd *curr = &wd[i];
int fd = curr->fd;
if (! prev->saved)
if (! fd)
{
int err = 0;
prev->saved = 1;
if (save_cwd (&prev->saved_cwd) != 0)
err = errno;
else if (0 <= prev->saved_cwd.desc)
{
/* Make sure we still have at least one descriptor available. */
int fd1 = prev->saved_cwd.desc;
int fd2 = dup (fd1);
if (0 <= fd2)
close (fd2);
else if (errno == EMFILE)
{
/* Force restore_cwd to use chdir_long. */
close (fd1);
prev->saved_cwd.desc = -1;
prev->saved_cwd.name = xgetcwd ();
}
else
err = errno;
}
if (err)
FATAL_ERROR ((0, err, _("Cannot save working directory")));
}
if (curr->saved)
{
if (restore_cwd (&curr->saved_cwd))
FATAL_ERROR ((0, 0, _("Cannot change working directory")));
}
else
{
if (i && ! ISSLASH (curr->name[0]))
if (! IS_ABSOLUTE_FILE_NAME (curr->name))
chdir_do (i - 1);
if (chdir (curr->name) != 0)
chdir_fatal (curr->name);
fd = openat (chdir_fd, curr->name,
open_searchdir_flags & ~ O_NOFOLLOW);
if (fd < 0)
open_fatal (curr->name);
curr->fd = fd;
/* Add I to the cache, tossing out the lowest-ranking entry if the
cache is full. */
if (wdcache_count < CHDIR_CACHE_SIZE)
wdcache[wdcache_count++] = i;
else
{
struct wd *stale = &wd[wdcache[CHDIR_CACHE_SIZE - 1]];
if (close (stale->fd) != 0)
close_diag (stale->name);
stale->fd = 0;
wdcache[CHDIR_CACHE_SIZE - 1] = i;
}
}
previous = i;
if (0 < fd)
{
/* Move the i value to the front of the cache. This is
O(CHDIR_CACHE_SIZE), but the cache is small. */
size_t ci;
int prev = wdcache[0];
for (ci = 1; prev != i; ci++)
{
int curr = wdcache[ci];
wdcache[ci] = prev;
if (curr == i)
break;
prev = curr;
}
wdcache[0] = i;
}
chdir_current = i;
chdir_fd = fd;
}
}
@@ -759,21 +850,6 @@ file_removed_diag (const char *name, bool top_level,
(0, 0, _("%s: File removed before we read it"),
quotearg_colon (name)));
set_exit_status (TAREXIT_DIFFERS);
}
else
diagfn (name);
}
void
dir_removed_diag (const char *name, bool top_level,
void (*diagfn) (char const *name))
{
if (!top_level && errno == ENOENT)
{
WARNOPT (WARN_FILE_REMOVED,
(0, 0, _("%s: Directory removed before we read it"),
quotearg_colon (name)));
set_exit_status (TAREXIT_DIFFERS);
}
else
diagfn (name);
@@ -869,6 +945,3 @@ namebuf_name (namebuf_t buf, const char *name)
strcpy (buf->buffer + buf->dir_length, name);
return buf->buffer;
}

View File

@@ -27,15 +27,6 @@
/* User and group names. */
struct group *getgrnam ();
struct passwd *getpwnam ();
#if ! HAVE_DECL_GETPWUID
struct passwd *getpwuid ();
#endif
#if ! HAVE_DECL_GETGRGID
struct group *getgrgid ();
#endif
/* Make sure you link with the proper libraries if you are running the
Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
This code should also be modified for non-UNIX systems to do something
@@ -56,8 +47,6 @@ static char *cached_no_such_gname;
static uid_t cached_no_such_uid;
static gid_t cached_no_such_gid;
static void register_individual_file (char const *name);
/* Given UID, find the corresponding UNAME. */
void
uid_to_uname (uid_t uid, char **uname)
@@ -179,7 +168,7 @@ gname_to_gid (char const *gname, gid_t *gidp)
}
struct name *
static struct name *
make_name (const char *file_name)
{
struct name *p = xzalloc (sizeof (*p));
@@ -190,7 +179,7 @@ make_name (const char *file_name)
return p;
}
void
static void
free_name (struct name *p)
{
if (p)
@@ -207,7 +196,7 @@ free_name (struct name *p)
static struct name *namelist; /* first name in list, if any */
static struct name *nametail; /* end of name list */
/* File name arguments are processed in two stages: first a
/* File name arguments are processed in two stages: first a
name_array (see below) is filled, then the names from it
are moved into the namelist.
@@ -215,7 +204,7 @@ static struct name *nametail; /* end of name list */
which is meant to help process large archives on machines with
limited memory. With this option on, namelist contains at most one
entry, which diminishes the memory consumption.
However, I very much doubt if we still need this -- Sergey */
/* A name_array element contains entries of three types: */
@@ -230,24 +219,25 @@ struct name_elt /* A name_array element. */
union
{
const char *name; /* File or directory name */
int matching_flags;/* fnmatch options if type == NELT_FMASK */
int matching_flags;/* fnmatch options if type == NELT_FMASK */
} v;
};
static struct name_elt *name_array; /* store an array of names */
static size_t allocated_names; /* how big is the array? */
static size_t names; /* how many entries does it have? */
static size_t name_index; /* how many of the entries have we scanned? */
static size_t allocated_entries; /* how big is the array? */
static size_t entries; /* how many entries does it have? */
static size_t scanned; /* how many of the entries have we scanned? */
size_t name_count; /* how many of the entries are names? */
/* Check the size of name_array, reallocating it as necessary. */
static void
check_name_alloc ()
check_name_alloc (void)
{
if (names == allocated_names)
if (entries == allocated_entries)
{
if (allocated_names == 0)
allocated_names = 10; /* Set initial allocation */
name_array = x2nrealloc (name_array, &allocated_names,
if (allocated_entries == 0)
allocated_entries = 10; /* Set initial allocation */
name_array = x2nrealloc (name_array, &allocated_entries,
sizeof (name_array[0]));
}
}
@@ -260,17 +250,18 @@ name_add_name (const char *name, int matching_flags)
struct name_elt *ep;
check_name_alloc ();
ep = &name_array[names++];
ep = &name_array[entries++];
if (prev_flags != matching_flags)
{
ep->type = NELT_FMASK;
ep->v.matching_flags = matching_flags;
prev_flags = matching_flags;
check_name_alloc ();
ep = &name_array[names++];
ep = &name_array[entries++];
}
ep->type = NELT_NAME;
ep->v.name = name;
name_count++;
}
/* Add to name_array a chdir request for the directory NAME */
@@ -279,10 +270,10 @@ name_add_dir (const char *name)
{
struct name_elt *ep;
check_name_alloc ();
ep = &name_array[names++];
ep = &name_array[entries++];
ep->type = NELT_CHDIR;
ep->v.name = name;
}
}
/* Names from external name file. */
@@ -313,28 +304,28 @@ static int matching_flags; /* exclude_fnmatch options */
If CHANGE_DIRS is true, treat any entries of type NELT_CHDIR as
the request to change to the given directory.
Entries of type NELT_FMASK cause updates of the matching_flags
value. */
struct name_elt *
static struct name_elt *
name_next_elt (int change_dirs)
{
static struct name_elt entry;
const char *source;
char *cursor;
while (name_index != names)
while (scanned != entries)
{
struct name_elt *ep;
size_t source_len;
ep = &name_array[name_index++];
ep = &name_array[scanned++];
if (ep->type == NELT_FMASK)
{
matching_flags = ep->v.matching_flags;
continue;
}
source = ep->v.name;
source_len = strlen (source);
if (name_buffer_length < source_len)
@@ -367,8 +358,6 @@ name_next_elt (int change_dirs)
{
if (unquote_option)
unquote_string (name_buffer);
if (incremental_option)
register_individual_file (name_buffer);
entry.type = ep->type;
entry.v.name = name_buffer;
return &entry;
@@ -421,7 +410,7 @@ name_gather (void)
buffer->directory = NULL;
buffer->parent = NULL;
buffer->cmdline = true;
namelist = nametail = buffer;
}
else if (change_dir)
@@ -519,7 +508,7 @@ name_match (const char *file_name)
if (!cursor)
return true;
if (cursor->name[0] == 0)
{
chdir_do (cursor->change_dir);
@@ -589,7 +578,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 +592,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 +605,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,13 +628,49 @@ 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. */
/* Sort *singly* linked LIST of names, of given LENGTH, using COMPARE
to order names. Return the sorted list. Note that after calling
this function, the `prev' links in list elements are messed up.
Apart from the type `struct name' and the definition of SUCCESSOR,
this is a generic list-sorting function, but it's too painful to
make it both generic and portable
@@ -752,17 +777,15 @@ compare_names (struct name const *n1, struct name const *n2)
}
/* Add all the dirs under NAME, which names a directory, to the namelist.
If any of the files is a directory, recurse on the subdirectory.
DEVICE is the device not to leave, if the -l option is specified.
CMDLINE is true, if the NAME appeared on the command line. */
/* Add all the dirs under ST to the namelist NAME, descending the
directory hierarchy recursively. */
static void
add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline)
add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
{
const char *buffer;
name_fill_directory (name, device, cmdline);
name->directory = scan_directory (st);
buffer = directory_contents (name->directory);
if (buffer)
{
@@ -790,6 +813,8 @@ add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline)
if (*string == 'D')
{
struct name *np;
struct tar_stat_info subdir;
int subfd;
if (allocated_length <= name_length + string_length)
{
@@ -810,7 +835,38 @@ add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline)
else
child_tail->sibling = np;
child_tail = np;
add_hierarchy_to_namelist (np, device, false);
tar_stat_init (&subdir);
subdir.parent = st;
if (st->fd < 0)
{
subfd = -1;
errno = - st->fd;
}
else
subfd = subfile_open (st, string + 1,
open_read_flags | O_DIRECTORY);
if (subfd < 0)
open_diag (namebuf);
else
{
subdir.fd = subfd;
if (fstat (subfd, &subdir.stat) != 0)
stat_diag (namebuf);
else if (! (O_DIRECTORY || S_ISDIR (subdir.stat.st_mode)))
{
errno = ENOTDIR;
open_diag (namebuf);
}
else
{
subdir.orig_file_name = xstrdup (namebuf);
add_hierarchy_to_namelist (&subdir, np);
restore_parent_fd (&subdir);
}
}
tar_stat_destroy (&subdir);
}
}
@@ -846,7 +902,7 @@ rebase_child_list (struct name *child, struct name *parent)
size_t old_prefix_len = child->parent->length;
size_t new_prefix_len = parent->length;
char *new_prefix = parent->name;
for (; child; child = child->sibling)
{
size_t size = child->length - old_prefix_len + new_prefix_len;
@@ -858,7 +914,7 @@ rebase_child_list (struct name *child, struct name *parent)
child->length = size;
rebase_directory (child->directory,
child->parent->name, old_prefix_len,
child->parent->name, old_prefix_len,
new_prefix, new_prefix_len);
}
}
@@ -871,11 +927,10 @@ 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;
name_gather ();
if (!namelist)
@@ -903,10 +958,12 @@ collect_and_sort_names (void)
read_directory_file ();
}
num_names = 0;
for (name = namelist; name; name = name->next, num_names++)
{
struct tar_stat_info st;
if (name->found_count || name->directory)
continue;
if (name->matching_flags & EXCLUDE_WILDCARDS)
@@ -918,16 +975,34 @@ collect_and_sort_names (void)
if (name->name[0] == 0)
continue;
if (deref_stat (dereference_option, name->name, &statbuf) != 0)
tar_stat_init (&st);
if (deref_stat (name->name, &st.stat) != 0)
{
stat_diag (name->name);
continue;
}
if (S_ISDIR (statbuf.st_mode))
if (S_ISDIR (st.stat.st_mode))
{
name->found_count++;
add_hierarchy_to_namelist (name, statbuf.st_dev, true);
int dir_fd = openat (chdir_fd, name->name,
open_read_flags | O_DIRECTORY);
if (dir_fd < 0)
open_diag (name->name);
else
{
st.fd = dir_fd;
if (fstat (dir_fd, &st.stat) != 0)
stat_diag (name->name);
else if (O_DIRECTORY || S_ISDIR (st.stat.st_mode))
{
st.orig_file_name = xstrdup (name->name);
name->found_count++;
add_hierarchy_to_namelist (&st, name);
}
}
}
tar_stat_destroy (&st);
}
namelist = merge_sort (namelist, num_names, compare_names);
@@ -950,6 +1025,7 @@ collect_and_sort_names (void)
{
if (p->child)
rebase_child_list (p->child, name);
hash_delete (nametab, name);
/* FIXME: remove_directory (p->caname); ? */
remname (p);
free_name (p);
@@ -1071,28 +1147,6 @@ excluded_name (char const *name)
{
return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
}
static Hash_table *individual_file_table;
static void
register_individual_file (char const *name)
{
struct stat st;
if (deref_stat (dereference_option, name, &st) != 0)
return; /* Will be complained about later */
if (S_ISDIR (st.st_mode))
return;
hash_string_insert (&individual_file_table, name);
}
bool
is_individual_file (char const *name)
{
return hash_string_lookup (individual_file_table, name);
}
/* Return the size of the prefix of FILE_NAME that is removed after

View File

@@ -1,6 +1,7 @@
/* Functions for dealing with sparse files
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 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
@@ -216,43 +217,45 @@ sparse_scan_file (struct tar_sparse_file *file)
struct tar_stat_info *st = file->stat_info;
int fd = file->fd;
char buffer[BLOCKSIZE];
size_t count;
size_t count = 0;
off_t offset = 0;
struct sp_array sp = {0, 0};
if (!lseek_or_error (file, 0))
return false;
st->archive_file_size = 0;
if (!tar_sparse_scan (file, scan_begin, NULL))
return false;
while ((count = safe_read (fd, buffer, sizeof buffer)) != 0
&& count != SAFE_READ_ERROR)
if (ST_NBLOCKS (st->stat) == 0)
offset = st->stat.st_size;
else
{
/* Analyze the block. */
if (zero_block_p (buffer, count))
if (!tar_sparse_scan (file, scan_begin, NULL))
return false;
while ((count = safe_read (fd, buffer, sizeof buffer)) != 0
&& count != SAFE_READ_ERROR)
{
if (sp.numbytes)
/* Analyze the block. */
if (zero_block_p (buffer, count))
{
sparse_add_map (st, &sp);
sp.numbytes = 0;
if (!tar_sparse_scan (file, scan_block, NULL))
if (sp.numbytes)
{
sparse_add_map (st, &sp);
sp.numbytes = 0;
if (!tar_sparse_scan (file, scan_block, NULL))
return false;
}
}
else
{
if (sp.numbytes == 0)
sp.offset = offset;
sp.numbytes += count;
st->archive_file_size += count;
if (!tar_sparse_scan (file, scan_block, buffer))
return false;
}
}
else
{
if (sp.numbytes == 0)
sp.offset = offset;
sp.numbytes += count;
st->archive_file_size += count;
if (!tar_sparse_scan (file, scan_block, buffer))
return false;
}
offset += count;
offset += count;
}
}
if (sp.numbytes == 0)
@@ -324,7 +327,6 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
bytes_left -= bytes_read;
file->dumped_size += bytes_read;
mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
set_next_block_after (blk);
}
@@ -334,7 +336,7 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
static bool
sparse_extract_region (struct tar_sparse_file *file, size_t i)
{
size_t write_size;
off_t write_size;
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
return false;
@@ -398,10 +400,11 @@ sparse_dump_file (int fd, struct tar_stat_info *st)
{
size_t i;
mv_begin (file.stat_info);
mv_begin_write (file.stat_info->file_name,
file.stat_info->stat.st_size,
file.stat_info->archive_file_size - file.dumped_size);
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
rc = tar_sparse_dump_region (&file, i);
mv_end ();
}
}
@@ -508,13 +511,13 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
static bool
check_data_region (struct tar_sparse_file *file, size_t i)
{
size_t size_left;
off_t size_left;
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
return false;
size_left = file->stat_info->sparse_map[i].numbytes;
mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
while (size_left > 0)
{
size_t bytes_read;
@@ -564,9 +567,9 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
file.stat_info = st;
file.fd = fd;
file.seekable = true; /* File *must* be seekable for compare to work */
rc = tar_sparse_decode_header (&file);
mv_begin (st);
mv_begin_read (st);
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
{
rc = check_sparse_region (&file,
@@ -579,7 +582,7 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
if (!rc)
skip_file (file.stat_info->archive_file_size - file.dumped_size);
mv_end ();
tar_sparse_done (&file);
return rc;
}
@@ -625,8 +628,9 @@ oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
if (s->numbytes[0] == '\0')
return add_finish;
sp.offset = OFF_FROM_HEADER (s->offset);
sp.numbytes = SIZE_FROM_HEADER (s->numbytes);
sp.numbytes = OFF_FROM_HEADER (s->numbytes);
if (sp.offset < 0
|| sp.offset + sp.numbytes < 0
|| file->stat_info->stat.st_size < sp.offset + sp.numbytes
|| file->stat_info->archive_file_size < 0)
return add_fail;
@@ -695,8 +699,8 @@ oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
{
OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
sp->offset);
SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
sp->numbytes);
OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
sp->numbytes);
}
}
@@ -851,13 +855,13 @@ static struct tar_sparse_optab const star_optab = {
instances of GNU.sparse.offset/GNU.sparse.numbytes variables, whereas
POSIX requires the latest occurrence of the variable to override all
previous occurrences.
To avoid this incompatibility two following versions were introduced.
* 0.1
Used by tar 1.15.2 -- 1.15.91 (alpha releases).
The sparse file map is stored in
x header:
@@ -875,18 +879,18 @@ static struct tar_sparse_optab const star_optab = {
Starting from this version, the exact sparse format version is specified
explicitely in the header using the following variables:
GNU.sparse.major Major version
GNU.sparse.major Major version
GNU.sparse.minor Minor version
X header keeps the following variables:
GNU.sparse.name Real file name of the sparse file
GNU.sparse.realsize Real size of the stored file (corresponds to the old
GNU.sparse.size variable)
The name field of the ustar header is constructed using the pattern
"%d/GNUSparseFile.%p/%f".
The sparse map itself is stored in the file data block, preceding the actual
file data. It consists of a series of octal numbers of arbitrary length,
delimited by newlines. The map is padded with nulls to the nearest block
@@ -924,11 +928,11 @@ pax_dump_header_0 (struct tar_sparse_file *file)
char nbuf[UINTMAX_STRSIZE_BOUND];
struct sp_array *map = file->stat_info->sparse_map;
char *save_file_name = NULL;
/* Store the real file size */
xheader_store ("GNU.sparse.size", file->stat_info, NULL);
xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
if (xheader_keyword_deleted_p ("GNU.sparse.map")
|| tar_sparse_minor == 0)
{
@@ -987,11 +991,11 @@ pax_dump_header_1 (struct tar_sparse_file *file)
off_t size = 0;
struct sp_array *map = file->stat_info->sparse_map;
char *save_file_name = file->stat_info->file_name;
#define COPY_STRING(b,dst,src) do \
{ \
char *endp = b->buffer + BLOCKSIZE; \
char *srcp = src; \
char const *srcp = src; \
while (*srcp) \
{ \
if (dst == endp) \
@@ -1003,7 +1007,7 @@ pax_dump_header_1 (struct tar_sparse_file *file)
} \
*dst++ = *srcp++; \
} \
} while (0)
} while (0)
/* Compute stored file size */
p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
@@ -1018,15 +1022,18 @@ pax_dump_header_1 (struct tar_sparse_file *file)
size = (size + BLOCKSIZE - 1) / BLOCKSIZE;
file->stat_info->archive_file_size += size * BLOCKSIZE;
file->dumped_size += size * BLOCKSIZE;
/* Store sparse file identification */
xheader_store ("GNU.sparse.major", file->stat_info, NULL);
xheader_store ("GNU.sparse.minor", file->stat_info, NULL);
xheader_store ("GNU.sparse.name", file->stat_info, NULL);
xheader_store ("GNU.sparse.realsize", file->stat_info, NULL);
file->stat_info->file_name = xheader_format_name (file->stat_info,
"%d/GNUSparseFile.%p/%f", 0);
file->stat_info->file_name =
xheader_format_name (file->stat_info, "%d/GNUSparseFile.%p/%f", 0);
/* Make sure the created header name is shorter than NAME_FIELD_SIZE: */
if (strlen (file->stat_info->file_name) > NAME_FIELD_SIZE)
file->stat_info->file_name[NAME_FIELD_SIZE] = 0;
blk = start_header (file->stat_info);
/* Store the effective (shrunken) file size */
@@ -1072,12 +1079,12 @@ decode_num (uintmax_t *num, char const *arg, uintmax_t maxval)
if (!ISDIGIT (*arg))
return false;
u = strtoumax (arg, &arg_lim, 10);
if (! (u <= maxval && errno != ERANGE) || *arg_lim)
return false;
*num = u;
return true;
}
@@ -1117,7 +1124,7 @@ pax_decode_header (struct tar_sparse_file *file)
} \
while (*dst++ != '\n'); \
dst[-1] = 0; \
} while (0)
} while (0)
set_next_block_after (current_header);
file->dumped_size += BLOCKSIZE;
@@ -1126,7 +1133,7 @@ pax_decode_header (struct tar_sparse_file *file)
COPY_BUF (blk,nbuf,p);
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
{
ERROR ((0, 0, _("%s: malformed sparse archive member"),
ERROR ((0, 0, _("%s: malformed sparse archive member"),
file->stat_info->orig_file_name));
return false;
}
@@ -1137,19 +1144,19 @@ pax_decode_header (struct tar_sparse_file *file)
for (i = 0; i < file->stat_info->sparse_map_size; i++)
{
struct sp_array sp;
COPY_BUF (blk,nbuf,p);
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
{
ERROR ((0, 0, _("%s: malformed sparse archive member"),
ERROR ((0, 0, _("%s: malformed sparse archive member"),
file->stat_info->orig_file_name));
return false;
}
sp.offset = u;
COPY_BUF (blk,nbuf,p);
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
{
ERROR ((0, 0, _("%s: malformed sparse archive member"),
ERROR ((0, 0, _("%s: malformed sparse archive member"),
file->stat_info->orig_file_name));
return false;
}
@@ -1158,7 +1165,7 @@ pax_decode_header (struct tar_sparse_file *file)
}
set_next_block_after (blk);
}
return true;
}
@@ -1168,7 +1175,7 @@ static struct tar_sparse_optab const pax_optab = {
pax_sparse_member_p,
pax_dump_header,
NULL,
pax_decode_header,
pax_decode_header,
NULL, /* No scan_block function */
sparse_dump_region,
sparse_extract_region,

View File

@@ -27,7 +27,7 @@ struct compression_suffix
};
static struct compression_suffix compression_suffixes[] = {
#define __CAT2__(a,b) a ## b
#define __CAT2__(a,b) a ## b
#define S(s,p) #s, sizeof (#s) - 1, __CAT2__(p,_PROGRAM)
{ S(gz, GZIP) },
{ S(tgz, GZIP) },
@@ -54,7 +54,7 @@ static const char *
find_compression_program (const char *name, const char *defprog)
{
char *suf = strrchr (name, '.');
if (suf)
{
int i;
@@ -74,10 +74,9 @@ find_compression_program (const char *name, const char *defprog)
}
void
set_comression_program_by_suffix (const char *name, const char *defprog)
set_compression_program_by_suffix (const char *name, const char *defprog)
{
const char *program = find_compression_program (name, defprog);
if (program)
use_compress_program_option = program;
}

View File

@@ -1,7 +1,7 @@
/* System-dependent calls for tar.
Copyright (C) 2003, 2004, 2005, 2006, 2007,
2008 Free Software Foundation, Inc.
2008, 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
@@ -20,6 +20,7 @@
#include <system.h>
#include "common.h"
#include <priv-set.h>
#include <rmt.h>
#include <signal.h>
@@ -192,6 +193,7 @@ sys_spawn_shell (void)
child = xfork ();
if (child == 0)
{
priv_set_restore_linkdir ();
execlp (shell, "-sh", "-i", (char *) 0);
exec_fatal (shell);
}
@@ -283,15 +285,15 @@ xdup2 (int from, int into)
}
}
void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
static void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
/* Propagate any failure of the grandchild back to the parent. */
void
static void
wait_for_grandchild (pid_t pid)
{
int wait_status;
int exit_code = 0;
while (waitpid (pid, &wait_status, 0) == -1)
if (errno != EINTR)
{
@@ -303,7 +305,7 @@ wait_for_grandchild (pid_t pid)
raise (WTERMSIG (wait_status));
else if (WEXITSTATUS (wait_status) != 0)
exit_code = WEXITSTATUS (wait_status);
exit (exit_code);
}
@@ -332,7 +334,7 @@ sys_child_open_for_compress (void)
set_program_name (_("tar (child)"));
signal (SIGPIPE, SIG_DFL);
xdup2 (parent_pipe[PREAD], STDIN_FILENO);
xclose (parent_pipe[PWRITE]);
@@ -362,6 +364,7 @@ sys_child_open_for_compress (void)
}
xdup2 (archive, STDOUT_FILENO);
}
priv_set_restore_linkdir ();
execlp (use_compress_program_option, use_compress_program_option, NULL);
exec_fatal (use_compress_program_option);
}
@@ -379,6 +382,7 @@ sys_child_open_for_compress (void)
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
xclose (child_pipe[PREAD]);
priv_set_restore_linkdir ();
execlp (use_compress_program_option, use_compress_program_option,
(char *) 0);
exec_fatal (use_compress_program_option);
@@ -451,6 +455,29 @@ sys_child_open_for_compress (void)
wait_for_grandchild (grandchild_pid);
}
static void
run_decompress_program (void)
{
int i;
const char *p, *prog = NULL;
for (p = first_decompress_program (&i); p; p = next_decompress_program (&i))
{
if (prog)
{
WARNOPT (WARN_DECOMPRESS_PROGRAM,
(0, errno, _("cannot run %s"), prog));
WARNOPT (WARN_DECOMPRESS_PROGRAM,
(0, 0, _("trying %s"), p));
}
prog = p;
execlp (p, p, "-d", NULL);
}
if (!prog)
FATAL_ERROR ((0, 0, _("unable to run decompression program")));
exec_fatal (prog);
}
/* Set ARCHIVE for uncompressing, then reading an archive. */
pid_t
sys_child_open_for_uncompress (void)
@@ -476,7 +503,7 @@ sys_child_open_for_uncompress (void)
set_program_name (_("tar (child)"));
signal (SIGPIPE, SIG_DFL);
xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
xclose (parent_pipe[PREAD]);
@@ -496,9 +523,8 @@ sys_child_open_for_uncompress (void)
if (archive < 0)
open_fatal (archive_name_array[0]);
xdup2 (archive, STDIN_FILENO);
execlp (use_compress_program_option, use_compress_program_option,
"-d", (char *) 0);
exec_fatal (use_compress_program_option);
priv_set_restore_linkdir ();
run_decompress_program ();
}
/* We do need a grandchild tar. */
@@ -514,9 +540,8 @@ sys_child_open_for_uncompress (void)
xdup2 (child_pipe[PREAD], STDIN_FILENO);
xclose (child_pipe[PWRITE]);
execlp (use_compress_program_option, use_compress_program_option,
"-d", (char *) 0);
exec_fatal (use_compress_program_option);
priv_set_restore_linkdir ();
run_decompress_program ();
}
/* The child tar is still here! */
@@ -575,7 +600,7 @@ sys_child_open_for_uncompress (void)
static void
dec_to_env (char *envar, uintmax_t num)
dec_to_env (char const *envar, uintmax_t num)
{
char buf[UINTMAX_STRSIZE_BOUND];
char *numstr;
@@ -586,7 +611,7 @@ dec_to_env (char *envar, uintmax_t num)
}
static void
time_to_env (char *envar, struct timespec t)
time_to_env (char const *envar, struct timespec t)
{
char buf[TIMESPEC_STRSIZE_BOUND];
if (setenv (envar, code_timespec (t, buf), 1) != 0)
@@ -594,7 +619,7 @@ time_to_env (char *envar, struct timespec t)
}
static void
oct_to_env (char *envar, unsigned long num)
oct_to_env (char const *envar, unsigned long num)
{
char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
@@ -604,7 +629,7 @@ oct_to_env (char *envar, unsigned long num)
}
static void
str_to_env (char *envar, char const *str)
str_to_env (char const *envar, char const *str)
{
if (str)
{
@@ -616,7 +641,7 @@ str_to_env (char *envar, char const *str)
}
static void
chr_to_env (char *envar, char c)
chr_to_env (char const *envar, char c)
{
char buf[2];
buf[0] = c;
@@ -702,6 +727,7 @@ sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
argv[2] = to_command_option;
argv[3] = NULL;
priv_set_restore_linkdir ();
execv ("/bin/sh", argv);
exec_fatal (file_name);
@@ -750,7 +776,7 @@ sys_exec_info_script (const char **archive_name, int volume_number)
char uintbuf[UINTMAX_STRSIZE_BOUND];
int p[2];
static RETSIGTYPE (*saved_handler) (int sig);
xpipe (p);
saved_handler = signal (SIGPIPE, SIG_IGN);
@@ -783,7 +809,7 @@ sys_exec_info_script (const char **archive_name, int volume_number)
}
signal (SIGPIPE, saved_handler);
if (WIFEXITED (status))
{
if (WEXITSTATUS (status) == 0 && rc > 0)
@@ -813,9 +839,10 @@ sys_exec_info_script (const char **archive_name, int volume_number)
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = (char*) info_script_option;
argv[2] = (char *) info_script_option;
argv[3] = NULL;
priv_set_restore_linkdir ();
execv (argv[0], argv);
exec_fatal (info_script_option);
@@ -860,9 +887,10 @@ sys_exec_checkpoint_script (const char *script_name,
archive_format : current_format), 1);
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = (char*) script_name;
argv[2] = (char *) script_name;
argv[3] = NULL;
priv_set_restore_linkdir ();
execv (argv[0], argv);
exec_fatal (script_name);

435
src/tar.c

File diff suppressed because it is too large Load Diff

View File

@@ -265,7 +265,7 @@ enum archive_format
struct sp_array
{
off_t offset;
size_t numbytes;
off_t numbytes;
};
struct xheader
@@ -311,12 +311,32 @@ struct tar_stat_info
/* Extended headers */
struct xheader xhdr;
/* For dumpdirs */
bool is_dumpdir; /* Is the member a dumpdir? */
bool skipped; /* The member contents is already read
(for GNUTYPE_DUMPDIR) */
char *dumpdir; /* Contents of the dump directory */
/* Parent directory, if creating an archive. This is null if the
file is at the top level. */
struct tar_stat_info *parent;
/* Directory stream. If this is not null, it is in control of FD,
and should be closed instead of FD. */
DIR *dirstream;
/* File descriptor, if creating an archive, and if a directory or a
regular file or a contiguous file.
It is zero if no file descriptor is available, either because it
was never needed or because it was open and then closed to
conserve on file descriptors. (Standard input is never used
here, so zero cannot be a valid file descriptor.)
It is negative if it could not be reopened after it was closed.
Negate it to find out what errno was when the reopen failed. */
int fd;
};
union block

View File

@@ -1,4 +1,4 @@
/* This file is part of GNU tar.
/* This file is part of GNU tar.
Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
@@ -34,8 +34,8 @@ enum replace_segm_type
enum case_ctl_type
{
ctl_stop, /* Stop case conversion */
ctl_upcase_next,/* Turn the next character to uppercase */
ctl_stop, /* Stop case conversion */
ctl_upcase_next,/* Turn the next character to uppercase */
ctl_locase_next,/* Turn the next character to lowercase */
ctl_upcase, /* Turn the replacement to uppercase until ctl_stop */
ctl_locase /* Turn the replacement to lowercase until ctl_stop */
@@ -51,9 +51,9 @@ struct replace_segm
{
char *ptr;
size_t size;
} literal; /* type == segm_literal */
} literal; /* type == segm_literal */
size_t ref; /* type == segm_backref */
enum case_ctl_type ctl; /* type == segm_case_ctl */
enum case_ctl_type ctl; /* type == segm_case_ctl */
} v;
};
@@ -75,7 +75,7 @@ int transform_flags = XFORM_ALL;
static struct transform *transform_head, *transform_tail;
static struct transform *
new_transform ()
new_transform (void)
{
struct transform *p = xzalloc (sizeof *p);
if (transform_tail)
@@ -146,7 +146,7 @@ parse_xform_flags (int *pflags, int c)
case 'R':
*pflags &= ~XFORM_REGFILE;
break;
case 'h':
*pflags |= XFORM_LINK;
break;
@@ -154,7 +154,7 @@ parse_xform_flags (int *pflags, int c)
case 'H':
*pflags &= ~XFORM_LINK;
break;
case 's':
*pflags |= XFORM_SYMLINK;
break;
@@ -204,10 +204,10 @@ parse_transform_expr (const char *expr)
*expr));
}
return expr;
}
}
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
}
delim = expr[1];
/* Scan regular expression */
@@ -258,14 +258,14 @@ parse_transform_expr (const char *expr)
if (*p == ';')
p++;
/* Extract and compile regex */
str = xmalloc (i - 1);
memcpy (str, expr + 2, i - 2);
str[i - 2] = 0;
rc = regcomp (&tf->regex, str, cflags);
if (rc)
{
char errbuf[512];
@@ -275,7 +275,7 @@ parse_transform_expr (const char *expr)
if (str[0] == '^' || str[strlen (str) - 1] == '$')
tf->transform_type = transform_first;
free (str);
/* Extract and compile replacement expr */
@@ -289,7 +289,7 @@ parse_transform_expr (const char *expr)
if (*cur == '\\')
{
size_t n;
add_literal_segment (tf, beg, cur);
switch (*++cur)
{
@@ -310,32 +310,32 @@ parse_transform_expr (const char *expr)
add_char_segment (tf, '\a');
cur++;
break;
case 'b':
add_char_segment (tf, '\b');
cur++;
break;
case 'f':
add_char_segment (tf, '\f');
cur++;
break;
case 'n':
add_char_segment (tf, '\n');
cur++;
break;
case 'r':
add_char_segment (tf, '\r');
cur++;
break;
case 't':
add_char_segment (tf, '\t');
cur++;
break;
case 'v':
add_char_segment (tf, '\v');
cur++;
@@ -345,39 +345,39 @@ parse_transform_expr (const char *expr)
add_char_segment (tf, '&');
cur++;
break;
case 'L':
/* Turn the replacement to lowercase until a `\U' or `\E'
is found, */
add_case_ctl_segment (tf, ctl_locase);
cur++;
break;
case 'l':
/* Turn the next character to lowercase, */
add_case_ctl_segment (tf, ctl_locase_next);
cur++;
break;
case 'U':
/* Turn the replacement to uppercase until a `\L' or `\E'
is found, */
add_case_ctl_segment (tf, ctl_upcase);
cur++;
break;
case 'u':
/* Turn the next character to uppercase, */
add_case_ctl_segment (tf, ctl_upcase_next);
cur++;
break;
case 'E':
/* Stop case conversion started by `\L' or `\U'. */
add_case_ctl_segment (tf, ctl_stop);
cur++;
break;
default:
/* Try to be nice */
{
@@ -420,7 +420,7 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
static char *case_ctl_buffer;
static size_t case_ctl_bufsize;
char *p;
if (case_ctl_bufsize < size)
{
case_ctl_bufsize = size;
@@ -432,16 +432,16 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
case ctl_upcase_next:
case_ctl_buffer[0] = toupper ((unsigned char) case_ctl_buffer[0]);
break;
case ctl_locase_next:
case_ctl_buffer[0] = tolower ((unsigned char) case_ctl_buffer[0]);
break;
case ctl_upcase:
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
*p = toupper ((unsigned char) *p);
break;
case ctl_locase:
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
*p = tolower ((unsigned char) *p);
@@ -457,7 +457,7 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
static struct obstack stk;
static bool stk_init;
void
static void
_single_transform_name_to_obstack (struct transform *tf, char *input)
{
regmatch_t *rmp;
@@ -465,7 +465,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
size_t nmatches = 0;
enum case_ctl_type case_ctl = ctl_stop, /* Current case conversion op */
save_ctl = ctl_stop; /* Saved case_ctl for \u and \l */
/* Reset case conversion after a single-char operation */
#define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \
|| case_ctl == ctl_locase_next) \
@@ -473,20 +473,20 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
case_ctl = save_ctl; \
save_ctl = ctl_stop; \
}
rmp = xmalloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
while (*input)
{
size_t disp;
char *ptr;
rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0);
if (rc == 0)
{
struct replace_segm *segm;
disp = rmp[0].rm_eo;
if (rmp[0].rm_so)
@@ -516,7 +516,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
}
obstack_grow (&stk, ptr, segm->v.literal.size);
break;
case segm_backref: /* Back-reference segment */
if (rmp[segm->v.ref].rm_so != -1
&& rmp[segm->v.ref].rm_eo != -1)
@@ -529,7 +529,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
ptr = run_case_conv (case_ctl, ptr, size);
CASE_CTL_RESET();
}
obstack_grow (&stk, ptr, size);
}
break;
@@ -549,7 +549,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
break;
}
/*FALL THROUGH*/
case ctl_upcase:
case ctl_locase:
case ctl_stop:
@@ -577,18 +577,18 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
free (rmp);
}
bool
static bool
_transform_name_to_obstack (int flags, char *input, char **output)
{
struct transform *tf;
bool alloced = false;
if (!stk_init)
{
obstack_init (&stk);
stk_init = true;
}
for (tf = transform_head; tf; tf = tf->next)
{
if (tf->flags & flags)
@@ -601,7 +601,7 @@ _transform_name_to_obstack (int flags, char *input, char **output)
*output = input;
return alloced;
}
bool
transform_name_fp (char **pinput, int flags,
char *(*fun)(char *, void *), void *dat)
@@ -628,3 +628,9 @@ transform_name (char **pinput, int type)
{
return transform_name_fp (pinput, type, NULL, NULL);
}
bool
transform_program_p (void)
{
return transform_head != NULL;
}

View File

@@ -1,4 +1,4 @@
/* This file is part of GNU tar.
/* This file is part of GNU tar.
Copyright (C) 2009 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@ static struct deferred_unlink *dunlink_avail;
size_t deferred_unlink_delay = 0;
static struct deferred_unlink *
dunlink_alloc ()
dunlink_alloc (void)
{
struct deferred_unlink *p;
if (dunlink_avail)
@@ -77,7 +77,7 @@ flush_deferred_unlinks (bool force)
{
if (p->is_dir)
{
if (rmdir (p->file_name) != 0)
if (unlinkat (chdir_fd, p->file_name, AT_REMOVEDIR) != 0)
{
switch (errno)
{
@@ -101,7 +101,7 @@ flush_deferred_unlinks (bool force)
}
else
{
if (unlink (p->file_name) != 0 && errno != ENOENT)
if (unlinkat (chdir_fd, p->file_name, 0) != 0 && errno != ENOENT)
unlink_error (p->file_name);
}
dunlink_reclaim (p);
@@ -116,7 +116,7 @@ flush_deferred_unlinks (bool force)
{
prev = p;
p = next;
}
}
}
if (!dunlink_head)
dunlink_tail = NULL;
@@ -142,13 +142,13 @@ queue_deferred_unlink (const char *name, bool is_dir)
if (dunlink_head
&& records_written > dunlink_head->records_written + deferred_unlink_delay)
flush_deferred_unlinks (false);
p = dunlink_alloc ();
p->next = NULL;
p->file_name = normalize_filename (name);
p->is_dir = is_dir;
p->records_written = records_written;
if (dunlink_tail)
dunlink_tail->next = p;
else

View File

@@ -47,7 +47,7 @@ char *output_start;
static void
append_file (char *file_name)
{
int handle = open (file_name, O_RDONLY | O_BINARY);
int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY);
struct stat stat_data;
if (handle < 0)
@@ -114,8 +114,8 @@ update_archive (void)
while (!found_end)
{
enum read_header status = read_header (&current_header,
&current_stat_info,
enum read_header status = read_header (&current_header,
&current_stat_info,
read_header_auto);
switch (status)
@@ -130,6 +130,8 @@ update_archive (void)
decode_header (current_header, &current_stat_info,
&current_format, 0);
transform_stat_info (current_header->header.typeflag,
&current_stat_info);
archive_format = current_format;
if (subcommand_option == UPDATE_SUBCOMMAND
@@ -138,28 +140,37 @@ update_archive (void)
struct stat s;
chdir_do (name->change_dir);
if (deref_stat (dereference_option,
current_stat_info.file_name, &s) == 0)
if (deref_stat (current_stat_info.file_name, &s) == 0)
{
if (S_ISDIR (s.st_mode))
{
char *p, *dirp;
dirp = savedir (name->name);
if (!dirp)
DIR *stream;
int fd = openat (chdir_fd, name->name,
open_read_flags | O_DIRECTORY);
if (fd < 0)
open_error (name->name);
else if (! ((stream = fdopendir (fd))
&& (dirp = streamsavedir (stream))))
savedir_error (name->name);
else
{
namebuf_t nbuf = namebuf_create (name->name);
for (p = dirp; *p; p += strlen (p) + 1)
addname (namebuf_name (nbuf, p),
0, false, NULL);
namebuf_free (nbuf);
free (dirp);
remname (name);
}
if (stream
? closedir (stream) != 0
: 0 <= fd && close (fd) != 0)
savedir_error (name->name);
}
else if (tar_timespec_cmp (get_stat_mtime (&s),
current_stat_info.mtime)
@@ -167,7 +178,7 @@ update_archive (void)
remname (name);
}
}
skip_member ();
break;
}
@@ -224,11 +235,12 @@ update_archive (void)
if (subcommand_option == CAT_SUBCOMMAND)
append_file (file_name);
else
dump_file (file_name, 1, (dev_t) 0);
dump_file (0, file_name, file_name);
}
}
write_eot ();
close_archive ();
finish_deferred_unlinks ();
names_notfound ();
}

View File

@@ -41,6 +41,7 @@ static char const *const warning_args[] = {
"unknown-cast",
"unknown-keyword",
"xdev",
"decompress-program",
NULL
};
@@ -64,7 +65,8 @@ static int warning_types[] = {
WARN_TIMESTAMP,
WARN_UNKNOWN_CAST,
WARN_UNKNOWN_KEYWORD,
WARN_XDEV
WARN_XDEV,
WARN_DECOMPRESS_PROGRAM
};
ARGMATCH_VERIFY (warning_args, warning_types);
@@ -76,7 +78,7 @@ set_warning_option (const char *arg)
{
int negate = 0;
int option;
if (strcmp (arg, "none") == 0)
{
warning_option = 0;
@@ -88,11 +90,10 @@ set_warning_option (const char *arg)
arg += 3;
}
option = XARGMATCH ("--warning", arg,
option = XARGMATCH ("--warning", arg,
warning_args, warning_types);
if (negate)
warning_option &= ~option;
else
warning_option |= option;
}

View File

@@ -26,6 +26,7 @@
#include "common.h"
static void xheader_init (struct xheader *xhdr);
static bool xheader_protected_pattern_p (char const *pattern);
static bool xheader_protected_keyword_p (char const *keyword);
static void xheader_set_single_keyword (char *) __attribute__ ((noreturn));
@@ -452,7 +453,7 @@ xheader_write_global (struct xheader *xhdr)
if (xhdr->stk)
{
char *name;
xheader_finish (xhdr);
xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
free (name);
@@ -661,7 +662,7 @@ xheader_decode_global (struct xheader *xhdr)
}
}
void
static void
xheader_init (struct xheader *xhdr)
{
if (!xhdr->stk)
@@ -708,7 +709,7 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size)
if (!p)
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
memcpy (&xhdr->buffer[j], p->buffer, len);
set_next_block_after (p);
@@ -1307,7 +1308,7 @@ sparse_numbytes_decoder (struct tar_stat_info *st,
size_t size __attribute__((unused)))
{
uintmax_t u;
if (decode_num (&u, arg, SIZE_MAX, keyword))
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
{
if (st->sparse_map_avail < st->sparse_map_size)
st->sparse_map[st->sparse_map_avail++].numbytes = u;
@@ -1355,7 +1356,7 @@ sparse_map_decoder (struct tar_stat_info *st,
e.numbytes = u;
if (!(u == e.numbytes && errno != ERANGE))
{
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (size_t));
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
return;
}
if (st->sparse_map_avail < st->sparse_map_size)

View File

@@ -1,6 +1,6 @@
# Makefile for GNU tar regression tests.
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
# 2006, 2007, 2009 Free Software Foundation, Inc.
# François Pinard <pinard@iro.umontreal.ca>, 1988.
@@ -52,6 +52,7 @@ TESTSUITE_AT = \
append.at\
append01.at\
append02.at\
append03.at\
backup01.at\
chtype.at\
comprec.at\
@@ -66,6 +67,7 @@ TESTSUITE_AT = \
exclude03.at\
exclude04.at\
exclude05.at\
exclude06.at\
extrac01.at\
extrac02.at\
extrac03.at\
@@ -74,6 +76,15 @@ TESTSUITE_AT = \
extrac06.at\
extrac07.at\
extrac08.at\
extrac09.at\
extrac10.at\
extrac11.at\
extrac12.at\
extrac13.at\
extrac14.at\
extrac15.at\
extrac16.at\
extrac17.at\
filerem01.at\
filerem02.at\
gzip.at\
@@ -89,11 +100,17 @@ TESTSUITE_AT = \
ignfail.at\
label01.at\
label02.at\
label03.at\
label04.at\
label05.at\
link01.at\
link02.at\
link03.at\
link04.at\
listed01.at\
listed02.at\
listed03.at\
listed04.at\
long01.at\
longv7.at\
lustar01.at\
@@ -106,6 +123,7 @@ TESTSUITE_AT = \
multiv05.at\
multiv06.at\
multiv07.at\
multiv08.at\
old.at\
options.at\
options02.at\
@@ -118,14 +136,17 @@ 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\
sparse04.at\
sparsemv.at\
sparsemvp.at\
spmvp00.at\
@@ -138,8 +159,10 @@ TESTSUITE_AT = \
volsize.at\
volume.at\
verbose.at\
verify.at\
version.at\
xform-h.at\
xform01.at\
star/gtarfail.at\
star/gtarfail2.at\
star/multi-fail.at\
@@ -184,4 +207,4 @@ genfile_SOURCES = genfile.c argcv.c argcv.h
localedir = $(datadir)/locale
INCLUDES = -I$(top_srcdir)/gnu -I../gnu -I$(top_srcdir)/gnu -I$(top_srcdir)/lib
AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\"
LDADD = ../gnu/libgnu.a $(LIBINTL) $(LIB_CLOCK_GETTIME)
LDADD = ../gnu/libgnu.a $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)

View File

@@ -21,11 +21,11 @@
# When decoding a header tar was assigning 0 to oldgnu_header.isextended,
# which destroyed name prefix. When updating archive, modified prefix
# could have been written to disk thus producing invalid archive member.
# Reported by Adye, TJ (Tim), <T.J.Adye@rl.ac.uk>
# Reported by Adye, TJ (Tim), <T.J.Adye@rl.ac.uk>
# References:
# <7231C15EAC2F164CA6DC326D97493C8B36C25D@exchange35.fed.cclrc.ac.uk>
# http://lists.gnu.org/archive/html/bug-tar/2005-02/msg00032.html
AT_SETUP([appending files with long names])
AT_KEYWORDS([append append01])
@@ -45,4 +45,3 @@ PREFIX/file2
[],[],[],[oldgnu, ustar, posix, gnu])
AT_CLEANUP

View File

@@ -20,7 +20,7 @@
# Using tar 1.15.x the following equivalent command sets:
#
# 1. tar cf archive file1 file2
# 1. tar cf archive file1 file2
# and
# 2. tar cfT archive /dev/null
# tar rf archive file1
@@ -62,7 +62,7 @@ genfile --file file2
MTIME="--mtime=@0"
# For PAX archives, we need to make sure extended header names are
# reproducible and that their contents won't change with time
# reproducible and that their contents won't change with time
if test $[]TEST_TAR_FORMAT = posix; then
TAR_OPTIONS="$TAR_OPTIONS --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=mtime,delete=atime,delete=ctime"
fi

43
tests/append03.at Normal file
View File

@@ -0,0 +1,43 @@
# 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 <http://www.gnu.org/licenses/>.
AT_SETUP([append with name transformation])
AT_KEYWORDS([append append03])
# Description: Make sure filenames are transformed during append.
AT_TAR_CHECK([
genfile --file file.1
genfile --file file.2
tar -c -f archive --transform 's/file/plik/' file.*
echo Appending
tar -r -f archive --transform 's/file/plik/' -v --show-transformed-names file.1
echo Testing
tar tf archive
],
[0],
[Appending
plik.1
Testing
plik.1
plik.2
plik.1
])
AT_CLEANUP

View File

@@ -16,17 +16,17 @@ fi
STAR_DATA_URL=ftp://ftp.berlios.de/pub/star/testscripts
if test -z "$STAR_TESTSCRIPTS"; then
STAR_TESTSCRIPTS=$TEST_DATA_DIR
fi
fi
# tarball_prereq file sum dir url
tarball_prereq() {
if test -d "$3"; then
if test -d "$3"; then
if test -r $3/$1; then
:
elif test -n "$FULL_TEST"; then
wget -q --directory-prefix=$3 $4/$1
fi
fi
fi
echo "$2 $3/$1" | md5sum --status --check - >/dev/null 2>&1
}
@@ -34,4 +34,3 @@ decho() {
echo $*
echo >&2 $*
}

View File

@@ -1,7 +1,7 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
# Test suite for GNU tar.
# Copyright (C) 2009 Free Software Foundation, Inc.
# Copyright (C) 2009-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
@@ -34,10 +34,11 @@ AT_SETUP([extracting existing dir with --backup])
AT_KEYWORDS([extract backup backup01])
AT_TAR_CHECK([
unset VERSION_CONTROL
mkdir dir1 dir2
echo bla > dir1/file1
tar cf test.tar dir1 dir2
tar xfv test.tar --backup
tar xfv test.tar --backup --warning=no-timestamp
],
[0],
[dir1/
@@ -46,4 +47,4 @@ Renaming `dir1/file1' to `dir1/file1~'
dir2/
])
AT_CLEANUP
AT_CLEANUP

View File

@@ -51,9 +51,9 @@ tar --create --file=archive.2 --listed-incremental=db.2 directory
rm -r directory
echo Restore archive.1
tar -xf archive.1 --listed-incremental=/dev/null
tar -xf archive.1 --listed-incremental=/dev/null --warning=no-timestamp
echo Restore archive.2
tar -xf archive.2 --listed-incremental=/dev/null
tar -xf archive.2 --listed-incremental=/dev/null --warning=no-timestamp
find directory | sort
],
[0],

View File

@@ -29,7 +29,7 @@ echo "separator"
tar cfz archive file1
echo "separator"
mv file1 orig
tar xfv archive
tar xfv archive --warning=no-timestamp
cmp orig file1
],
[0],

View File

@@ -31,8 +31,8 @@ for i in 1 2 3 4 5 6 7 8 9
do touch $prefix$i
done
tar -cf archive ./$prefix* &&
tar --delete -f archive ./${prefix}5 &&
tar -tf archive
tar --delete -f archive ./${prefix}5 &&
tar -tf archive
],
[0],
[./PREFIX[]1

View File

@@ -36,7 +36,7 @@ mkdir dir/rock
echo "Signature: 8a477f597d28d172789f06886806bc55" > dir/rock/CACHEDIR.TAG
echo "test" > dir/rock/file
for option in exclude-caches exclude-caches-under exclude-caches-all
for option in exclude-caches exclude-caches-under exclude-caches-all
do
echo OPTION $option
tar -cf archive.tar --$option -v dir 2>err | sort
@@ -45,7 +45,7 @@ do
tar tf archive.tar | sort
done
for option in exclude-tag exclude-tag-under exclude-tag-all
for option in exclude-tag exclude-tag-under exclude-tag-all
do
echo OPTION $option
tar -cf archive.tar --${option}=tagfile -v dir 2>err | sort

47
tests/exclude06.at Normal file
View File

@@ -0,0 +1,47 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
# 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 <http://www.gnu.org/licenses/>.
# Tar 1.23 would fail to exclude names longer that 100 characters from
# pax format archives.
#
# Reported-by: Matthew Peterson <mrpeterson2@gmail.com>
# References: <AANLkTin0teb1dcl0HCNquHxvN4HQnJmP6aK7CJCqy0sd@mail.gmail.com>
# http://lists.gnu.org/archive/html/help-tar/2010-06/msg00000.html
AT_SETUP([exclude: long files in pax archives])
AT_KEYWORDS([exclude exclude06])
m4_define([test_base_dir],[one/two/three/four/five/six/seven/eight/nine/ten/eleven/twelve/thirteen/fourteen/fifteen/sixteen/seventeen])
AT_TAR_CHECK([
AT_TAR_MKHIER(test_base_dir)
genfile --length 20 -f test_base_dir[/1.txt]
genfile --length 20 -f test_base_dir[/1.c]
tar cf archive.tar test_base_dir
mkdir out
tar -C out -xf archive.tar --exclude='*.txt' --warning=no-timestamp
find out -type f
],
[0],
[[out/]test_base_dir[/1.c]
],
[],
[],
[],
[pax])
AT_CLEANUP

View File

@@ -27,7 +27,7 @@ AT_TAR_CHECK([
mkdir directory
touch directory/file
tar cf archive directory || exit 1
tar xf archive || exit 1
tar xf archive --warning=no-timestamp || exit 1
])
AT_CLEANUP

View File

@@ -27,7 +27,7 @@ AT_TAR_CHECK([
mkdir directory
tar -cPvf archive directory/../directory
echo separator
tar -xPvf archive],
tar -xPvf archive --warning=no-timestamp],
[0],
[directory/../directory/
separator

View File

@@ -36,7 +36,7 @@ tar -cf archive ./file1 directory
tar -tf archive \
--exclude='./*1' \
--exclude='d*/*1' \
--exclude='d*/s*/*2' | sort
--exclude='d*/s*/*2' | sort
],
[0],
[directory/

View File

@@ -30,13 +30,13 @@
AT_SETUP([extracting selected members from pax])
AT_KEYWORDS([extract extract05])
AT_DATA([list],
AT_DATA([list],
[jeden
cztery
])
AT_TAR_CHECK([
genfile --sparse --file sparsefile 0 ABCD 1M EFGH 2000K IJKL || AT_SKIP_TEST
genfile --sparse --file sparsefile 0 ABCD 1M EFGH 2000K IJKL || AT_SKIP_TEST
genfile --length 118 --file jeden
genfile --length 223 --file dwa
genfile --length 517 --file trzy
@@ -47,7 +47,7 @@ tar cf archive jeden dwa trzy cztery || exit 1
mkdir dir
cd dir
tar xvfT ../archive ../../list || exit 1
tar xvfT ../archive ../../list --warning=no-timestamp || exit 1
cd ..
],

View File

@@ -23,7 +23,7 @@
# permissions than your umask. In this case, the permissions of the
# existing directory will toggle between the version which complies with
# your umask (which would be correct, without -p) and the version from the
# tarfile.
# tarfile.
#
# Reported by: Ian Jackson <iwj@ubuntu.com>
#
@@ -41,7 +41,7 @@ umask 022
# Make sure user's umask is honored, even if we are superuser
TAR_OPTIONS="$TAR_OPTIONS --no-same-permissions"
# Create a directory
# Create a directory
mkdir directory
chmod 777 directory
genfile --stat=mode:777 directory
@@ -54,10 +54,10 @@ chmod 755 directory
genfile --stat=mode:777 directory
# ... and attempt to restore it twice
tar xf arc directory
tar xf arc directory --warning=no-timestamp
genfile --stat=mode:777 directory
tar xf arc directory
tar xf arc directory --warning=no-timestamp
genfile --stat=mode:777 directory
# After both restores, the directory mode should be 755

View File

@@ -28,13 +28,15 @@ AT_SETUP([extracting symlinks to a read-only dir])
AT_KEYWORDS([extract extract07 read-only symlink])
AT_TAR_CHECK([
AT_UNPRIVILEGED_PREREQ
echo Prepare the directory
mkdir dir
genfile -f foo
cd dir
ln -s ../foo .
cd ..
chmod -w dir
chmod a-w dir
echo Create the archive
tar cf archive dir || exit 1
@@ -52,8 +54,6 @@ Extract
dir/
dir/foo
],
[],[],[ustar]) # Testing one format is enough
[],[],[],[ustar]) # Testing one format is enough
AT_CLEANUP

View File

@@ -40,7 +40,7 @@ chmod 755 dir
echo bla > dir/file
tar cf test.tar dir
chmod 700 dir
tar xfv test.tar
tar xfv test.tar --warning=no-timestamp
genfile --stat=mode.777 dir
],
[0],
@@ -49,4 +49,4 @@ dir/file
755
])
AT_CLEANUP
AT_CLEANUP

48
tests/extrac09.at Normal file
View File

@@ -0,0 +1,48 @@
# 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 <http://www.gnu.org/licenses/>.
# This checks for the --listed-incremental bug reported by J Chapman Flack at
# http://lists.gnu.org/archive/html/bug-tar/2010-06/msg00000.html
AT_SETUP([no need to save dir with unreadable . and ..])
AT_KEYWORDS([extract extrac09])
AT_TAR_CHECK([
AT_UNPRIVILEGED_PREREQ
mkdir dir
mkdir dir/sub
mkdir dir/sub/extract
genfile --file dir/sub/f
cd dir/sub
tar -cf archive.tar f
chmod a-r . ..
tar -xvf archive.tar -C extract f
status=$?
chmod a+r . ..
cmp f extract/f || status=$?
exit $status
],
[0],
[f
],
[],[],[],[gnu])
AT_CLEANUP

44
tests/extrac10.at Normal file
View File

@@ -0,0 +1,44 @@
# 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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert
# Check that delayed setting of directory metadata does not collide
# with the -C option. When setting a directory's permissions, time
# stamps, etc., tar should apply the -C option that was in effect when
# the directory was extracted, not the -C option that happens to be in
# effect when the metadata are later set.
AT_SETUP([-C and delayed setting of metadata])
AT_KEYWORDS([extract extrac10])
AT_TAR_CHECK([
mkdir d x x/y
echo foo >d/d1
echo bar >e
tar -cf archive.tar d e &&
tar -xf archive.tar -C x d -C y e &&
diff -r d x/d &&
diff e x/y/e
],
[0],
[],
[],[],[],[gnu])
AT_CLEANUP

84
tests/extrac11.at Normal file
View File

@@ -0,0 +1,84 @@
# 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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert
# Check that 'tar' works even in a file-descriptor-limited environment.
AT_SETUP([scarce file descriptors])
AT_KEYWORDS([extract extrac11])
AT_TAR_CHECK([
exec </dev/null
dirs='a
a/b
a/b/c
a/b/c/d
a/b/c/d/e
a/b/c/d/e/f
a/b/c/d/e/f/g
a/b/c/d/e/f/g/h
a/b/c/d/e/f/g/h/i
a/b/c/d/e/f/g/h/i/j
a/b/c/d/e/f/g/h/i/j/k
'
files=
mkdir $dirs dest1 dest2 dest3 || exit
for dir in $dirs; do
for file in X Y Z; do
echo $file >$dir/$file || exit
files="$files $file"
done
done
# Check that "ulimit" itself works. Close file descriptors before
# invoking ulimit, to work around a bug (or a "feature") in some shells,
# where they squirrel away dups of file descriptors into FD 10 and up
# before closing the originals.
( (exec 3<&- 4<&- 5<&- 6<&- 7<&- 8<&- 9<&- &&
ulimit -n 100 &&
tar -cf archive1.tar a &&
tar -xf archive1.tar -C dest1 a
) &&
diff -r a dest1/a
) >/dev/null 2>&1 ||
AT_SKIP_TEST
# Another test that "ulimit" itself works:
# tar should fail when completely starved of file descriptors.
( (exec 3<&- 4<&- 5<&- 6<&- 7<&- 8<&- 9<&- &&
ulimit -n 4 &&
tar -cf archive2.tar a &&
tar -xf archive2.tar -C dest2 a
) &&
diff -r a dest2/a
) >/dev/null 2>&1 &&
AT_SKIP_TEST
# Tar should work when there are few, but enough, file descriptors.
( (exec 3<&- 4<&- 5<&- 6<&- 7<&- 8<&- 9<&- &&
ulimit -n 10 &&
tar -cf archive3.tar a &&
tar -xf archive3.tar -C dest3 a
) &&
diff -r a dest3/a >/dev/null 2>&1
) || { diff -r a dest3/a; exit 1; }
],
[0],[],[],[],[],[gnu])
AT_CLEANUP

39
tests/extrac12.at Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert
# Check that 'tar' extracts permissions on the working directory last.
AT_SETUP([extract dot permissions])
AT_KEYWORDS([extract extrac12])
AT_TAR_CHECK([
mkdir src dst
echo file1 >src/file1
echo file2 >src/file2
chmod a-w src
tar --no-recursion -cf archive.tar -C src . ./file1 file2 &&
tar -xf archive.tar -C dst &&
cmp src/file1 dst/file1 &&
cmp src/file2 dst/file2
],
[0],[],[],[],[],[gnu])
AT_CLEANUP

53
tests/extrac13.at Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert
# Check that 'tar' normally does follow symbolic links when extracting,
# unless --dereference is specified.
AT_SETUP([extract over symlinks])
AT_KEYWORDS([extract extrac13])
AT_TAR_CHECK([
mkdir src dst1 dst2 dst3
echo file1 >src/file1
ln -s target1 dst1/file1
echo target1 >dst1/target1
echo target1 >target1
tar -cf archive.tar -C src . &&
tar -xf archive.tar -C dst1 --warning=no-timestamp &&
diff src/file1 dst1/file1 &&
diff target1 dst1/target1
ln -s target1 dst2/file1
echo target1 >dst2/target1
tar --overwrite -xf archive.tar -C dst2 --warning=no-timestamp &&
diff src/file1 dst2/file1 &&
diff target1 dst2/target1
ln -s target1 dst3/file1
echo target1 >dst3/target1
tar --overwrite -xhf archive.tar -C dst3 --warning=no-timestamp &&
diff src/file1 dst3/file1 &&
diff src/file1 dst3/target1
],
[0],[],[],[],[],[gnu])
AT_CLEANUP

36
tests/extrac14.at Normal file
View File

@@ -0,0 +1,36 @@
# 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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert
# Check that 'tar -x -C FOO' follows FOO if FOO is a symbolic link.
AT_SETUP([extract -C symlink])
AT_KEYWORDS([extract extrac14])
AT_TAR_CHECK([
mkdir dest
ln -s dest symlink
echo foo >foo
tar -cf archive.tar foo &&
tar -xf archive.tar -C symlink --warning=no-timestamp &&
cmp foo dest/foo
],
[0],[],[],[],[],[gnu])
AT_CLEANUP

44
tests/extrac15.at Normal file
View File

@@ -0,0 +1,44 @@
# 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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert
# Check diagnostic of 'tar -x a/b/c' when b cannot be created.
AT_SETUP([extract parent mkdir failure])
AT_KEYWORDS([extract extrac15])
AT_TAR_CHECK([
AT_UNPRIVILEGED_PREREQ
mkdir src src/a src/a/b dest dest/a
touch src/a/b/c
chmod a-w dest/a
tar -cf archive.tar -C src a/b/c &&
if tar -xf archive.tar -C dest a/b/c
then (exit 1)
else (exit 0)
fi
],
[0],[],[tar: a/b: Cannot mkdir: Permission denied
tar: a/b/c: Cannot open: No such file or directory
tar: Exiting with failure status due to previous errors
],[],[],[gnu])
AT_CLEANUP

36
tests/extrac16.at Normal file
View File

@@ -0,0 +1,36 @@
# 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 <http://www.gnu.org/licenses/>.
# written by Paul Eggert from a bug report by Denis Excoffier
# <http://lists.gnu.org/archive/html/bug-tar/2010-10/msg00034.html>
# Check extraction of empty directory with -C.
AT_SETUP([extract empty directory with -C])
AT_KEYWORDS([extract extrac16])
AT_TAR_CHECK([
mkdir src src/a src/a/b dest
touch src/a/c
tar -cf archive.tar -C src a &&
tar -xf archive.tar -C dest
],
[0],[],[],[],[],[gnu])
AT_CLEANUP

46
tests/extrac17.at Normal file
View File

@@ -0,0 +1,46 @@
# 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 <http://www.gnu.org/licenses/>.
AT_SETUP([name matching/transformation ordering])
AT_KEYWORDS([extract extrac17])
# Description: Tar 1.24 changed the ordering of name matching and
# name transformation so that the former saw already transformed
# file names (see commit 9c194c99 and exclude06.at). This reverted
# ordering made it impossible to match file names in certain cases.
# In particular, the testcase below would not extract anything.
#
# Reported-by: "Gabor Z. Papp" <gzp@papp.hu>
# References: <x6r5fd9jye@gzp>, <20101026175126.29028@Pirx.gnu.org.ua>
# http://lists.gnu.org/archive/html/bug-tar/2010-10/msg00047.html
AT_TAR_CHECK([
mkdir dir dir/subdir1 dir/subdir2 out
genfile --file dir/subdir1/file1
genfile --file dir/subdir2/file2
tar cf dir.tar dir
tar -x -v -f dir.tar -C out --strip-components=2 --warning=no-timestamp \
dir/subdir1/
],
[0],
[dir/subdir1/file1
])
AT_CLEANUP

View File

@@ -26,7 +26,7 @@
# instead.
#
# Reported by: Solar Designer <solar@openwall.com>
#
#
# References: <20090228235820.GA13362@openwall.com>
# http://lists.gnu.org/archive/html/bug-tar/2009-03/msg00000.html
#
@@ -98,4 +98,3 @@ tar: dir/file1: File removed before we read it
AT_CLEANUP

View File

@@ -39,12 +39,11 @@ genfile --run --checkpoint=3 --exec 'rm -rf dir2' -- \
],
[2],
[ignore],
[tar: dir2: Cannot stat: No such file or directory
tar: dir2/file1: File removed before we read it
tar: Exiting with failure status due to previous errors
],[],[],[gnu, posix])
[ignore],[],[],[gnu, posix])
# Ignore stdout and stderr because their contents depend on
# the file system implementation.
# Timing information: see filerem01.at
AT_CLEANUP

View File

@@ -1,7 +1,7 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
# Test suite for GNU tar.
# Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.
# Copyright (C) 2004, 2007, 2009, 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
@@ -27,13 +27,14 @@ unset TAR_OPTIONS
AT_CHECK([
AT_GZIP_PREREQ
tar xfvz /dev/null
tar xfvz /dev/null 2>err
RC=$?
sed -n '/^tar:/p' err >&2
exit $RC
],
[2],
[],
[
gzip: stdin: unexpected end of file
tar: Child returned status 1
[tar: Child returned status 1
tar: Error is not recoverable: exiting now
],
[],[])

View File

@@ -37,9 +37,9 @@ tar -cf archive.1 -g db directory
mv directory orig
tar xvfg archive.0 /dev/null
tar xvfg archive.0 /dev/null --warning=no-timestamp
echo separator
tar xvfg archive.1 /dev/null
tar xvfg archive.1 /dev/null --warning=no-timestamp
],
[0],
[directory/
@@ -51,5 +51,3 @@ tar: Deleting `directory/bar'
[],[],[],[gnu, oldgnu, posix])
AT_CLEANUP

View File

@@ -23,9 +23,9 @@
# if the archive has normal member ordering, i.e. each directory
# member is immediately followed by members located under that directory.
# This is not true for incremental archives, where directory members
# precede the non-directory ones. Due to this, GNU tar up to version 1.15.2
# precede the non-directory ones. Due to this, GNU tar up to version 1.15.2
# failed to correctly restore directory timestamps from an incremental
# archive if this directory contained some files in it.
# archive if this directory contained some files in it.
#
# References: <200511291228.47081.karaman@dssgmbh.de>

View File

@@ -45,17 +45,17 @@ tar -cf archive.2 -g db directory
mv directory orig
echo Listing of archive.1
tar -tf archive.1 | sort
tar -tf archive.1 | sort
echo Listing of archive.2
tar -tf archive.2 | sort
tar -tf archive.2 | sort
echo Directory after first restore
tar -xf archive.1 -g db
tar -xf archive.1 -g db --warning=no-timestamp
find directory | sort
echo Directory after second restore
tar -xf archive.2 -g db
find directory | sort
tar -xf archive.2 -g db --warning=no-timestamp
find directory | sort
],
[0],
[Listing of archive.1
@@ -78,4 +78,3 @@ directory/z
AT_CLEANUP
# End of incr03.at

View File

@@ -75,5 +75,3 @@ sub/b/file4
],[],[],[],[gnu, oldgnu, posix])
AT_CLEANUP

View File

@@ -25,7 +25,7 @@ genfile --length 0 --file foo
genfile --length 12288 --file bar
genfile --length 12288 --file baz
tar --label=Test -cM -L10 -f 1.tar -f 2.tar -f 3.tar -f 4.tar foo bar baz
tar -Mt -f 1.tar -f 2.tar -f 3.tar -f 4.tar
tar -Mt -f 1.tar -f 2.tar -f 3.tar -f 4.tar
],
[0],
[Test Volume 1

87
tests/label03.at Normal file
View File

@@ -0,0 +1,87 @@
# 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 <http://www.gnu.org/licenses/>.
# 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

51
tests/label04.at Normal file
View File

@@ -0,0 +1,51 @@
# 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 <http://www.gnu.org/licenses/>.
# 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

48
tests/label05.at Normal file
View File

@@ -0,0 +1,48 @@
# 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 <http://www.gnu.org/licenses/>.
# 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

View File

@@ -44,7 +44,7 @@ ln directory/test1/test.txt directory/test2/test.txt || AT_SKIP_TEST
tar cf archive directory/test1/test.txt directory/test1/test.txt
rm -r directory
tar xf archive
tar xf archive --warning=no-timestamp
ls directory/test1
],

View File

@@ -34,9 +34,9 @@ AT_KEYWORDS([hardlinks link02])
AT_TAR_CHECK([
genfile -l 64 -f file1
link file1 file2
link file2 file3
link file3 file4
ln file1 file2
ln file2 file3
ln file3 file4
tar -c -f archive --remove-files file1 file2 file3 file4
tar tfv archive | sed -n 's/.*file[[2-4]] link to //p'
],
@@ -49,4 +49,3 @@ file1
AT_CLEANUP
# End of link02.at

View File

@@ -26,9 +26,9 @@ AT_KEYWORDS([hardlinks link03])
m4_define([create_files],[
genfile -l 64 -f file1
link file1 file2
link file2 file3
link file3 file4
ln file1 file2
ln file2 file3
ln file3 file4
])
AT_TAR_CHECK([
@@ -52,5 +52,3 @@ file1
])
AT_CLEANUP

64
tests/link04.at Normal file
View File

@@ -0,0 +1,64 @@
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# written by Paul Eggert
# Make sure that tar -c correctly handles the case where a file is
# encountered multiple times, even though it has a link count of 1.
# This can occur when "tar -c FOO FOO" is used; it can also occur when
# "tar -ch FOO" is used, if FOO contains symbolic links that point to
# the same file.
AT_SETUP([link count is 1 but multiple occurrences])
AT_KEYWORDS([hardlinks link04])
AT_TAR_CHECK([
mkdir dir
echo TEST > dir/file
ln -s file dir/symlink || AT_SKIP_TEST
tar cf archive dir dir
tar tvf archive | sed '
s,.*[[0-9]] dir/,dir/,
' | sort
echo ==
tar chf archive dir
tar tvf archive | sed '
s,.*[[0-9]] dir/,dir/,
s,file,FOO,g
s,symlink,FOO,g
' | sort
],
[0],
[dir/
dir/
dir/file
dir/file link to dir/file
dir/symlink -> file
dir/symlink link to dir/symlink
==
dir/
dir/FOO
dir/FOO link to dir/FOO
])
AT_CLEANUP

View File

@@ -60,4 +60,3 @@ directory/file2
[],[],[],[gnu, oldgnu])
AT_CLEANUP

Some files were not shown because too many files have changed in this diff Show More