Compare commits
136 Commits
release_1_
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf28f95b3a | ||
|
|
beeb19f927 | ||
|
|
553210d5ad | ||
|
|
ee2ec5ff19 | ||
|
|
d9d4435692 | ||
|
|
2251317e3f | ||
|
|
972bebf07e | ||
|
|
8e2898ab11 | ||
|
|
0b43ea2906 | ||
|
|
e4d1edadef | ||
|
|
0836a51147 | ||
|
|
afa743ac23 | ||
|
|
01dd89c121 | ||
|
|
1263f9bc1d | ||
|
|
1ff0b63f48 | ||
|
|
34d15af170 | ||
|
|
63712973c7 | ||
|
|
d9ec6f04e2 | ||
|
|
b5418cd393 | ||
|
|
615732a804 | ||
|
|
dd1a6bd37a | ||
|
|
41654f91f0 | ||
|
|
8d90723d30 | ||
|
|
14d8fc718f | ||
|
|
883cc555df | ||
|
|
e1005b385d | ||
|
|
14f00a2c7a | ||
|
|
f122fc94a7 | ||
|
|
b31afe7cf0 | ||
|
|
ea6f84dd40 | ||
|
|
2d3396c3ea | ||
|
|
d70b8b3b39 | ||
|
|
c445d99d4f | ||
|
|
2c9730357f | ||
|
|
ef0f882382 | ||
|
|
66162927eb | ||
|
|
44cfdfb8b6 | ||
|
|
97d8951536 | ||
|
|
bf5d66109c | ||
|
|
bd1b0fc97c | ||
|
|
a7289daf5c | ||
|
|
72506bddee | ||
|
|
a311b908c0 | ||
|
|
cb07844454 | ||
|
|
2f5a57be4b | ||
|
|
3da8c2850d | ||
|
|
c697d62598 | ||
|
|
b0930da045 | ||
|
|
f86722c34c | ||
|
|
aa0684ce90 | ||
|
|
85c005ee13 | ||
|
|
2684c88a49 | ||
|
|
1ed62596cf | ||
|
|
9d1993f651 | ||
|
|
e7cd377f78 | ||
|
|
c15c42ccd1 | ||
|
|
3c2a2cd94d | ||
|
|
ea3aea06f1 | ||
|
|
983a82a376 | ||
|
|
916fe62ae9 | ||
|
|
99d415e190 | ||
|
|
c7c59b57fa | ||
|
|
eae48289c0 | ||
|
|
62c0c3a780 | ||
|
|
ba472050da | ||
|
|
f6e2860e8a | ||
|
|
2777a2bfd9 | ||
|
|
9fc1cb40f9 | ||
|
|
6238296458 | ||
|
|
9042dfc4b1 | ||
|
|
016d6d27d1 | ||
|
|
e54741745c | ||
|
|
110e3bd7a6 | ||
|
|
c1b569d9d6 | ||
|
|
577dc34565 | ||
|
|
c7b3f0217f | ||
|
|
e81c89ddd6 | ||
|
|
07b0026e5d | ||
|
|
b531801d6f | ||
|
|
f563b896cc | ||
|
|
c90c6fee01 | ||
|
|
0a0242582f | ||
|
|
2baa531ce5 | ||
|
|
ccef8581b8 | ||
|
|
2d00d8b321 | ||
|
|
e8c3f4860d | ||
|
|
00f03498a9 | ||
|
|
688924d2a8 | ||
|
|
3d45373d3b | ||
|
|
64b43fdf70 | ||
|
|
7b8efcc7cb | ||
|
|
c13401c0a7 | ||
|
|
847a36f064 | ||
|
|
2b7fc4aee9 | ||
|
|
f8459cf838 | ||
|
|
22b5645879 | ||
|
|
d44d592013 | ||
|
|
0c8e7bad3e | ||
|
|
37d7ce16c5 | ||
|
|
9ed0a6ba35 | ||
|
|
35008b75e4 | ||
|
|
9855bc011e | ||
|
|
22093ad2b6 | ||
|
|
ee0508f01c | ||
|
|
32e51de2af | ||
|
|
560f67c9f0 | ||
|
|
3ae075a51a | ||
|
|
1bf590ab2d | ||
|
|
dee7e3f16e | ||
|
|
13edc746f6 | ||
|
|
1e6d2c0488 | ||
|
|
228d83ed24 | ||
|
|
ede0d1b42d | ||
|
|
1e8b786e65 | ||
|
|
8b9026f3ae | ||
|
|
795877532e | ||
|
|
da8d0659a6 | ||
|
|
d06126f814 | ||
|
|
2be02a7c9a | ||
|
|
30fe67226a | ||
|
|
2bfacfe3d0 | ||
|
|
76dad6d1fb | ||
|
|
a2fd82f622 | ||
|
|
3a283cfe9f | ||
|
|
ca9399d4ee | ||
|
|
597b0ae509 | ||
|
|
21c1c29592 | ||
|
|
00f928642f | ||
|
|
c81a0853bb | ||
|
|
bb6ddd8e04 | ||
|
|
7340f67b98 | ||
|
|
1d2674bacc | ||
|
|
e1b7e40ff0 | ||
|
|
c2886473a8 | ||
|
|
ac065c57fd | ||
|
|
9a33077a7b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,6 +8,7 @@
|
||||
.deps
|
||||
.emacs*
|
||||
.libs
|
||||
.gdbinit
|
||||
ABOUT-NLS
|
||||
ChangeLog
|
||||
INSTALL
|
||||
@@ -28,3 +29,4 @@ libtool
|
||||
m4
|
||||
rmt
|
||||
stamp-h1
|
||||
TAGS
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Main Makefile for GNU tar.
|
||||
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2007, 2009, 2013-2014, 2016 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
163
NEWS
163
NEWS
@@ -1,5 +1,152 @@
|
||||
GNU tar NEWS - User visible changes. 2016-05-16
|
||||
GNU tar NEWS - User visible changes. 2021-02-13
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
version 1.34 - Sergey Poznyakoff, 2021-02-13
|
||||
|
||||
* Fix extraction over pipe (savannah bug #60002)
|
||||
|
||||
* Fix memory leak in read_header (savannah bug #59897)
|
||||
|
||||
* Fix extraction when . and .. are unreadable
|
||||
|
||||
See https://lists.gnu.org/archive/html/bug-tar/2021-01/msg00012.html
|
||||
|
||||
* Gracefully handle duplicate symlinks when extracting
|
||||
|
||||
See https://lists.gnu.org/archive/html/bug-tar/2021-01/msg00026.html
|
||||
|
||||
* Re-initialize supplementary groups when switching to user privileges
|
||||
|
||||
version 1.33 - Sergey Poznyakoff, 2021-01-07
|
||||
|
||||
* POSIX extended format headers do not include PID by default
|
||||
|
||||
The intent is to make binary-equivalent PAX archives easy to create. If
|
||||
POSIXLY_CORRECT is set, the POSIX standard default is used, which embeds
|
||||
the pid.
|
||||
|
||||
* --delay-directory-restore works for archives with reversed member ordering
|
||||
|
||||
* Fix extraction of a symbolic link hardlinked to another symbolic link
|
||||
|
||||
* Wildcards in exclude-vcs-ignore mode don't match slash
|
||||
|
||||
* Fix the --no-overwrite-dir option
|
||||
|
||||
Given this option, previous versions of tar failed to preserve
|
||||
permissions of empty directories and to create files under directories
|
||||
owned by the current user that did not have the S_IWUSR bit set.
|
||||
|
||||
* Fix handling of chained renames in incremental backups
|
||||
|
||||
* Link counting works for file names supplied with -T
|
||||
|
||||
* Accept only position-sensitive (file-selection) options in file list files.
|
||||
|
||||
Using such options as -f, -z, etc. is senseless in a file list file and
|
||||
bypasses option consistency checks in decode_options. Therefore,
|
||||
only options related to file selection (a.k.a position-sensitive options)
|
||||
are allowed in file list files.
|
||||
|
||||
|
||||
version 1.32 - Sergey Poznyakoff, 2019-02-23
|
||||
|
||||
* Fix the use of --checkpoint without explicit --checkpoint-action
|
||||
|
||||
* Fix extraction with the -U option
|
||||
|
||||
See http://lists.gnu.org/archive/html/bug-tar/2019-01/msg00015.html,
|
||||
for details
|
||||
|
||||
* Fix iconv usage on BSD-based systems
|
||||
|
||||
* Fix possible NULL dereference (savannah bug #55369)
|
||||
|
||||
* Improve the testsuite
|
||||
|
||||
|
||||
version 1.31 - Sergey Poznyakoff, 2019-01-02
|
||||
|
||||
* Fix heap-buffer-overrun with --one-top-level.
|
||||
Bug introduced with the addition of that option in 1.28.
|
||||
|
||||
* Support for zstd compression
|
||||
|
||||
New option '--zstd' instructs tar to use zstd as compression program.
|
||||
When listing, extractng and comparing, zstd compressed archives are
|
||||
recognized automatically.
|
||||
When '-a' option is in effect, zstd compression is selected if the
|
||||
destination archive name ends in '.zst' or '.tzst'.
|
||||
|
||||
* The -K option interacts properly with member names given in the command line
|
||||
|
||||
Names of members to extract can be specified along with the "-K NAME"
|
||||
option. In this case, tar will extract NAME and those of named members
|
||||
that appear in the archive after it, which is consistent with the
|
||||
semantics of the option.
|
||||
|
||||
Previous versions of tar extracted NAME, those of named members that
|
||||
appeared before it, and everything after it.
|
||||
|
||||
* Fix CVE-2018-20482
|
||||
|
||||
When creating archives with the --sparse option, previous versions of
|
||||
tar would loop endlessly if a sparse file had been truncated while
|
||||
being archived.
|
||||
|
||||
|
||||
version 1.30 - Sergey Poznyakoff, 2017-12-17
|
||||
|
||||
* Member names containing '..' components are now skipped when extracting.
|
||||
|
||||
This fixes tar's behavior to match its documentation, and is a bit
|
||||
safer when extracting untrusted archives over old files (an unsafe
|
||||
practice that the tar manual has long recommended against).
|
||||
|
||||
* Report erroneous use of position-sensitive options.
|
||||
|
||||
During archive creation or update, tar keeps track of positional
|
||||
options (see the manual, subsection 3.4.4 "Position-Sensitive
|
||||
Options"), and reports those that had no effect. For example, when
|
||||
invoked as
|
||||
|
||||
tar -cf a.tar . --exclude '*.o'
|
||||
|
||||
tar will create the archive, but will exit with status 2, having
|
||||
issued the following error message
|
||||
|
||||
tar: The following options were used after non-optional
|
||||
arguments in archive create or update mode. These options are
|
||||
positional and affect only arguments that follow them. Please,
|
||||
rearrange them properly.
|
||||
tar: --exclude '*.o' has no effect
|
||||
tar: Exiting with failure status due to previous errors
|
||||
|
||||
* --numeric-owner now affects private headers too.
|
||||
|
||||
This helps the output of 'tar' to be more deterministic.
|
||||
|
||||
* Fixed the --delay-directory-restore option
|
||||
|
||||
In some cases tar would restore the directory permissions too early,
|
||||
causing subsequent link extractions in that directory to fail.
|
||||
|
||||
* The --warnings=failed-read option
|
||||
|
||||
This new warning control option suppresses warning messages about
|
||||
unreadable files and directories. It has effect only if used together
|
||||
with the --ignore-failed-read option.
|
||||
|
||||
* The --warnings=none option now suppresses all warnings
|
||||
|
||||
This includes warnings about unreadable files produced when
|
||||
--ignore-failed-read is in effect. To output these, use
|
||||
--warnings=none --warnings=no-failed-read.
|
||||
|
||||
* Fix reporting of hardlink mismatches during compare
|
||||
|
||||
Tar reported incorrect target file name in the 'Not linked to'
|
||||
diagnostic message.
|
||||
|
||||
|
||||
version 1.29 - Sergey Poznyakoff, 2016-05-16
|
||||
@@ -24,7 +171,7 @@ the command line. Its effect is reverted by the
|
||||
|
||||
* --null option reads file names verbatim
|
||||
|
||||
The --null option implies --verbatim-files-from. I.e. each line
|
||||
The --null option implies --verbatim-files-from. I.e. each line
|
||||
read from null-delimited file lists is treated as a file name.
|
||||
|
||||
This restores the documented behavior, which was broken in version
|
||||
@@ -55,7 +202,7 @@ use the time specified if the file mtime is newer than the given time.
|
||||
The --clamp-mtime option can only be used together with --mtime.
|
||||
|
||||
Typical use case is to make builds reproducible: to loose less
|
||||
information, it's better to keep the original date of an archive,
|
||||
information, it's better to keep the original date of an archive,
|
||||
except for files modified during the build process. In that case, using
|
||||
reference (and thus reproducible) timestamps for the latter is good
|
||||
enough.
|
||||
@@ -103,7 +250,7 @@ sign and the specifier letter.
|
||||
deleted, correspondingly.
|
||||
%{FMT}t - Current local time using FMT as strftime(3) format.
|
||||
If {FMT} is omitted, use %c.
|
||||
%{N}* - Pad output with spaces to the Nth column, or to the
|
||||
%{N}* - Pad output with spaces to the Nth column, or to the
|
||||
current screen width, if {N} is not given.
|
||||
%c - A shortcut for "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r"
|
||||
|
||||
@@ -142,7 +289,7 @@ speed up archivation.
|
||||
--exclude-vcs-ignores Read exclude tags from VCS ignore files,
|
||||
where such files exist. Supported VCS's
|
||||
are: CVS, Git, Bazaar, Mercurial.
|
||||
|
||||
|
||||
|
||||
* Tar refuses to read input from and write output to a tty device.
|
||||
|
||||
@@ -151,7 +298,7 @@ speed up archivation.
|
||||
This release includes official tar(1) and rmt(8) manpages.
|
||||
Distribution maintainers are kindly asked to use these instead of the
|
||||
home-made pages they have been providing so far.
|
||||
|
||||
|
||||
|
||||
version 1.27.1 - Sergey Poznyakoff, 2013-11-17
|
||||
|
||||
@@ -244,7 +391,7 @@ tar discovers that the corresponding file name already exists and is a
|
||||
symbolic link, it first unlinks the entry, and then extracts the directory.
|
||||
|
||||
This option disables this behavior and instructs tar to follow
|
||||
symlinks to directories when extracting from the archive.
|
||||
symlinks to directories when extracting from the archive.
|
||||
|
||||
It is mainly intended to provide compatibility with the Slackware
|
||||
installation scripts.
|
||||
@@ -1587,7 +1734,7 @@ Versions 1.07 back to 1.00 by Jay Fenlason.
|
||||
|
||||
|
||||
|
||||
Copyright 1994-2001, 2003-2010, 2013-2016 Free Software Foundation, Inc.
|
||||
Copyright 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
3
README
3
README
@@ -221,8 +221,7 @@ and share your findings by writing to <bug-tar@gnu.org>.
|
||||
|
||||
* Copying
|
||||
|
||||
Copyright 1990-1992, 1994, 1997-2001, 2003-2004, 2007, 2012-2014, 2016
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1990-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ behavior. Run 'bootstrap --help' for a list.
|
||||
|
||||
|
||||
|
||||
Copyright 2001, 2003-2005, 2007, 2013-2016 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2001-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ See 'bootstrap --help' for a detailed list.
|
||||
|
||||
* Copyright information
|
||||
|
||||
Copyright 2007-2009, 2013-2016 Free Software Foundation, Inc.
|
||||
Copyright 2007-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
3
THANKS
3
THANKS
@@ -8,6 +8,7 @@ list of these people. Help me keep it complete and exempt of errors.
|
||||
See various ChangeLogs for a detailed description of contributions.
|
||||
|
||||
Aage Robeck aagero@ifi.uio.no
|
||||
Adam Borowski kilobyte@angband.pl
|
||||
Adye, TJ (Tim) T.J.Adye@rl.ac.uk
|
||||
Akiko Matsushita matusita@sra.co.jp
|
||||
Alan Bawden Alan@lcs.mit.edu
|
||||
@@ -94,6 +95,7 @@ Christian Laubscher christian.laubscher@tiscalinet.ch
|
||||
Christian T. Dum ctd@mpe-garching.mpg.de
|
||||
Christian von Roques roques@pond.sub.org
|
||||
Christian Wetzel wetzel@phoenix-pacs.de
|
||||
Christian Weisgerber naddy@mips.inka.de
|
||||
Christoph Litauer litauer@mailhost.uni-koblenz.de
|
||||
Christophe Colle colle@krtkg1.rug.ac.be
|
||||
Christophe Kalt Christophe.Kalt@kbcfp.com
|
||||
@@ -138,6 +140,7 @@ David Nugent davidn@blaze.net.au
|
||||
David Shaw david.shaw@alcatel.com.au
|
||||
David Steiner dsteiner@ispa.uni-osnabrueck.de
|
||||
David Taylor taylor@think.com
|
||||
Dawid dpc@dpc.pw
|
||||
Dean Gaudet dgaudet@watdragon.uwaterloo.ca
|
||||
Demizu Noritoshi nori-d@is.aist-nara.ac.jp
|
||||
Denis Excoffier denis.excoffier@free.fr
|
||||
|
||||
3
TODO
3
TODO
@@ -45,8 +45,7 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright 2003-2004, 2007, 2013-2014, 2016 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2003-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dnl Special Autoconf macros for GNU tar -*- autoconf -*-
|
||||
|
||||
dnl Copyright 2009, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
dnl Copyright 2009-2021 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is part of GNU tar.
|
||||
dnl
|
||||
|
||||
@@ -4,7 +4,7 @@ scriptversion=2015-08-24.08; # UTC
|
||||
|
||||
# Bootstrap this package from checked-out sources.
|
||||
|
||||
# Copyright (C) 2003-2016 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003-2021 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bootstrap configuration for GNU tar.
|
||||
|
||||
# Copyright 2006-2009, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
21
configure.ac
21
configure.ac
@@ -1,6 +1,6 @@
|
||||
# Configure template for GNU tar. -*- autoconf -*-
|
||||
|
||||
# Copyright 1991, 1994-2010, 2013-2016 Free Software Foundation, Inc.
|
||||
# Copyright 1991, 1994-2010, 2013-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT([GNU tar], [1.29], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.34], [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-xz std-options silent-rules])
|
||||
AC_PREREQ([2.64])
|
||||
AM_INIT_AUTOMAKE([1.15 gnits tar-ustar dist-bzip2 dist-xz std-options silent-rules])
|
||||
|
||||
# Enable silent rules by default:
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -102,6 +102,18 @@ gt_TYPE_SSIZE_T
|
||||
|
||||
# gnulib modules
|
||||
gl_INIT
|
||||
|
||||
if test $ac_cv_lib_error_at_line = no; then
|
||||
# This means that the error() function is not present in libc, so
|
||||
# the one from gnulib will be used instead. This function precedes
|
||||
# error messages it prints with the program name as returned by getprogname()
|
||||
# call, instead of using the name set by set_program_name.
|
||||
# Install workaround.
|
||||
AC_DEFINE([ENABLE_ERROR_PRINT_PROGNAME],[1],
|
||||
[Enable the use of error_print_progname to print program name with error messages.
|
||||
See comment to function tar_print_progname in src/tar.c])
|
||||
fi
|
||||
|
||||
# paxutils modules
|
||||
tar_PAXUTILS
|
||||
|
||||
@@ -250,6 +262,7 @@ TAR_COMPR_PROGRAM(lzip)
|
||||
TAR_COMPR_PROGRAM(lzma)
|
||||
TAR_COMPR_PROGRAM(lzop)
|
||||
TAR_COMPR_PROGRAM(xz)
|
||||
TAR_COMPR_PROGRAM(zstd)
|
||||
|
||||
AC_MSG_CHECKING(for default archive format)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
%%comments:
|
||||
Copyright 2004, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
|
||||
1
doc/.gitignore
vendored
1
doc/.gitignore
vendored
@@ -24,3 +24,4 @@ tar.tp
|
||||
tar.vr
|
||||
version.texi
|
||||
/parse-datetime.texi
|
||||
/rmt.8
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Makefile for GNU tar documentation.
|
||||
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2006-2007, 2013-2014, 2016 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -23,11 +22,11 @@ tar_TEXINFOS = \
|
||||
dumpdir.texi\
|
||||
tar-snapshot-edit.texi\
|
||||
fdl.texi\
|
||||
freemanuals.texi\
|
||||
genfile.texi\
|
||||
header.texi\
|
||||
intern.texi\
|
||||
parse-datetime.texi\
|
||||
recipes.texi\
|
||||
rendition.texi\
|
||||
snapshot.texi\
|
||||
sparse.texi\
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006-2007, 2014, 2016 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2021 Free Software Foundation, Inc.
|
||||
@c Written by Sergey Poznyakoff
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000-2002, 2007-2008, 2014, 2016 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright @copyright{} 2000--2021 Free Software Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
@cindex free documentation
|
||||
|
||||
The biggest deficiency in the free software community today is not in
|
||||
the software---it is the lack of good free documentation that we can
|
||||
include with the free software. Many of our most important
|
||||
programs do not come with free reference manuals and free introductory
|
||||
texts. Documentation is an essential part of any software package;
|
||||
when an important free software package does not come with a free
|
||||
manual and a free tutorial, that is a major gap. We have many such
|
||||
gaps today.
|
||||
|
||||
Consider Perl, for instance. The tutorial manuals that people
|
||||
normally use are non-free. How did this come about? Because the
|
||||
authors of those manuals published them with restrictive terms---no
|
||||
copying, no modification, source files not available---which exclude
|
||||
them from the free software world.
|
||||
|
||||
That wasn't the first time this sort of thing happened, and it was far
|
||||
from the last. Many times we have heard a GNU user eagerly describe a
|
||||
manual that he is writing, his intended contribution to the community,
|
||||
only to learn that he had ruined everything by signing a publication
|
||||
contract to make it non-free.
|
||||
|
||||
Free documentation, like free software, is a matter of freedom, not
|
||||
price. The problem with the non-free manual is not that publishers
|
||||
charge a price for printed copies---that in itself is fine. (The Free
|
||||
Software Foundation sells printed copies of manuals, too.) The
|
||||
problem is the restrictions on the use of the manual. Free manuals
|
||||
are available in source code form, and give you permission to copy and
|
||||
modify. Non-free manuals do not allow this.
|
||||
|
||||
The criteria of freedom for a free manual are roughly the same as for
|
||||
free software. Redistribution (including the normal kinds of
|
||||
commercial redistribution) must be permitted, so that the manual can
|
||||
accompany every copy of the program, both on-line and on paper.
|
||||
|
||||
Permission for modification of the technical content is crucial too.
|
||||
When people modify the software, adding or changing features, if they
|
||||
are conscientious they will change the manual too---so they can
|
||||
provide accurate and clear documentation for the modified program. A
|
||||
manual that leaves you no choice but to write a new manual to document
|
||||
a changed version of the program is not really available to our
|
||||
community.
|
||||
|
||||
Some kinds of limits on the way modification is handled are
|
||||
acceptable. For example, requirements to preserve the original
|
||||
author's copyright notice, the distribution terms, or the list of
|
||||
authors, are ok. It is also no problem to require modified versions
|
||||
to include notice that they were modified. Even entire sections that
|
||||
may not be deleted or changed are acceptable, as long as they deal
|
||||
with nontechnical topics (like this one). These kinds of restrictions
|
||||
are acceptable because they don't obstruct the community's normal use
|
||||
of the manual.
|
||||
|
||||
However, it must be possible to modify all the @emph{technical}
|
||||
content of the manual, and then distribute the result in all the usual
|
||||
media, through all the usual channels. Otherwise, the restrictions
|
||||
obstruct the use of the manual, it is not free, and we need another
|
||||
manual to replace it.
|
||||
|
||||
Please spread the word about this issue. Our community continues to
|
||||
lose manuals to proprietary publishing. If we spread the word that
|
||||
free software needs free reference manuals and free tutorials, perhaps
|
||||
the next person who wants to contribute by writing documentation will
|
||||
realize, before it is too late, that only free manuals contribute to
|
||||
the free software community.
|
||||
|
||||
If you are writing documentation, please insist on publishing it under
|
||||
the GNU Free Documentation License or another free documentation
|
||||
license. Remember that this decision requires your approval---you
|
||||
don't have to let the publisher decide. Some commercial publishers
|
||||
will use a free license if you insist, but they will not propose the
|
||||
option; it is up to you to raise the issue and say firmly that this is
|
||||
what you want. If the publisher you are dealing with refuses, please
|
||||
try other publishers. If you're not sure whether a proposed license
|
||||
is free, write to @email{licensing@@gnu.org}.
|
||||
|
||||
You can encourage commercial publishers to sell more free, copylefted
|
||||
manuals and tutorials by buying them, and particularly by buying
|
||||
copies from the publishers that paid for their writing or for major
|
||||
improvements. Meanwhile, try to avoid buying non-free documentation
|
||||
at all. Check the distribution terms of a manual before you buy it,
|
||||
and insist that whoever seeks your business must respect your freedom.
|
||||
Check the history of the book, and try reward the publishers that have
|
||||
paid or pay the authors to work on it.
|
||||
|
||||
The Free Software Foundation maintains a list of free documentation
|
||||
published by other publishers, at
|
||||
@url{http://www.fsf.org/doc/other-free-books.html}.
|
||||
@@ -106,7 +106,7 @@ Please send broken links and other corrections (or suggestions) to
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Copyright 2004, 2013-2014, 2016 Free Software Foundation, Inc.,
|
||||
Copyright 2004-2021 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02111, USA
|
||||
<br />
|
||||
Verbatim copying and distribution of this entire article is
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2014, 2016 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2021 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -87,6 +87,8 @@ The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and
|
||||
@code{gname} are null-terminated character strings. All other fields
|
||||
are zero-filled octal numbers in ASCII. Each numeric field of width
|
||||
@var{w} contains @var{w} minus 1 digits, and a null.
|
||||
(In the extended @acronym{GNU} format, the numeric fields can take
|
||||
other forms.)
|
||||
|
||||
The @code{name} field is the file name of the file, with directory names
|
||||
(if any) preceding the file name, separated by slashes.
|
||||
@@ -112,14 +114,12 @@ be ignored.
|
||||
The @code{size} field is the size of the file in bytes; linked files
|
||||
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
|
||||
value of the last time the file's contents were modified, represented
|
||||
as an integer number of
|
||||
The @code{mtime} field represents the data modification time of the file at
|
||||
the time it was archived. It represents the integer number of
|
||||
seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
||||
|
||||
The @code{chksum} field is the ASCII representation of the octal value
|
||||
of the simple sum of all bytes in the header block. Each 8-bit
|
||||
The @code{chksum} field represents
|
||||
the simple sum of all bytes in the header block. Each 8-bit
|
||||
byte in the header is added to an unsigned integer, initialized to
|
||||
zero, the precision of which shall be no less than seventeen bits.
|
||||
When calculating the checksum, the @code{chksum} field is treated as
|
||||
@@ -310,6 +310,18 @@ of an archive should have this type.
|
||||
|
||||
@end table
|
||||
|
||||
For fields containing numbers or timestamps that are out of range for
|
||||
the basic format, the @acronym{GNU} format uses a base-256
|
||||
representation instead of an ASCII octal number. If the leading byte
|
||||
is 0xff (255), all the bytes of the field (including the leading byte)
|
||||
are concatenated in big-endian order, with the result being a negative
|
||||
number expressed in two's complement form. If the leading byte is
|
||||
0x80 (128), the non-leading bytes of the field are concatenated in
|
||||
big-endian order, with the result being a positive number expressed in
|
||||
binary form. Leading bytes other than 0xff, 0x80 and ASCII octal
|
||||
digits are reserved for future use, as are base-256 representations of
|
||||
values that would be in range for the basic format.
|
||||
|
||||
You may have trouble reading a @acronym{GNU} format archive on a
|
||||
non-@acronym{GNU} system if the options @option{--incremental} (@option{-G}),
|
||||
@option{--multi-volume} (@option{-M}), @option{--sparse} (@option{-S}), or @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) were
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright 2006-2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
;; Copyright 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Sergey Poznyakoff
|
||||
;; Maintainer: bug-tar@gnu.org
|
||||
|
||||
134
doc/recipes.texi
Normal file
134
doc/recipes.texi
Normal file
@@ -0,0 +1,134 @@
|
||||
@c This is part of the GNU tar manual.
|
||||
@c Copyright (C) 2017--2021 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.3 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
This appendix provides several recipes for performing common tasks
|
||||
using @GNUTAR{}.
|
||||
|
||||
@menu
|
||||
* copy directory hierarchy::
|
||||
* intermediate directories::
|
||||
@end menu
|
||||
|
||||
@node copy directory hierarchy
|
||||
@appendixsec Copying directory hierarchies
|
||||
|
||||
This is a traditional way to copy a directory hierarchy preserving
|
||||
the dates, modes, owners and link-structure of all the files therein.
|
||||
It was used back when the @command{cp} command lacked the @option{-a}
|
||||
option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{(cd sourcedir; tar -cf - .) | (cd targetdir; tar -xf -)}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
You can avoid subshells by using @option{-C} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar -C sourcedir -cf - . | tar -C targetdir -xf -}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
The same command using long option forms:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{(cd sourcedir; tar --create --file=- . ) \
|
||||
| (cd targetdir; tar --extract --file=-)}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
or
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{tar --directory sourcedir --create --file=- . \
|
||||
| tar --directory targetdir --extract --file=-}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@node intermediate directories
|
||||
@appendixsec Restoring Intermediate Directories
|
||||
|
||||
A common concern is how to extract permissions and ownerships of
|
||||
intermediate directories when extracting only selected members from
|
||||
the archive. To illustrate this, consider the following archive:
|
||||
|
||||
@example
|
||||
@group
|
||||
# tar tvf A.tar
|
||||
drwxr-xr-x root/root 0 2017-11-16 14:39 foo/
|
||||
dr-xr-x--- gray/user 0 2017-11-16 14:39 foo/bar/
|
||||
-rw-r--r-- gray/user 10 2017-11-16 14:40 foo/bar/file
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Suppose you extract only the file @file{foo/bar/file}, while being
|
||||
@samp{root}:
|
||||
|
||||
@example
|
||||
# @kbd{tar xvf A.tar foo/bar/file}
|
||||
foo/bar/file
|
||||
@end example
|
||||
|
||||
Now, let's inspect the content of the created directories:
|
||||
|
||||
@example
|
||||
@group
|
||||
# find foo -ls
|
||||
427257 0 drwxr-xr-x 3 root root 16 Nov 17 16:10 foo
|
||||
427258 0 drwxr-xr-x 2 root root 17 Nov 17 16:10 foo/bar
|
||||
427259 0 -rw-r--r-- 1 gray user 10 Nov 6 14:40 foo/bar/file
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The requested file is restored, including its ownership and
|
||||
permissions. The intermediate directories, however, are created with
|
||||
the default permissions, current timestamp and owned by the current
|
||||
user. This is because by the time @command{tar} has reached the requested file,
|
||||
it had already skipped the entries for its parent directories, so it
|
||||
has no iformation about their ownership and modes.
|
||||
|
||||
To restore meta information about the intermediate directories,
|
||||
you'll need to specify them explicitly in the command line and use the
|
||||
@option{--no-recursive} option (@pxref{recurse}) to avoid extracting
|
||||
their content.
|
||||
|
||||
To automate this process, @cite{Neal P. Murphy} proposed the following
|
||||
shell script@footnote{The original version of the script can be
|
||||
seen at @uref{http://lists.gnu.org/archive/html/bug-tar/2016-11/msg00024.html}}:
|
||||
|
||||
@example
|
||||
@group
|
||||
#! /bin/sh
|
||||
(while read path
|
||||
do
|
||||
path=`dirname $path`
|
||||
while [ -n "$path" -a "$path" != "." ]
|
||||
do
|
||||
echo $path
|
||||
path=`dirname $path`
|
||||
done
|
||||
done < $2 | sort | uniq) |
|
||||
tar -x --no-recursion -v -f $1 -T - -T $2
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The script takes two arguments: the name of the archive file, and the
|
||||
name of the file list file.
|
||||
|
||||
To complete our example, the file list will contain single line:
|
||||
|
||||
@example
|
||||
foo/bar/file
|
||||
@end example
|
||||
|
||||
Supposing its name is @file{file.list} and the script is named
|
||||
@file{restore.sh}, you can invoke it as follows:
|
||||
|
||||
@example
|
||||
# @kbd{sh restore.sh A.tar file.list}
|
||||
@end example
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright 1992, 1994-1997, 1999-2004, 2006, 2013-2014, 2016 Free
|
||||
@c Software Foundation, Inc.
|
||||
@c Copyright 1992--2021 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@c This file contains support for 'renditions' by Fran@,{c}ois Pinard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2005, 2007, 2014, 2016 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2005--2021 Free Software Foundation, Inc.
|
||||
@c Written by Sergey Poznyakoff
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
@@ -146,7 +146,7 @@ is compiled. To see the specific ranges allowed for a particular
|
||||
@option{--show-snapshot-field-ranges} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --show-shapshot-field-ranges}
|
||||
$ @kbd{tar --show-snapshot-field-ranges}
|
||||
This tar's snapshot file field ranges are
|
||||
(field name => [ min, max ]):
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2014, 2016 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2021 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -143,7 +143,7 @@ format, it will also extract a file containing extension header
|
||||
attributes. This file can be used to expand the file to its original
|
||||
state. However, posix-aware @command{tar}s will usually ignore the
|
||||
unknown variables, which makes restoring the file more
|
||||
difficult. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
difficult. @xref{extracting sparse v0x, Extraction of sparse
|
||||
members in v.0.0 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
@end enumerate
|
||||
@@ -175,7 +175,7 @@ The real name of the sparse file is stored in the variable
|
||||
@code{GNU.sparse.name}. Thus, those @command{tar} implementations
|
||||
that are not aware of GNU extensions will at least extract the files
|
||||
into separate directories, giving the user a possibility to expand it
|
||||
afterwards. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
afterwards. @xref{extracting sparse v0x, Extraction of sparse
|
||||
members in v.0.1 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
|
||||
@@ -218,12 +218,12 @@ The real name of the sparse file is stored in the variable
|
||||
variable @code{GNU.sparse.realsize}.
|
||||
|
||||
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
|
||||
file data. It consists of a series of decimal numbers delimited
|
||||
by newlines. The map is padded with nulls to the nearest block boundary.
|
||||
|
||||
The first number gives the number of entries in the map. Following are map entries,
|
||||
each one consisting of two numbers giving the offset and size of the
|
||||
data block it describes.
|
||||
The first number gives the number of entries in the map. Following are
|
||||
map entries, each one consisting of two numbers giving the offset and
|
||||
size of the data block it describes.
|
||||
|
||||
The format is designed in such a way that non-posix aware @command{tar}s and @command{tar}s not
|
||||
supporting @code{GNU.sparse.*} keywords will extract each sparse file
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2007, 2014, 2016 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2007--2021 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
|
||||
74
doc/tar.1
74
doc/tar.1
@@ -1,5 +1,5 @@
|
||||
.\" This file is part of GNU tar. -*- nroff -*-
|
||||
.\" Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
.\" Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
.\"
|
||||
.\" GNU tar is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the GNU General Public License as published by
|
||||
@@ -13,7 +13,7 @@
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public License
|
||||
.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.TH TAR 1 "March 23, 2016" "TAR" "GNU TAR Manual"
|
||||
.TH TAR 1 "July 13, 2020" "TAR" "GNU TAR Manual"
|
||||
.SH NAME
|
||||
tar \- an archiving utility
|
||||
.SH SYNOPSIS
|
||||
@@ -111,7 +111,7 @@ into the archive file
|
||||
verbosely listing the files being archived:
|
||||
.PP
|
||||
.EX
|
||||
.B tar cfv a.tar /etc
|
||||
tar cfv etc.tar /etc
|
||||
.EE
|
||||
.PP
|
||||
In
|
||||
@@ -133,9 +133,11 @@ The example command above written in the
|
||||
could look like:
|
||||
.PP
|
||||
.EX
|
||||
.B tar -cvf a.tar /etc
|
||||
tar -cvf etc.tar /etc
|
||||
.EE
|
||||
or
|
||||
.B tar -c -v -f a.tar /etc
|
||||
.EX
|
||||
tar -c -v -f etc.tar /etc
|
||||
.EE
|
||||
.PP
|
||||
In
|
||||
@@ -152,11 +154,11 @@ method.
|
||||
Here are several ways of writing the example command in this style:
|
||||
.PP
|
||||
.EX
|
||||
.B tar --create --file a.tar --verbose /etc
|
||||
tar --create --file etc.tar --verbose /etc
|
||||
.EE
|
||||
or (abbreviating some options):
|
||||
.EX
|
||||
.B tar --cre --file=a.tar --verb /etc
|
||||
tar --cre --file=etc.tar --verb /etc
|
||||
.EE
|
||||
.PP
|
||||
The options in all three styles can be intermixed, although doing so
|
||||
@@ -219,7 +221,10 @@ There is no short option equivalent for this option.
|
||||
\fB\-u\fR, \fB\-\-update\fR
|
||||
Append files which are newer than the corresponding copy in the
|
||||
archive. Arguments have the same meaning as with \fB\-c\fR and
|
||||
\fB\-r\fR options.
|
||||
\fB\-r\fR options. Notice, that newer files don't replace their
|
||||
old archive copies, but instead are appended to the end of archive.
|
||||
The resulting archive can thus contain several members of the
|
||||
same name, corresponding to various versions of the same file.
|
||||
.TP
|
||||
\fB\-x\fR, \fB\-\-extract\fR, \fB\-\-get\fR
|
||||
Extract files from an archive. Arguments are optional. When given,
|
||||
@@ -253,7 +258,7 @@ exist when creating an archive, it will be created and all files will
|
||||
be added to the resulting archive (the \fBlevel 0\fR dump). To create
|
||||
incremental archives of non-zero level \fBN\fR, create a copy of the
|
||||
snapshot file created during the level \fBN-1\fR, and use it as
|
||||
\fIFILE\fR.
|
||||
\fIFILE\fR.
|
||||
|
||||
When listing or extracting, the actual contents of \fIFILE\fR is not
|
||||
inspected, it is needed only due to syntactical requirements. It is
|
||||
@@ -284,7 +289,7 @@ effect only if the archive is open for reading (e.g. with
|
||||
.B \-\-list
|
||||
or
|
||||
.B \-\-extract
|
||||
options).
|
||||
options).
|
||||
.TP
|
||||
\fB\-\-no\-check\-device\fR
|
||||
Do not check device numbers when creating incremental archives.
|
||||
@@ -333,6 +338,9 @@ Don't replace existing files when extracting.
|
||||
\fB\-\-keep\-newer\-files\fR
|
||||
Don't replace existing files that are newer than their archive copies.
|
||||
.TP
|
||||
\fB\-\-keep\-directory\-symlink\fR
|
||||
Don't replace existing symlinks to directories when extracting.
|
||||
.TP
|
||||
\fB\-\-no\-overwrite\-dir\fR
|
||||
Preserve metadata of existing directories.
|
||||
.TP
|
||||
@@ -377,7 +385,7 @@ Extract files to standard output.
|
||||
Pipe extracted files to \fICOMMAND\fR. The argument is the pathname
|
||||
of an external program, optionally with command line arguments. The
|
||||
program will be invoked and the contents of the file being extracted
|
||||
supplied to it on its standard output. Additional data will be
|
||||
supplied to it on its standard input. Additional data will be
|
||||
supplied via the following environment variables:
|
||||
.RS
|
||||
.TP
|
||||
@@ -457,9 +465,10 @@ Format of the archive being processed. One of:
|
||||
.BR posix ,
|
||||
.BR ustar ,
|
||||
.BR v7 .
|
||||
.TP
|
||||
.B TAR_SUBCOMMAND
|
||||
A short option (with a leading dash) describing the operation \fBtar\fR is
|
||||
executing.
|
||||
executing.
|
||||
.RE
|
||||
.SS Handling of file attributes
|
||||
.TP
|
||||
@@ -556,9 +565,6 @@ stored in archive with owner name \fINEWUSR\fR and UID \fINEWUID\fR.
|
||||
\fB\-p\fR, \fB\-\-preserve\-permissions\fR, \fB\-\-same\-permissions\fR
|
||||
extract information about file permissions (default for superuser)
|
||||
.TP
|
||||
\fB\-\-preserve\fR
|
||||
Same as both \fB\-p\fR and \fB\-s\fR.
|
||||
.TP
|
||||
\fB\-\-same\-owner\fR
|
||||
Try extracting files with the same ownership as exists in the archive
|
||||
(default for superuser).
|
||||
@@ -688,7 +694,7 @@ executing.
|
||||
.B TAR_FD
|
||||
File descriptor which can be used to communicate the new volume name
|
||||
to
|
||||
.BR tar .
|
||||
.BR tar .
|
||||
.RE
|
||||
.RS
|
||||
|
||||
@@ -726,7 +732,7 @@ When this option is used in conjunction with
|
||||
.BR \-\-multi\-volume ,
|
||||
.B tar
|
||||
will keep track of which volume of a multi-volume archive it is
|
||||
working in \fIFILE\fR.
|
||||
working in \fIFILE\fR.
|
||||
.SS Device blocking
|
||||
.TP
|
||||
\fB\-b\fR, \fB\-\-blocking\-factor\fR=\fIBLOCKS\fR
|
||||
@@ -734,7 +740,7 @@ Set record size to \fIBLOCKS\fRx\fB512\fR bytes.
|
||||
.TP
|
||||
\fB\-B\fR, \fB\-\-read\-full\-records\fR
|
||||
When listing or extracting, accept incomplete input records after
|
||||
end-of-file marker.
|
||||
end-of-file marker.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-ignore\-zeros\fR
|
||||
Ignore zeroed blocks in archive. Normally two consecutive 512-blocks
|
||||
@@ -777,7 +783,8 @@ Same as \fB\-\-format=v7\fR.
|
||||
\fB\-\-pax\-option\fR=\fIkeyword\fR[[:]=\fIvalue\fR][,\fIkeyword\fR[[:]=\fIvalue\fR]]...
|
||||
Control pax keywords when creating \fBPAX\fR archives (\fB\-H
|
||||
pax\fR). This option is equivalent to the \fB\-o\fR option of the
|
||||
.BR pax (1) utility.
|
||||
.BR pax (1)
|
||||
utility.
|
||||
.TP
|
||||
\fB\-\-posix\fR
|
||||
Same as \fB\-\-format=posix\fR.
|
||||
@@ -825,6 +832,10 @@ Filter the archive through
|
||||
\fB\-Z\fR, \fB\-\-compress\fR, \fB\-\-uncompress\fR
|
||||
Filter the archive through
|
||||
.BR compress (1).
|
||||
.TP
|
||||
\fB\-\-zstd\fR
|
||||
Filter the archive through
|
||||
.BR zstd (1).
|
||||
.SS Local file selection
|
||||
.TP
|
||||
\fB\-\-add\-file\fR=\fIFILE\fR
|
||||
@@ -953,7 +964,7 @@ See also \fB\-\-verbatim\-files\-from\fR.
|
||||
.TP
|
||||
\fB\-N\fR, \fB\-\-newer\fR=\fIDATE\fR, \fB\-\-after\-date\fR=\fIDATE\fR
|
||||
Only store files newer than DATE. If \fIDATE\fR starts with \fB/\fR
|
||||
or \fB.\fR it is taken to be a file name; the ctime of that file is
|
||||
or \fB.\fR it is taken to be a file name; the mtime of that file is
|
||||
used as the date.
|
||||
.TP
|
||||
\fB\-\-one\-file\-system\fR
|
||||
@@ -1096,7 +1107,7 @@ Show file or archive names after transformation by \fB\-\-strip\fR and
|
||||
Print total bytes after processing the archive. If \fISIGNAL\fR is
|
||||
given, print total bytes when this signal is delivered. Allowed
|
||||
signals are:
|
||||
.BR SIGHUP ,
|
||||
.BR SIGHUP ,
|
||||
.BR SIGQUIT ,
|
||||
.BR SIGINT ,
|
||||
.BR SIGUSR1 ", and"
|
||||
@@ -1107,7 +1118,11 @@ The \fBSIG\fR prefix can be omitted.
|
||||
Print file modification times in UTC.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Verbosely list files processed.
|
||||
Verbosely list files processed. Each instance of this option on the
|
||||
command line increases the verbosity level by one. The maximum
|
||||
verbosity level is 3. For a detailed discussion of how various
|
||||
verbosity levels affect tar's output, please refer to \fBGNU Tar
|
||||
Manual\fR, subsection 2.5.1 "\fBThe \-\-verbose Option\fR".
|
||||
.TP
|
||||
\fB\-\-warning\fR=\fIKEYWORD\fR
|
||||
Enable or disable warning messages identified by \fIKEYWORD\fR. The
|
||||
@@ -1160,6 +1175,12 @@ Keywords applicable for \fBtar --create\fR:
|
||||
.TP
|
||||
.B file-changed
|
||||
"%s: file changed as we read it"
|
||||
.TP
|
||||
.B failed-read
|
||||
Suppresses warnings about unreadable files or directories. This
|
||||
keyword applies only if used together with the
|
||||
.B \-\-ignore\-failed\-read
|
||||
option.
|
||||
.HP
|
||||
Keywords applicable for \fBtar --extract\fR:
|
||||
.TP
|
||||
@@ -1193,7 +1214,7 @@ default (unless \fB\-\-verbose\fR is used). A common example of what
|
||||
you can get when using this warning is:
|
||||
|
||||
.EX
|
||||
$ \fBtar --warning=decompress-program -x -f archive.Z
|
||||
$ tar --warning=decompress-program -x -f archive.Z
|
||||
tar (child): cannot run compress: No such file or directory
|
||||
tar (child): trying gzip
|
||||
.EE
|
||||
@@ -1284,8 +1305,8 @@ failure during backup to a remote device.
|
||||
.BR lzop (1),
|
||||
.BR rmt (8),
|
||||
.BR symlink (7),
|
||||
.BR tar (5),
|
||||
.BR xz (1).
|
||||
.BR xz (1),
|
||||
.BR zstd (1).
|
||||
.PP
|
||||
Complete \fBtar\fR manual: run
|
||||
.B info tar
|
||||
@@ -1301,7 +1322,7 @@ found at:
|
||||
.SH "BUG REPORTS"
|
||||
Report bugs to <bug\-tar@gnu.org>.
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2013 Free Software Foundation, Inc.
|
||||
Copyright \(co 2013-2019 Free Software Foundation, Inc.
|
||||
.br
|
||||
.na
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
||||
@@ -1316,4 +1337,3 @@ There is NO WARRANTY, to the extent permitted by law.
|
||||
.\" time-stamp-end: "\""
|
||||
.\" time-stamp-line-limit: 20
|
||||
.\" end:
|
||||
|
||||
|
||||
315
doc/tar.texi
315
doc/tar.texi
@@ -36,8 +36,8 @@ This manual is for @acronym{GNU} @command{tar} (version
|
||||
@value{VERSION}, @value{UPDATED}), which creates and extracts files
|
||||
from archives.
|
||||
|
||||
Copyright @copyright{} 1992, 1994--1997, 1999--2001, 2003--2016 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright @copyright{} 1992, 1994--1997, 1999--2001, 2003--2017, 2021
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
@quotation
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
@@ -111,11 +111,11 @@ document. The rest of the menu lists all the lower level nodes.
|
||||
Appendices
|
||||
|
||||
* Changes::
|
||||
* Recipes:: Frequently used tar recipes
|
||||
* Configuring Help Summary::
|
||||
* Fixing Snapshot Files::
|
||||
* Tar Internals::
|
||||
* Genfile::
|
||||
* Free Software Needs Free Documentation::
|
||||
* GNU Free Documentation License::
|
||||
* Index of Command Line Options::
|
||||
* Index::
|
||||
@@ -204,7 +204,6 @@ All @command{tar} Options
|
||||
* create options::
|
||||
* extract options::
|
||||
* backup::
|
||||
* Applications::
|
||||
* looking ahead::
|
||||
|
||||
Advanced @GNUTAR{} Operations
|
||||
@@ -1464,7 +1463,7 @@ tar: Removing leading '/' from member names
|
||||
/home/myself/practice/folk
|
||||
/home/myself/practice/jazz
|
||||
/home/myself/practice/collection.tar
|
||||
$ @kbd{tar --test --file practice.tar}
|
||||
$ @kbd{tar --list --file practice.tar}
|
||||
home/myself/practice/
|
||||
home/myself/practice/blues
|
||||
home/myself/practice/folk
|
||||
@@ -1495,7 +1494,7 @@ home/myself/practice/blues
|
||||
home/myself/practice/folk
|
||||
home/myself/practice/jazz
|
||||
home/myself/practice/collection.tar
|
||||
$ @kbd{tar --test --file practice.tar}
|
||||
$ @kbd{tar --list --file practice.tar}
|
||||
home/myself/practice/
|
||||
home/myself/practice/blues
|
||||
home/myself/practice/folk
|
||||
@@ -1521,7 +1520,7 @@ the error message is produced because there is no member named
|
||||
@file{folk}, only one named @file{home/myself/folk}.
|
||||
|
||||
If you are not sure of the exact file name, use @dfn{globbing
|
||||
patterns}, for example:
|
||||
patterns}, for example:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --list --file=practice.tar --wildcards '*/folk'}
|
||||
@@ -2553,6 +2552,12 @@ Wait for @var{time} seconds.
|
||||
|
||||
@item ttyout=@var{string}
|
||||
Output @var{string} on the current console (@file{/dev/tty}).
|
||||
|
||||
@item totals
|
||||
Print statistics (see @pxref{totals}).
|
||||
|
||||
@item wait=@var{signo}
|
||||
Wait for signal @var{signo}.
|
||||
@end table
|
||||
|
||||
Several @option{--checkpoint-action} options can be specified. The
|
||||
@@ -3155,7 +3160,7 @@ Disable extended attributes support. @xref{Extended File Attributes, xattrs}.
|
||||
|
||||
When @command{tar} is using the @option{--files-from} option, this option
|
||||
instructs @command{tar} to expect file names terminated with
|
||||
@acronym{NUL}, and to process file names verbatim.
|
||||
@acronym{NUL}, and to process file names verbatim.
|
||||
|
||||
This means that @command{tar} correctly works with file names that
|
||||
contain newlines or begin with a dash.
|
||||
@@ -3703,8 +3708,8 @@ Specify exclude pattern for xattr keys.
|
||||
|
||||
@opsummary{xattrs-include}
|
||||
@item --xattrs-include=@var{pattern}.
|
||||
Specify include pattern for xattr keys. @var{pattern} is a POSIX
|
||||
regular expression, e.g. @samp{--xattrs-exclude='^user\.'} to include
|
||||
Specify include pattern for xattr keys. @var{pattern} is a globbing
|
||||
pattern, e.g. @samp{--xattrs-include='user.*'} to include
|
||||
only attributes from the user namespace.
|
||||
@xref{Extended File Attributes, xattrs-include}.
|
||||
|
||||
@@ -3713,6 +3718,9 @@ only attributes from the user namespace.
|
||||
@itemx -J
|
||||
Use @command{xz} for compressing or decompressing the archives. @xref{gzip}.
|
||||
|
||||
@item --zstd
|
||||
Use @command{zstd} for compressing or decompressing the archives. @xref{gzip}.
|
||||
|
||||
@end table
|
||||
|
||||
@node Short Option Summary
|
||||
@@ -3786,8 +3794,8 @@ them with the equivalent long option.
|
||||
|
||||
@item -m @tab @ref{--touch}.
|
||||
|
||||
@item -o @tab When creating, @ref{--no-same-owner}, when extracting ---
|
||||
@ref{--portability}.
|
||||
@item -o @tab When extracting, same as @ref{--no-same-owner}. When creating,
|
||||
-- @ref{--old-archive}.
|
||||
|
||||
The latter usage is deprecated. It is retained for compatibility with
|
||||
the earlier versions of @GNUTAR{}. In future releases
|
||||
@@ -3879,7 +3887,24 @@ tar -cf a.tar /usr --no-recursion /var/*
|
||||
tar -cf a.tar --recursion /usr --no-recursion /var/*
|
||||
@end example
|
||||
|
||||
The following table summarizes all position-sensitive options.
|
||||
During archive creation, @GNUTAR{} keeps track of positional options
|
||||
used and arguments affected by them. If it finds out that any such
|
||||
options are used in an obviously erroneous way, the fact is reported
|
||||
and exit code is set to 2. E.g.:
|
||||
|
||||
@example
|
||||
@group
|
||||
$ @kbd{tar -cf a.tar . --exclude '*.o'}
|
||||
tar: The following options were used after any non-optional
|
||||
arguments in archive create or update mode. These options are
|
||||
positional and affect only arguments that follow them. Please,
|
||||
rearrange them properly.
|
||||
tar: --exclude '*.o' has no effect
|
||||
tar: Exiting with failure status due to previous errors
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The following table summarizes all position-sensitive options.
|
||||
|
||||
@table @option
|
||||
@item --directory=@var{dir}
|
||||
@@ -3898,24 +3923,24 @@ The following table summarizes all position-sensitive options.
|
||||
@itemx --no-verbatim-files-from
|
||||
@xref{verbatim-files-from}.
|
||||
|
||||
@item --recursion
|
||||
@item --recursion
|
||||
@itemx --no-recursion
|
||||
@xref{recurse}.
|
||||
|
||||
@item --anchored
|
||||
@itemx --no-anchored
|
||||
@item --anchored
|
||||
@itemx --no-anchored
|
||||
@xref{anchored patterns}.
|
||||
|
||||
@item --ignore-case
|
||||
@itemx --no-ignore-case
|
||||
@item --ignore-case
|
||||
@itemx --no-ignore-case
|
||||
@xref{case-insensitive matches}.
|
||||
|
||||
@item --wildcards
|
||||
@itemx --no-wildcards
|
||||
@xref{controlling pattern-matching}.
|
||||
|
||||
@item --wildcards-match-slash
|
||||
@itemx --no-wildcards-match-slash
|
||||
@item --wildcards-match-slash
|
||||
@itemx --no-wildcards-match-slash
|
||||
@xref{controlling pattern-matching}.
|
||||
|
||||
@item --exclude
|
||||
@@ -3951,7 +3976,7 @@ successfully. For example, @w{@samp{tar --version}} might print:
|
||||
|
||||
@smallexample
|
||||
tar (GNU tar) @value{VERSION}
|
||||
Copyright (C) 2013-2016 Free Software Foundation, Inc.
|
||||
Copyright (C) 2013-2020 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
@@ -4432,6 +4457,25 @@ checkpoint:
|
||||
$ @kbd{tar -c --checkpoint=1000 --checkpoint-action=sleep=30}
|
||||
@end smallexample
|
||||
|
||||
@anchor{checkpoint wait}
|
||||
@cindex @code{wait}, checkpoint action
|
||||
The @code{wait=@var{signo}} action stops further execution until the
|
||||
signal @var{signo} is delivered. Valid values for @var{signo} are:
|
||||
@code{SIGHUP}, @code{SIGQUIT}, @code{SIGINT}, @code{SIGUSR1} and
|
||||
@code{SIGUSR2}. The @samp{SIG} prefix is optional. For example:
|
||||
|
||||
@example
|
||||
$ @kbd{tar -c -f arc --checkpoint=1000 --checkpoint-action wait=USR1 .}
|
||||
@end example
|
||||
|
||||
In this example, @GNUTAR{} will stop archivation at each 1000th
|
||||
checkpoint. wait until the @samp{SIGUSR1} signal is delivered,
|
||||
and resume processing.
|
||||
|
||||
This action is used by the @command{genfile} utility to perform
|
||||
modifications on the input files upon hitting certain checkpoints
|
||||
(@pxref{Exec Mode, genfile}).
|
||||
|
||||
@anchor{checkpoint exec}
|
||||
@cindex @code{exec}, checkpoint action
|
||||
Finally, the @code{exec} action executes a given external command.
|
||||
@@ -4593,6 +4637,10 @@ Disable all warning messages.
|
||||
@cindex @samp{file changed as we read it}, warning message
|
||||
@item file-changed
|
||||
@samp{%s: file changed as we read it}
|
||||
@item failed-read
|
||||
Suppresses warnings about unreadable files or directories. This
|
||||
keyword applies only if used together with the @option{--ignore-failed-read}
|
||||
option. @xref{Ignore Failed Read}.
|
||||
@end table
|
||||
|
||||
@subheading Keywords applicable for @command{tar --extract}
|
||||
@@ -4756,7 +4804,6 @@ expanded by the shell when invoking @command{tar}.
|
||||
* create options::
|
||||
* extract options::
|
||||
* backup::
|
||||
* Applications::
|
||||
* looking ahead::
|
||||
@end menu
|
||||
|
||||
@@ -5174,7 +5221,7 @@ the one at the end will be newer and larger, since you added text before
|
||||
updating it.
|
||||
|
||||
The reason @command{tar} does not overwrite the older file when updating
|
||||
it is because writing to the middle of a section of tape is a difficult
|
||||
it is that writing to the middle of a section of tape is a difficult
|
||||
process. Tapes are not designed to go backward. @xref{Media}, for more
|
||||
information about tapes.
|
||||
|
||||
@@ -5457,7 +5504,7 @@ reproducible archives given a common timestamp for generated files
|
||||
while still retaining the original timestamps of untouched files.
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar -c -f archive.tar --clamp-mtime --mtime=@atchar{}$SOURCE_DATE_EPOCH .}
|
||||
$ @kbd{tar -c -f archive.tar --clamp-mtime --mtime=@@$SOURCE_DATE_EPOCH .}
|
||||
@end smallexample
|
||||
|
||||
@item --owner=@var{user}
|
||||
@@ -5576,7 +5623,7 @@ map file.
|
||||
@subsection Extended File Attributes
|
||||
|
||||
Extended file attributes are name-value pairs that can be
|
||||
associated with each node in a file system. Despite the fact that
|
||||
associated with each node in a file system. Despite the fact that
|
||||
POSIX.1e draft which proposed them has been withdrawn, the extended
|
||||
file attributes are supported by many file systems. @GNUTAR{} can
|
||||
store extended file attributes along with the files. This feature is
|
||||
@@ -5612,11 +5659,11 @@ Specify exclude pattern for extended attributes.
|
||||
Specify include pattern for extended attributes.
|
||||
@end table
|
||||
|
||||
Here, the @var{pattern} is POSIX regular expression. For example, the
|
||||
Here, the @var{pattern} is a globbing pattern. For example, the
|
||||
following command:
|
||||
|
||||
@example
|
||||
$ @kbd{tar --xattrs --xattrs-exclude='^user\.' -c a.tar .}
|
||||
$ @kbd{tar --xattrs --xattrs-exclude='user.*' -c a.tar .}
|
||||
@end example
|
||||
|
||||
will include in the archive @file{a.tar} all attributes, except those
|
||||
@@ -5625,11 +5672,11 @@ from the @samp{user} namespace.
|
||||
Any number of these options can be given, thereby creating lists of
|
||||
include and exclude patterns.
|
||||
|
||||
When both options are used, first @option{--xattrs-inlcude} is applied
|
||||
When both options are used, first @option{--xattrs-include} is applied
|
||||
to select the set of attribute names to keep, and then
|
||||
@option{--xattrs-exclude} is applied to the resulting set. In other
|
||||
words, only those attributes will be stored, whose names match one
|
||||
of the regexps in @option{--xattrs-inlcude} and don't match any of
|
||||
of the regexps in @option{--xattrs-include} and don't match any of
|
||||
the regexps from @option{--xattrs-exclude}.
|
||||
|
||||
When listing the archive, if both @option{--xattrs} and
|
||||
@@ -5678,7 +5725,7 @@ Disable POSIX ACLs support. This is the default.
|
||||
|
||||
When listing the archive, if both @option{--acls} and
|
||||
@option{--verbose} options are given, files that have ACLs are marked
|
||||
with a plus sing following their permission mask. For example:
|
||||
with a plus sign following their permission mask. For example:
|
||||
|
||||
@example
|
||||
-rw-r--r--+ smith/users 110 2016-03-16 16:07 file
|
||||
@@ -5691,7 +5738,7 @@ listing of ACL is printed after each file entry:
|
||||
@group
|
||||
-rw-r--r--+ smith/users 110 2016-03-16 16:07 file
|
||||
a: user::rw-,user:gray:-w-,group::r--,mask::rw-,other::r--
|
||||
@end group
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@dfn{Security-Enhanced Linux} (@dfn{SELinux} for short) is a Linux
|
||||
@@ -5709,7 +5756,7 @@ Disable SELinux context support.
|
||||
@end table
|
||||
|
||||
@node Ignore Failed Read
|
||||
@subsection Ignore Fail Read
|
||||
@subsection Ignore Failed Read
|
||||
|
||||
@table @option
|
||||
@item --ignore-failed-read
|
||||
@@ -5717,6 +5764,13 @@ Disable SELinux context support.
|
||||
Do not exit with nonzero on unreadable files or directories.
|
||||
@end table
|
||||
|
||||
This option has effect only during creation. It instructs tar to
|
||||
treat as mild conditions any missing or unreadable files (directories).
|
||||
Such failures don't affect the program exit code, and the
|
||||
corresponding diagnostic messages are marked as warnings, not errors.
|
||||
These warnings can be suppressed using the
|
||||
@option{--warning=failed-read} option (@pxref{warnings}).
|
||||
|
||||
@node extract options
|
||||
@section Options Used by @option{--extract}
|
||||
@cindex options for use with @option{--extract}
|
||||
@@ -6473,65 +6527,6 @@ set, the default is @samp{~}, just as in Emacs.
|
||||
|
||||
@end table
|
||||
|
||||
@node Applications
|
||||
@section Notable @command{tar} Usages
|
||||
@UNREVISED
|
||||
|
||||
@FIXME{Using Unix file linking capability to recreate directory
|
||||
structures---linking files into one subdirectory and then
|
||||
@command{tar}ring that directory.}
|
||||
|
||||
@FIXME{Nice hairy example using absolute-names, newer, etc.}
|
||||
|
||||
@findex uuencode
|
||||
You can easily use archive files to transport a group of files from
|
||||
one system to another: put all relevant files into an archive on one
|
||||
computer system, transfer the archive to another system, and extract
|
||||
the contents there. The basic transfer medium might be magnetic tape,
|
||||
Internet FTP, or even electronic mail (though you must encode the
|
||||
archive with @command{uuencode} in order to transport it properly by
|
||||
mail). Both machines do not have to use the same operating system, as
|
||||
long as they both support the @command{tar} program.
|
||||
|
||||
For example, here is how you might copy a directory's contents from
|
||||
one disk to another, while preserving the dates, modes, owners and
|
||||
link-structure of all the files therein. In this case, the transfer
|
||||
medium is a @dfn{pipe}:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{(cd sourcedir; tar -cf - .) | (cd targetdir; tar -xf -)}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
You can avoid subshells by using @option{-C} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar -C sourcedir -cf - . | tar -C targetdir -xf -}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
The command also works using long option forms:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{(cd sourcedir; tar --create --file=- . ) \
|
||||
| (cd targetdir; tar --extract --file=-)}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
or
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{tar --directory sourcedir --create --file=- . \
|
||||
| tar --directory targetdir --extract --file=-}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
This is one of the easiest methods to transfer a @command{tar} archive.
|
||||
|
||||
@node looking ahead
|
||||
@section Looking Ahead: The Rest of this Manual
|
||||
|
||||
@@ -7735,9 +7730,12 @@ any leading and trailing whitespace. If the resulting string begins
|
||||
with @samp{-} character, it is considered a @command{tar} option and is
|
||||
processed accordingly@footnote{Versions of @GNUTAR{} up to 1.15.1
|
||||
recognized only @option{-C} option in file lists, and only if the
|
||||
option and its argument occupied two consecutive lines.}. For example,
|
||||
the common use of this feature is to change to another directory by
|
||||
specifying @option{-C} option:
|
||||
option and its argument occupied two consecutive lines.}. Only a
|
||||
subset of @GNUTAR{} options is allowed for use in file lists. For
|
||||
a list of such options, @ref{Position-Sensitive Options}.
|
||||
|
||||
For example, the common use of this feature is to change to another
|
||||
directory by specifying @option{-C} option:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -8474,9 +8472,7 @@ quoting}. The characters in question are:
|
||||
The exact way @command{tar} uses to quote these characters depends on
|
||||
the @dfn{quoting style}. The default quoting style, called
|
||||
@dfn{escape} (see below), uses backslash notation to represent control
|
||||
characters, space and backslash. Using this quoting style, control
|
||||
characters are represented as listed in column @samp{Character} in the
|
||||
above table, a space is printed as @samp{\ } and a backslash as @samp{\\}.
|
||||
characters and backslash.
|
||||
|
||||
@GNUTAR{} offers seven distinct quoting styles, which can be selected
|
||||
using @option{--quoting-style} option:
|
||||
@@ -8607,10 +8603,9 @@ $ @kbd{tar tf arch.tar --quoting-style=c}
|
||||
@end smallexample
|
||||
|
||||
@item escape
|
||||
Control characters are printed using backslash notation, a space is
|
||||
printed as @samp{\ } and a backslash as @samp{\\}. This is the
|
||||
default quoting style, unless it was changed when configured the
|
||||
package.
|
||||
Control characters are printed using backslash notation, and a
|
||||
backslash as @samp{\\}. This is the default quoting style, unless it
|
||||
was changed when configured the package.
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -8964,7 +8959,7 @@ is used, which excludes symbolic link targets from filename
|
||||
transformations. The result is:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --transform 's,^,/usr/local/,S', -c -v -f arch.tar \
|
||||
$ @kbd{tar --transform 's,^,/usr/local/,S' -c -v -f arch.tar \
|
||||
--show-transformed /lib}
|
||||
drwxr-xr-x root/root 0 2008-07-08 16:20 /usr/local/lib/
|
||||
-rwxr-xr-x root/root 1250840 2008-05-25 07:44 /usr/local/lib/libc-2.3.2.so
|
||||
@@ -9157,7 +9152,7 @@ create a list of files to be stored in an archive, use it as follows:
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{find @var{dir} @var{tests} | \
|
||||
tar -cf @var{archive} -T - --no-recursion}
|
||||
tar -cf @var{archive} --no-recursion -T -}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@@ -9555,24 +9550,32 @@ switch to @samp{posix}.
|
||||
@cindex lzma
|
||||
@cindex lzop
|
||||
@cindex compress
|
||||
@cindex zstd
|
||||
@GNUTAR{} is able to create and read compressed archives. It supports
|
||||
a wide variety of compression programs, namely: @command{gzip},
|
||||
@command{bzip2}, @command{lzip}, @command{lzma}, @command{lzop},
|
||||
@command{xz} and traditional @command{compress}. The latter is
|
||||
supported mostly for backward compatibility, and we recommend
|
||||
@command{zstd}, @command{xz} and traditional @command{compress}. The
|
||||
latter is supported mostly for backward compatibility, and we recommend
|
||||
against using it, because it is by far less effective than the other
|
||||
compression programs@footnote{It also had patent problems in the past.}.
|
||||
|
||||
Creating a compressed archive is simple: you just specify a
|
||||
@dfn{compression option} along with the usual archive creation
|
||||
commands. The compression option is @option{-z} (@option{--gzip}) to
|
||||
create a @command{gzip} compressed archive, @option{-j}
|
||||
(@option{--bzip2}) to create a @command{bzip2} compressed archive,
|
||||
@option{--lzip} to create an @asis{lzip} compressed archive,
|
||||
@option{-J} (@option{--xz}) to create an @asis{XZ} archive,
|
||||
@option{--lzma} to create an @asis{LZMA} compressed
|
||||
archive, @option{--lzop} to create an @asis{LSOP} archive, and
|
||||
@option{-Z} (@option{--compress}) to use @command{compress} program.
|
||||
commands. Available compression options are summarized in the
|
||||
table below:
|
||||
|
||||
@multitable @columnfractions 0.4 0.2 0.4
|
||||
@headitem Long @tab Short @tab Archive format
|
||||
@item @option{--gzip} @tab @option{-z} @tab @command{gzip}
|
||||
@item @option{--bzip2} @tab @option{-j} @tab @command{bzip2}
|
||||
@item @option{--xz} @tab @option{-J} @tab @command{xz}
|
||||
@item @option{--lzip} @tab @tab @command{lzip}
|
||||
@item @option{--lzma} @tab @tab @command{lzma}
|
||||
@item @option{--lzop} @tab @tab @command{lzop}
|
||||
@item @option{--zstd} @tab @tab @command{zstd}
|
||||
@item @option{--compress} @tab @option{-Z} @tab @command{compress}
|
||||
@end multitable
|
||||
|
||||
For example:
|
||||
|
||||
@smallexample
|
||||
@@ -9693,6 +9696,10 @@ Filter the archive through @command{lzma}.
|
||||
@item --lzop
|
||||
Filter the archive through @command{lzop}.
|
||||
|
||||
@opindex zstd
|
||||
@item --zstd
|
||||
Filter the archive through @command{zstd}.
|
||||
|
||||
@opindex compress
|
||||
@opindex uncompress
|
||||
@item -Z
|
||||
@@ -9765,6 +9772,8 @@ suffix. The following suffixes are recognized:
|
||||
@item @samp{.tlz} @tab @command{lzma}
|
||||
@item @samp{.lzo} @tab @command{lzop}
|
||||
@item @samp{.xz} @tab @command{xz}
|
||||
@item @samp{.zst} @tab @command{zstd}
|
||||
@item @samp{.tzst} @tab @command{zstd}
|
||||
@end multitable
|
||||
|
||||
@anchor{use-compress-program}
|
||||
@@ -10451,9 +10460,16 @@ If no option @samp{exthdr.name=string} is specified, @command{tar}
|
||||
will use the following default value:
|
||||
|
||||
@smallexample
|
||||
%d/PaxHeaders.%p/%f
|
||||
%d/PaxHeaders/%f
|
||||
@end smallexample
|
||||
|
||||
This default is selected to ensure the reproducibility of the
|
||||
archive. @acronym{POSIX} standard recommends to use
|
||||
@samp{%d/PaxHeaders.%p/%f} instead, which means the two archives
|
||||
created with the same set of options and containing the same set
|
||||
of files will be byte-to-byte different. This default will be used
|
||||
if the environment variable @env{POSIXLY_CORRECT} is set.
|
||||
|
||||
@item exthdr.mtime=@var{value}
|
||||
|
||||
This keyword defines the value of the @samp{mtime} field that
|
||||
@@ -10482,12 +10498,18 @@ Any other @samp{%} characters in @var{string} produce undefined results.
|
||||
If no option @samp{globexthdr.name=string} is specified, @command{tar}
|
||||
will use the following default value:
|
||||
|
||||
@smallexample
|
||||
$TMPDIR/GlobalHead.%n
|
||||
@end smallexample
|
||||
|
||||
If the environment variable @env{POSIXLY_CORRECT} is set, the
|
||||
following value is used instead:
|
||||
|
||||
@smallexample
|
||||
$TMPDIR/GlobalHead.%p.%n
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
where @samp{$TMPDIR} represents the value of the @var{TMPDIR}
|
||||
In both cases, @samp{$TMPDIR} stands for the value of the @var{TMPDIR}
|
||||
environment variable. If @var{TMPDIR} is not set, @command{tar}
|
||||
uses @samp{/tmp}.
|
||||
|
||||
@@ -10550,7 +10572,7 @@ archives created using it, will be binary equivalent if they have the
|
||||
same contents:
|
||||
|
||||
@smallexample
|
||||
--pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0
|
||||
--pax-option=atime:=0
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
@@ -10559,14 +10581,27 @@ from them, you will also need to eliminate changes due to ctime, as
|
||||
shown in examples below:
|
||||
|
||||
@smallexample
|
||||
--pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0,ctime:=0
|
||||
--pax-option=atime:=0,ctime:=0
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
or
|
||||
|
||||
@smallexample
|
||||
--pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0,delete=ctime
|
||||
--pax-option=atime:=0,delete=ctime
|
||||
@end smallexample
|
||||
|
||||
Notice, that if you create an archive in POSIX format (@pxref{posix})
|
||||
and the environment variable @env{POSIXLY_CORRECT} is set, then the
|
||||
two archives created using the same options on the same set of files
|
||||
will not be byte-to-byte equivalent even with the above option. This
|
||||
is because the posix default for extended header names includes the
|
||||
PID of the tar process, which is different at each run. To produce
|
||||
byte-to-byte equivalent archives in this case, either unset
|
||||
@env{POSIXLY_CORRECT}, or use the following option:
|
||||
|
||||
@smallexample
|
||||
---pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0,ctime:=0
|
||||
@end smallexample
|
||||
|
||||
@node Checksumming
|
||||
@@ -10692,7 +10727,7 @@ GNU extensions. More specifically, the very first part retains its
|
||||
original name, and all subsequent parts are named using the pattern:
|
||||
|
||||
@smallexample
|
||||
%d/GNUFileParts.%p/%f.%n
|
||||
%d/GNUFileParts/%f.%n
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
@@ -10711,13 +10746,12 @@ created the archive.
|
||||
@end multitable
|
||||
|
||||
For example, if the file @file{var/longfile} was split during archive
|
||||
creation between three volumes, and the creator @command{tar} process
|
||||
had process @acronym{ID} @samp{27962}, then the member names will be:
|
||||
creation between three volumes, then the member names will be:
|
||||
|
||||
@smallexample
|
||||
var/longfile
|
||||
var/GNUFileParts.27962/longfile.1
|
||||
var/GNUFileParts.27962/longfile.2
|
||||
var/GNUFileParts/longfile.1
|
||||
var/GNUFileParts/longfile.2
|
||||
@end smallexample
|
||||
|
||||
When you extract your archive using a third-party @command{tar}, these
|
||||
@@ -10728,9 +10762,9 @@ the proper order, for example:
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{cd var}
|
||||
$ @kbd{cat GNUFileParts.27962/longfile.1 \
|
||||
GNUFileParts.27962/longfile.2 >> longfile}
|
||||
$ rm -f GNUFileParts.27962
|
||||
$ @kbd{cat GNUFileParts/longfile.1 \
|
||||
GNUFileParts/longfile.2 >> longfile}
|
||||
$ rm -f GNUFileParts
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@@ -10756,12 +10790,12 @@ more warnings and more files generated on your disk, e.g.:
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{tar xf vol-1.tar}
|
||||
var/PaxHeaders.27962/longfile: Unknown file type 'x', extracted as
|
||||
var/PaxHeaders/longfile: Unknown file type 'x', extracted as
|
||||
normal file
|
||||
Unexpected EOF in archive
|
||||
$ @kbd{tar xf vol-2.tar}
|
||||
tmp/GlobalHead.27962.1: Unknown file type 'g', extracted as normal file
|
||||
GNUFileParts.27962/PaxHeaders.27962/sparsefile.1: Unknown file type
|
||||
tmp/GlobalHead.1: Unknown file type 'g', extracted as normal file
|
||||
GNUFileParts/PaxHeaders/sparsefile.1: Unknown file type
|
||||
'x', extracted as normal file
|
||||
@end group
|
||||
@end smallexample
|
||||
@@ -10877,8 +10911,8 @@ use. Continuing our example:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{xsparse -v -x /home/gray/PaxHeaders.6058/sparsefile \
|
||||
/home/gray/GNUSparseFile.6058/sparsefile}
|
||||
$ @kbd{xsparse -v -x /home/gray/PaxHeaders/sparsefile \
|
||||
/home/gray/GNUSparseFile/sparsefile}
|
||||
Reading extended header file
|
||||
Found variable GNU.sparse.major = 1
|
||||
Found variable GNU.sparse.minor = 0
|
||||
@@ -10891,7 +10925,7 @@ Done
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@anchor{extracting sparse v.0.x}
|
||||
@anchor{extracting sparse v0x}
|
||||
@cindex sparse files v.0.1, extracting with non-GNU tars
|
||||
@cindex sparse files v.0.0, extracting with non-GNU tars
|
||||
An @dfn{extended header} is a special @command{tar} archive header
|
||||
@@ -10908,8 +10942,7 @@ If you use a @command{tar} implementation that does not support PAX
|
||||
format, extended headers for each member will be extracted as a
|
||||
separate file. If we represent the member name as
|
||||
@file{@var{dir}/@var{name}}, then the extended header file will be
|
||||
named @file{@var{dir}/@/PaxHeaders.@var{n}/@/@var{name}}, where
|
||||
@var{n} is an integer number.
|
||||
named @file{@var{dir}/@/PaxHeaders/@/@var{name}}.
|
||||
|
||||
Things become more difficult if your @command{tar} implementation
|
||||
does support PAX headers, because in this case you will have to
|
||||
@@ -12907,8 +12940,8 @@ understand their security implications.
|
||||
@appendix Changes
|
||||
|
||||
This appendix lists some important user-visible changes between
|
||||
version @GNUTAR{} @value{VERSION} and previous versions. An up-to-date
|
||||
version of this document is available at
|
||||
various versions of @GNUTAR{}. An up-to-date version of this document
|
||||
is available at
|
||||
@uref{http://www.gnu.org/@/software/@/tar/manual/changes.html,the
|
||||
@GNUTAR{} documentation page}.
|
||||
|
||||
@@ -12994,6 +13027,10 @@ These options are deprecated. Please use @option{--format=v7} instead.
|
||||
This option is deprecated. Please use @option{--format=posix} instead.
|
||||
@end table
|
||||
|
||||
@node Recipes
|
||||
@appendix Recipes
|
||||
@include recipes.texi
|
||||
|
||||
@node Configuring Help Summary
|
||||
@appendix Configuring Help Summary
|
||||
|
||||
@@ -13219,10 +13256,6 @@ Right margin of the text output. Used for wrapping.
|
||||
@appendix Genfile
|
||||
@include genfile.texi
|
||||
|
||||
@node Free Software Needs Free Documentation
|
||||
@appendix Free Software Needs Free Documentation
|
||||
@include freemanuals.texi
|
||||
|
||||
@node GNU Free Documentation License
|
||||
@appendix GNU Free Documentation License
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2006-2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright 1992, 1994-1997, 1999-2006, 2013-2014, 2016 Free Software
|
||||
@c Foundation, Inc.
|
||||
@c Copyright 1992--2021 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
|
||||
2
gnulib
2
gnulib
Submodule gnulib updated: 1029a81122...30820c2d7c
@@ -1,7 +1,7 @@
|
||||
# List of gnulib modules needed for GNU tar.
|
||||
# A module name per line. Empty lines and comments are ignored.
|
||||
|
||||
# Copyright 2005-2010, 2012-2014 Free Software Foundation, Inc.
|
||||
# Copyright 2005-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -83,8 +83,10 @@ stat-time
|
||||
stdbool
|
||||
stdint
|
||||
stpcpy
|
||||
stdopen
|
||||
strdup-posix
|
||||
strerror
|
||||
strnlen
|
||||
strtoimax
|
||||
strtol
|
||||
strtoul
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Makefile for GNU tar library. -*- Makefile -*-
|
||||
|
||||
# Copyright 1994-1997, 1999-2001, 2003-2007, 2009-2010, 2013-2014, 2016
|
||||
# Free Software Foundation, Inc.
|
||||
# Copyright 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -33,7 +32,6 @@ AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
noinst_HEADERS = \
|
||||
paxlib.h\
|
||||
rmt.h\
|
||||
stdopen.h\
|
||||
system.h\
|
||||
system-ioctl.h\
|
||||
wordsplit.h\
|
||||
@@ -43,7 +41,6 @@ libtar_a_SOURCES = \
|
||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h \
|
||||
wordsplit.c\
|
||||
xattr-at.c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Replacement <attr/xattr.h> for platforms that lack it.
|
||||
Copyright 2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2012-2021 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
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/* stdopen.c - ensure that the three standard file descriptors are in use
|
||||
|
||||
Copyright 2005, 2007, 2013-2014, 2016 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 and Jim Meyering. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "stdopen.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Try to ensure that all of the standard file numbers (0, 1, 2)
|
||||
are in use. Without this, each application would have to guard
|
||||
every call to open, dup, fopen, etc. with tests to ensure they
|
||||
don't use one of the special file numbers when opening a file.
|
||||
Return false if at least one of the file descriptors is initially
|
||||
closed and an attempt to reopen it fails. Otherwise, return true. */
|
||||
bool
|
||||
stdopen (void)
|
||||
{
|
||||
int fd;
|
||||
bool ok = true;
|
||||
|
||||
for (fd = 0; fd <= 2; fd++)
|
||||
{
|
||||
if (fcntl (fd, F_GETFD) < 0)
|
||||
{
|
||||
if (errno != EBADF)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
static const int contrary_mode[]
|
||||
= { O_WRONLY, O_RDONLY, O_RDONLY };
|
||||
int mode = contrary_mode[fd];
|
||||
int new_fd;
|
||||
/* Open /dev/null with the contrary mode so that the typical
|
||||
read (stdin) or write (stdout, stderr) operation will fail.
|
||||
With descriptor 0, we can do even better on systems that
|
||||
have /dev/full, by opening that write-only instead of
|
||||
/dev/null. The only drawback is that a write-provoked
|
||||
failure comes with a misleading errno value, ENOSPC. */
|
||||
if (mode == O_RDONLY
|
||||
|| (new_fd = open ("/dev/full", mode) != fd))
|
||||
new_fd = open ("/dev/null", mode);
|
||||
if (new_fd != fd)
|
||||
{
|
||||
if (0 <= new_fd)
|
||||
close (new_fd);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef STDOPEN_H
|
||||
# define STDOPEN_H 1
|
||||
|
||||
# include <stdbool.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
bool stdopen (void);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
1698
lib/wordsplit.c
1698
lib/wordsplit.c
File diff suppressed because it is too large
Load Diff
219
lib/wordsplit.h
219
lib/wordsplit.h
@@ -1,5 +1,5 @@
|
||||
/* wordsplit - a word splitter
|
||||
Copyright (C) 2009-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright (C) 2009-2018 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
|
||||
@@ -12,10 +12,7 @@
|
||||
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 Sergey Poznyakoff
|
||||
*/
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef __WORDSPLIT_H
|
||||
#define __WORDSPLIT_H
|
||||
@@ -28,42 +25,106 @@
|
||||
# define __WORDSPLIT_ATTRIBUTE_FORMAT(spec) /* empty */
|
||||
#endif
|
||||
|
||||
struct wordsplit
|
||||
typedef struct wordsplit wordsplit_t;
|
||||
|
||||
/* Structure used to direct the splitting. Members marked with [Input]
|
||||
can be defined before calling wordsplit(), those marked with [Output]
|
||||
provide return values when the function returns. If neither mark is
|
||||
used, the member is internal and must not be used by the caller.
|
||||
|
||||
In the comments below, the identifiers in parentheses indicate bits that
|
||||
must be set (or unset, if starting with !) in ws_flags (if starting with
|
||||
WRDSF_) or ws_options (if starting with WRDSO_) to initialize or use the
|
||||
given member.
|
||||
|
||||
If not redefined explicitly, most of them are set to some reasonable
|
||||
default value upon entry to wordsplit(). */
|
||||
struct wordsplit
|
||||
{
|
||||
size_t ws_wordc;
|
||||
char **ws_wordv;
|
||||
size_t ws_offs;
|
||||
size_t ws_wordn;
|
||||
int ws_flags;
|
||||
const char *ws_delim;
|
||||
const char *ws_comment;
|
||||
const char *ws_escape;
|
||||
void (*ws_alloc_die) (struct wordsplit * wsp);
|
||||
size_t ws_wordc; /* [Output] Number of words in ws_wordv. */
|
||||
char **ws_wordv; /* [Output] Array of parsed out words. */
|
||||
size_t ws_offs; /* [Input] (WRDSF_DOOFFS) Number of initial
|
||||
elements in ws_wordv to fill with NULLs. */
|
||||
size_t ws_wordn; /* Number of elements ws_wordv can accomodate. */
|
||||
unsigned ws_flags; /* [Input] Flags passed to wordsplit. */
|
||||
unsigned ws_options; /* [Input] (WRDSF_OPTIONS)
|
||||
Additional options. */
|
||||
size_t ws_maxwords; /* [Input] (WRDSO_MAXWORDS) Return at most that
|
||||
many words */
|
||||
size_t ws_wordi; /* [Output] (WRDSF_INCREMENTAL) Total number of
|
||||
words returned so far */
|
||||
|
||||
const char *ws_delim; /* [Input] (WRDSF_DELIM) Word delimiters. */
|
||||
const char *ws_comment; /* [Input] (WRDSF_COMMENT) Comment characters. */
|
||||
const char *ws_escape[2]; /* [Input] (WRDSF_ESCAPE) Characters to be escaped
|
||||
with backslash. */
|
||||
void (*ws_alloc_die) (wordsplit_t *wsp);
|
||||
/* [Input] (WRDSF_ALLOC_DIE) Function called when
|
||||
out of memory. Must not return. */
|
||||
void (*ws_error) (const char *, ...)
|
||||
__WORDSPLIT_ATTRIBUTE_FORMAT ((__printf__, 1, 2));
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
/* [Input] (WRDSF_ERROR) Function used for error
|
||||
reporting */
|
||||
void (*ws_debug) (const char *, ...)
|
||||
__WORDSPLIT_ATTRIBUTE_FORMAT ((__printf__, 1, 2));
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
/* [Input] (WRDSF_DEBUG) Function used for debug
|
||||
output. */
|
||||
const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
|
||||
environment variables. */
|
||||
|
||||
const char **ws_env;
|
||||
const char *(*ws_getvar) (const char *, size_t, void *);
|
||||
void *ws_closure;
|
||||
char **ws_envbuf;
|
||||
size_t ws_envidx;
|
||||
size_t ws_envsiz;
|
||||
|
||||
int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos);
|
||||
/* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
|
||||
the name VAR (LEN bytes long) in the table of
|
||||
variables and if found returns in memory
|
||||
location pointed to by RET the value of that
|
||||
variable. Returns WRDSE_OK (0) on success,
|
||||
and an error code (see WRDSE_* defines below)
|
||||
on error. User-specific errors can be returned
|
||||
by storing the error diagnostic string in RET
|
||||
and returning WRDSE_USERERR.
|
||||
Whatever is stored in RET, it must be allocated
|
||||
using malloc(3). */
|
||||
void *ws_closure; /* [Input] (WRDSF_CLOSURE) Passed as the CLOS
|
||||
argument to ws_getvar and ws_command. */
|
||||
int (*ws_command) (char **ret, const char *cmd, size_t len, char **argv,
|
||||
void *clos);
|
||||
/* [Input] (!WRDSF_NOCMD) Returns in the memory
|
||||
location pointed to by RET the expansion of
|
||||
the command CMD (LEN bytes long). If WRDSO_ARGV
|
||||
option is set, ARGV contains CMD split out to
|
||||
words. Otherwise ARGV is NULL.
|
||||
|
||||
const char *ws_input;
|
||||
size_t ws_len;
|
||||
size_t ws_endp;
|
||||
int ws_errno;
|
||||
See ws_getvar for a discussion of possible
|
||||
return values. */
|
||||
|
||||
const char *ws_input; /* Input string (the S argument to wordsplit. */
|
||||
size_t ws_len; /* Length of ws_input. */
|
||||
size_t ws_endp; /* Points past the last processed byte in
|
||||
ws_input. */
|
||||
int ws_errno; /* [Output] Error code, if an error occurred. */
|
||||
char *ws_usererr; /* Points to textual description of
|
||||
the error, if ws_errno is WRDSE_USERERR. Must
|
||||
be allocated with malloc(3). */
|
||||
struct wordsplit_node *ws_head, *ws_tail;
|
||||
/* Doubly-linked list of parsed out nodes. */
|
||||
int ws_lvl; /* Invocation nesting level. */
|
||||
};
|
||||
|
||||
/* Wordsplit flags. Only 2 bits of a 32-bit word remain unused.
|
||||
It is getting crowded... */
|
||||
/* Initial size for ws_env, if allocated automatically */
|
||||
#define WORDSPLIT_ENV_INIT 16
|
||||
|
||||
/* Wordsplit flags. */
|
||||
/* Append the words found to the array resulting from a previous
|
||||
call. */
|
||||
#define WRDSF_APPEND 0x00000001
|
||||
/* Insert we_offs initial NULLs in the array ws_wordv.
|
||||
/* Insert ws_offs initial NULLs in the array ws_wordv.
|
||||
(These are not counted in the returned ws_wordc.) */
|
||||
#define WRDSF_DOOFFS 0x00000002
|
||||
/* Don't do command substitution. Reserved for future use. */
|
||||
/* Don't do command substitution. */
|
||||
#define WRDSF_NOCMD 0x00000004
|
||||
/* The parameter p resulted from a previous call to
|
||||
wordsplit(), and wordsplit_free() was not called. Reuse the
|
||||
@@ -71,10 +132,8 @@ struct wordsplit
|
||||
#define WRDSF_REUSE 0x00000008
|
||||
/* Print errors */
|
||||
#define WRDSF_SHOWERR 0x00000010
|
||||
/* Consider it an error if an undefined shell variable
|
||||
is expanded. */
|
||||
/* Consider it an error if an undefined variable is expanded. */
|
||||
#define WRDSF_UNDEF 0x00000020
|
||||
|
||||
/* Don't do variable expansion. */
|
||||
#define WRDSF_NOVAR 0x00000040
|
||||
/* Abort on ENOMEM error */
|
||||
@@ -85,7 +144,7 @@ struct wordsplit
|
||||
#define WRDSF_SQUOTE 0x00000200
|
||||
/* Handle double quotes */
|
||||
#define WRDSF_DQUOTE 0x00000400
|
||||
/* Handle quotes and escape directives */
|
||||
/* Handle single and double quotes */
|
||||
#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE)
|
||||
/* Replace each input sequence of repeated delimiters with a single
|
||||
delimiter */
|
||||
@@ -113,56 +172,106 @@ struct wordsplit
|
||||
/* Don't split input into words. Useful for side effects. */
|
||||
#define WRDSF_NOSPLIT 0x00400000
|
||||
/* Keep undefined variables in place, instead of expanding them to
|
||||
empty string */
|
||||
empty strings. */
|
||||
#define WRDSF_KEEPUNDEF 0x00800000
|
||||
/* Warn about undefined variables */
|
||||
#define WRDSF_WARNUNDEF 0x01000000
|
||||
/* Handle C escapes */
|
||||
#define WRDSF_CESCAPES 0x02000000
|
||||
|
||||
/* ws_closure is set */
|
||||
#define WRDSF_CLOSURE 0x04000000
|
||||
/* ws_env is a Key/Value environment, i.e. the value of a variable is
|
||||
stored in the element that follows its name. */
|
||||
#define WRDSF_ENV_KV 0x08000000
|
||||
|
||||
/* ws_escape is set */
|
||||
#define WRDSF_ESCAPE 0x10000000
|
||||
|
||||
/* Incremental mode */
|
||||
#define WRDSF_INCREMENTAL 0x20000000
|
||||
/* Perform pathname and tilde expansion */
|
||||
#define WRDSF_PATHEXPAND 0x40000000
|
||||
/* ws_options is initialized */
|
||||
#define WRDSF_OPTIONS 0x80000000
|
||||
|
||||
#define WRDSF_DEFFLAGS \
|
||||
(WRDSF_NOVAR | WRDSF_NOCMD | \
|
||||
WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES)
|
||||
|
||||
#define WRDSE_EOF 0
|
||||
/* Remove the word that produces empty string after path expansion */
|
||||
#define WRDSO_NULLGLOB 0x00000001
|
||||
/* Print error message if path expansion produces empty string */
|
||||
#define WRDSO_FAILGLOB 0x00000002
|
||||
/* Allow a leading period to be matched by metacharacters. */
|
||||
#define WRDSO_DOTGLOB 0x00000004
|
||||
/* ws_command needs argv parameter */
|
||||
#define WRDSO_ARGV 0x00000008
|
||||
/* Keep backslash in unrecognized escape sequences in words */
|
||||
#define WRDSO_BSKEEP_WORD 0x00000010
|
||||
/* Handle octal escapes in words */
|
||||
#define WRDSO_OESC_WORD 0x00000020
|
||||
/* Handle hex escapes in words */
|
||||
#define WRDSO_XESC_WORD 0x00000040
|
||||
|
||||
/* ws_maxwords field is initialized */
|
||||
#define WRDSO_MAXWORDS 0x00000080
|
||||
|
||||
/* Keep backslash in unrecognized escape sequences in quoted strings */
|
||||
#define WRDSO_BSKEEP_QUOTE 0x00000100
|
||||
/* Handle octal escapes in quoted strings */
|
||||
#define WRDSO_OESC_QUOTE 0x00000200
|
||||
/* Handle hex escapes in quoted strings */
|
||||
#define WRDSO_XESC_QUOTE 0x00000400
|
||||
|
||||
#define WRDSO_BSKEEP WRDSO_BSKEEP_WORD
|
||||
#define WRDSO_OESC WRDSO_OESC_WORD
|
||||
#define WRDSO_XESC WRDSO_XESC_WORD
|
||||
|
||||
/* Indices into ws_escape */
|
||||
#define WRDSX_WORD 0
|
||||
#define WRDSX_QUOTE 1
|
||||
|
||||
/* Set escape option F in WS for words (Q==0) or quoted strings (Q==1) */
|
||||
#define WRDSO_ESC_SET(ws,q,f) ((ws)->ws_options |= ((f) << 4*(q)))
|
||||
/* Test WS for escape option F for words (Q==0) or quoted strings (Q==1) */
|
||||
#define WRDSO_ESC_TEST(ws,q,f) ((ws)->ws_options & ((f) << 4*(q)))
|
||||
|
||||
#define WRDSE_OK 0
|
||||
#define WRDSE_EOF WRDSE_OK
|
||||
#define WRDSE_QUOTE 1
|
||||
#define WRDSE_NOSPACE 2
|
||||
#define WRDSE_NOSUPP 3
|
||||
#define WRDSE_USAGE 4
|
||||
#define WRDSE_CBRACE 5
|
||||
#define WRDSE_UNDEF 6
|
||||
#define WRDSE_NOINPUT 7
|
||||
#define WRDSE_USAGE 3
|
||||
#define WRDSE_CBRACE 4
|
||||
#define WRDSE_UNDEF 5
|
||||
#define WRDSE_NOINPUT 6
|
||||
#define WRDSE_PAREN 7
|
||||
#define WRDSE_GLOBERR 8
|
||||
#define WRDSE_USERERR 9
|
||||
|
||||
int wordsplit (const char *s, struct wordsplit *p, int flags);
|
||||
int wordsplit_len (const char *s, size_t len,
|
||||
struct wordsplit *p, int flags);
|
||||
void wordsplit_free (struct wordsplit *p);
|
||||
void wordsplit_free_words (struct wordsplit *ws);
|
||||
int wordsplit (const char *s, wordsplit_t *ws, unsigned flags);
|
||||
int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, unsigned flags);
|
||||
void wordsplit_free (wordsplit_t *ws);
|
||||
void wordsplit_free_words (wordsplit_t *ws);
|
||||
void wordsplit_free_envbuf (wordsplit_t *ws);
|
||||
int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv);
|
||||
|
||||
static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv)
|
||||
__attribute__ ((deprecated));
|
||||
|
||||
static inline void
|
||||
wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv)
|
||||
{
|
||||
wordsplit_get_words (ws, wordc, wordv);
|
||||
}
|
||||
|
||||
int wordsplit_append (wordsplit_t *wsp, int argc, char **argv);
|
||||
|
||||
int wordsplit_c_unquote_char (int c);
|
||||
int wordsplit_c_quote_char (int c);
|
||||
size_t wordsplit_c_quoted_length (const char *str, int quote_hex,
|
||||
int *quote);
|
||||
void wordsplit_general_unquote_copy (char *dst, const char *src, size_t n,
|
||||
const char *escapable);
|
||||
void wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n);
|
||||
void wordsplit_c_unquote_copy (char *dst, const char *src, size_t n);
|
||||
size_t wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote);
|
||||
void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex);
|
||||
|
||||
void wordsplit_perror (struct wordsplit *ws);
|
||||
const char *wordsplit_strerror (struct wordsplit *ws);
|
||||
void wordsplit_perror (wordsplit_t *ws);
|
||||
const char *wordsplit_strerror (wordsplit_t *ws);
|
||||
|
||||
void wordsplit_clearerr (wordsplit_t *ws);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* openat-style fd-relative functions for operating with extended file
|
||||
attributes.
|
||||
|
||||
Copyright 2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2012-2021 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Prototypes for openat-style fd-relative functions for operating with
|
||||
extended file attributes.
|
||||
|
||||
Copyright 2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2012-2021 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
|
||||
|
||||
2
paxutils
2
paxutils
Submodule paxutils updated: ec72abd9dd...b7da0d659e
1
po/.gitignore
vendored
1
po/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/Makefile.in.in
|
||||
/Makevars.template~
|
||||
/Makefile.in.in~
|
||||
*.gmo
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# List of files which contain translatable strings.
|
||||
|
||||
# Copyright 1996, 1999-2000, 2003-2005, 2007, 2013-2014, 2016 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1996-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Make GNU tar scripts.
|
||||
|
||||
# Copyright 2004, 2006-2007, 2013-2014, 2016 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ SLEEP_MESSAGE="`awk '
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright 2004, 2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013 Free Software Foundation
|
||||
# Copyright 2004-2006, 2013, 2019 Free Software Foundation
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -149,13 +149,16 @@ message 20 "Variables:"
|
||||
message 20 "BACKUP_DIRS=$BACKUP_DIRS"
|
||||
message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
|
||||
# The buch of commands below is run in a subshell for which all output is
|
||||
# The bunch of commands below is run in a subshell for which all output is
|
||||
# piped through 'tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
message 1 "preparing tapes"
|
||||
$MT_BEGIN "${TAPE_FILE}"
|
||||
if ! $MT_BEGIN "${TAPE_FILE}"; then
|
||||
echo >&2 "$0: tape initialization failed"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
@@ -191,7 +194,7 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
# 'rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed." 1>&2
|
||||
echo "$0: backup of ${1} failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
@@ -238,17 +241,17 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
message 1 "final cleanup"
|
||||
|
||||
$MT_REWIND "${TAPE_FILE}"
|
||||
$MT_OFFLINE "${TAPE_FILE}"
|
||||
echo "."
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
RC=$?
|
||||
|
||||
if test "${ADMINISTRATOR}" != NONE; then
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
fi
|
||||
|
||||
exit $RC
|
||||
# EOF
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -311,7 +311,9 @@ backup_host() {
|
||||
CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
|
||||
message 10 "CMD: $CMD"
|
||||
sh -c "$CMD"
|
||||
message 10 "RC: $?"
|
||||
RC=$?
|
||||
message 10 "RC: $RC"
|
||||
return $RC
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
# interested parties that a tape for the next volume of the backup needs to
|
||||
# be put in the tape drive.
|
||||
|
||||
# Copyright 2004-2005, 2010, 2012-2014, 2016 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Restore backups.
|
||||
|
||||
# Copyright 2004, 2006, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Display and edit the 'dev' field in tar's snapshots
|
||||
# Copyright 2007, 2011, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2007-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -408,7 +408,7 @@ sub check_field_values ($) {
|
||||
}
|
||||
if ( $msg ne "" ) {
|
||||
$error_found = 1;
|
||||
print "\n shapshot file header:\n";
|
||||
print "\n snapshot file header:\n";
|
||||
print $msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
# concatenates a GNU tar multi-volume archive into a single tar archive.
|
||||
# Author: Bruno Haible <bruno@clisp.org>, Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
# Copyright 2004-2005, 2010, 2013-2014, 2016 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* xsparse - expands compressed sparse file images extracted from GNU tar
|
||||
archives.
|
||||
|
||||
Copyright 2006-2007, 2010, 2013-2014, 2016 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Makefile for GNU tar sources.
|
||||
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2006-2007, 2009, 2013-2014, 2016
|
||||
# Free Software Foundation, Inc.
|
||||
# Copyright 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Long integers, for GNU tar.
|
||||
Copyright 1999, 2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1999-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
105
src/buffer.c
105
src/buffer.c
@@ -1,7 +1,6 @@
|
||||
/* Buffer management for tar.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2013-2014, 2016 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -105,13 +104,20 @@ bool write_archive_to_stdout;
|
||||
|
||||
/* When creating a multi-volume archive, each 'bufmap' represents
|
||||
a member stored (perhaps partly) in the current record buffer.
|
||||
Bufmaps are form a single-linked list in chronological order.
|
||||
|
||||
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.
|
||||
represent fully written members are removed from the list, the
|
||||
nblocks and sizeleft values in the bufmap_head and start values
|
||||
in all remaining bufmaps are updated. The information stored
|
||||
in bufmap_head is used to form the volume header.
|
||||
|
||||
When reading from a multi-volume archive, the list degrades to a
|
||||
single element, which keeps information about the member currently
|
||||
being read.
|
||||
being read. In that case the sizeleft member is updated explicitly
|
||||
from the extractor code by calling the mv_size_left function. The
|
||||
information from bufmap_head is compared with the volume header data
|
||||
to ensure that subsequent volumes are fed in the right order.
|
||||
*/
|
||||
|
||||
struct bufmap
|
||||
@@ -121,6 +127,7 @@ struct bufmap
|
||||
char *file_name; /* Name of the stored file */
|
||||
off_t sizetotal; /* Size of the stored file */
|
||||
off_t sizeleft; /* Size left to read/write */
|
||||
size_t nblocks; /* Number of blocks written since reset */
|
||||
};
|
||||
static struct bufmap *bufmap_head, *bufmap_tail;
|
||||
|
||||
@@ -145,6 +152,7 @@ mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft)
|
||||
bp->file_name = xstrdup (file_name);
|
||||
bp->sizetotal = totsize;
|
||||
bp->sizeleft = sizeleft;
|
||||
bp->nblocks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +163,7 @@ bufmap_locate (size_t off)
|
||||
|
||||
for (map = bufmap_head; map; map = map->next)
|
||||
{
|
||||
if (!map->next
|
||||
|| off < map->next->start * BLOCKSIZE)
|
||||
if (!map->next || off < map->next->start * BLOCKSIZE)
|
||||
break;
|
||||
}
|
||||
return map;
|
||||
@@ -185,7 +192,10 @@ bufmap_reset (struct bufmap *map, ssize_t fixup)
|
||||
if (map)
|
||||
{
|
||||
for (; map; map = map->next)
|
||||
map->start += fixup;
|
||||
{
|
||||
map->start += fixup;
|
||||
map->nblocks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +280,8 @@ enum compress_type {
|
||||
ct_lzip,
|
||||
ct_lzma,
|
||||
ct_lzop,
|
||||
ct_xz
|
||||
ct_xz,
|
||||
ct_zstd
|
||||
};
|
||||
|
||||
static enum compress_type archive_compression_type = ct_none;
|
||||
@@ -299,6 +310,7 @@ static struct zip_magic const magic[] = {
|
||||
{ ct_lzma, 6, "\xFFLZMA" },
|
||||
{ ct_lzop, 4, "\211LZO" },
|
||||
{ ct_xz, 6, "\xFD" "7zXZ" },
|
||||
{ ct_zstd, 4, "\x28\xB5\x2F\xFD" },
|
||||
};
|
||||
|
||||
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
|
||||
@@ -314,6 +326,7 @@ static struct zip_program zip_program[] = {
|
||||
{ ct_lzma, XZ_PROGRAM, "-J" },
|
||||
{ ct_lzop, LZOP_PROGRAM, "--lzop" },
|
||||
{ ct_xz, XZ_PROGRAM, "-J" },
|
||||
{ ct_zstd, ZSTD_PROGRAM, "--zstd" },
|
||||
{ ct_none }
|
||||
};
|
||||
|
||||
@@ -391,10 +404,12 @@ check_compressed_archive (bool *pshort)
|
||||
/* Restore global values */
|
||||
read_full_records = sfr;
|
||||
|
||||
if ((strcmp (record_start->header.magic, TMAGIC) == 0 ||
|
||||
strcmp (record_start->buffer + offsetof (struct posix_header, magic),
|
||||
OLDGNU_MAGIC) == 0) &&
|
||||
tar_checksum (record_start, true) == HEADER_SUCCESS)
|
||||
if (record_start != record_end /* no files smaller than BLOCKSIZE */
|
||||
&& (strcmp (record_start->header.magic, TMAGIC) == 0
|
||||
|| strcmp (record_start->buffer + offsetof (struct posix_header,
|
||||
magic),
|
||||
OLDGNU_MAGIC) == 0)
|
||||
&& tar_checksum (record_start, true) == HEADER_SUCCESS)
|
||||
/* Probably a valid header */
|
||||
return ct_tar;
|
||||
|
||||
@@ -868,12 +883,19 @@ _flush_write (void)
|
||||
if (map)
|
||||
{
|
||||
size_t delta = status - map->start * BLOCKSIZE;
|
||||
ssize_t diff;
|
||||
map->nblocks += delta / 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);
|
||||
{
|
||||
diff = map->start + map->nblocks;
|
||||
map = map->next;
|
||||
}
|
||||
else
|
||||
diff = map->start;
|
||||
bufmap_reset (map, - diff);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
@@ -984,7 +1006,7 @@ void
|
||||
flush_archive (void)
|
||||
{
|
||||
size_t buffer_level;
|
||||
|
||||
|
||||
if (access_mode == ACCESS_READ && time_to_start_writing)
|
||||
{
|
||||
access_mode = ACCESS_WRITE;
|
||||
@@ -1105,9 +1127,9 @@ close_archive (void)
|
||||
{
|
||||
if (time_to_start_writing || access_mode == ACCESS_WRITE)
|
||||
{
|
||||
flush_archive ();
|
||||
if (current_block > record_start)
|
||||
flush_archive ();
|
||||
do
|
||||
flush_archive ();
|
||||
while (current_block > record_start);
|
||||
}
|
||||
|
||||
compute_duration ();
|
||||
@@ -1276,8 +1298,7 @@ change_tape_menu (FILE *read_file)
|
||||
sys_spawn_shell ();
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
fprintf (stderr, _("Invalid input. Type ? for help.\n"));
|
||||
}
|
||||
@@ -1481,18 +1502,17 @@ try_new_volume (void)
|
||||
if (!read_header0 (&dummy))
|
||||
return false;
|
||||
tar_stat_destroy (&dummy);
|
||||
assign_string (&volume_label, current_header->header.name);
|
||||
ASSIGN_STRING_N (&volume_label, current_header->header.name);
|
||||
set_next_block_after (header);
|
||||
header = find_next_block ();
|
||||
if (header->header.typeflag != GNUTYPE_MULTIVOL)
|
||||
break;
|
||||
/* FALL THROUGH */
|
||||
|
||||
FALLTHROUGH;
|
||||
case GNUTYPE_MULTIVOL:
|
||||
if (!read_header0 (&dummy))
|
||||
return false;
|
||||
tar_stat_destroy (&dummy);
|
||||
assign_string (&continued_file_name, current_header->header.name);
|
||||
ASSIGN_STRING_N (&continued_file_name, current_header->header.name);
|
||||
continued_file_size =
|
||||
UINTMAX_FROM_HEADER (current_header->header.size);
|
||||
continued_file_offset =
|
||||
@@ -1512,7 +1532,7 @@ try_new_volume (void)
|
||||
quote (bufmap_head->file_name)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (strcmp (continued_file_name, bufmap_head->file_name))
|
||||
{
|
||||
if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)
|
||||
@@ -1635,15 +1655,7 @@ match_volume_label (void)
|
||||
quote (volume_label_option)));
|
||||
if (label->header.typeflag == GNUTYPE_VOLHDR)
|
||||
{
|
||||
if (memchr (label->header.name, '\0', sizeof label->header.name))
|
||||
assign_string (&volume_label, label->header.name);
|
||||
else
|
||||
{
|
||||
volume_label = xmalloc (sizeof (label->header.name) + 1);
|
||||
memcpy (volume_label, label->header.name,
|
||||
sizeof (label->header.name));
|
||||
volume_label[sizeof (label->header.name)] = 0;
|
||||
}
|
||||
ASSIGN_STRING_N (&volume_label, label->header.name);
|
||||
}
|
||||
else if (label->header.typeflag == XGLTYPE)
|
||||
{
|
||||
@@ -1679,8 +1691,7 @@ _write_volume_label (const char *str)
|
||||
memset (label, 0, BLOCKSIZE);
|
||||
|
||||
strcpy (label->header.name, str);
|
||||
assign_string (¤t_stat_info.file_name,
|
||||
label->header.name);
|
||||
assign_string (¤t_stat_info.file_name, label->header.name);
|
||||
current_stat_info.had_trailing_slash =
|
||||
strip_trailing_slashes (current_stat_info.file_name);
|
||||
|
||||
@@ -1711,7 +1722,6 @@ add_chunk_header (struct bufmap *map)
|
||||
{
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
off_t block_ordinal;
|
||||
union block *blk;
|
||||
struct tar_stat_info st;
|
||||
|
||||
@@ -1721,16 +1731,15 @@ add_chunk_header (struct bufmap *map)
|
||||
st.stat.st_uid = getuid ();
|
||||
st.stat.st_gid = getgid ();
|
||||
st.orig_file_name = xheader_format_name (&st,
|
||||
"%d/GNUFileParts.%p/%f.%n",
|
||||
"%d/GNUFileParts/%f.%n",
|
||||
volno);
|
||||
st.file_name = st.orig_file_name;
|
||||
st.archive_file_size = st.stat.st_size = map->sizeleft;
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
blk = start_header (&st);
|
||||
if (!blk)
|
||||
abort (); /* FIXME */
|
||||
finish_header (&st, blk, block_ordinal);
|
||||
simple_finish_header (write_extended (false, &st, blk));
|
||||
free (st.orig_file_name);
|
||||
}
|
||||
}
|
||||
@@ -1752,15 +1761,19 @@ gnu_add_multi_volume_header (struct bufmap *map)
|
||||
{
|
||||
int tmp;
|
||||
union block *block = find_next_block ();
|
||||
size_t len = strlen (map->file_name);
|
||||
|
||||
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 (map->file_name)));
|
||||
if (len > NAME_FIELD_SIZE)
|
||||
{
|
||||
WARN ((0, 0,
|
||||
_("%s: file name too long to be stored in a GNU multivolume header, truncated"),
|
||||
quotearg_colon (map->file_name)));
|
||||
len = NAME_FIELD_SIZE;
|
||||
}
|
||||
|
||||
memset (block, 0, BLOCKSIZE);
|
||||
|
||||
strncpy (block->header.name, map->file_name, NAME_FIELD_SIZE);
|
||||
memcpy (block->header.name, map->file_name, len);
|
||||
block->header.typeflag = GNUTYPE_MULTIVOL;
|
||||
|
||||
OFF_TO_CHARS (map->sizeleft, block->header.size);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Checkpoint management for tar.
|
||||
|
||||
Copyright 2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2007-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include "fprintftime.h"
|
||||
#include <signal.h>
|
||||
|
||||
enum checkpoint_opcode
|
||||
{
|
||||
@@ -32,7 +33,8 @@ enum checkpoint_opcode
|
||||
cop_ttyout,
|
||||
cop_sleep,
|
||||
cop_exec,
|
||||
cop_totals
|
||||
cop_totals,
|
||||
cop_wait
|
||||
};
|
||||
|
||||
struct checkpoint_action
|
||||
@@ -43,6 +45,7 @@ struct checkpoint_action
|
||||
{
|
||||
time_t time;
|
||||
char *command;
|
||||
int signal;
|
||||
} v;
|
||||
};
|
||||
|
||||
@@ -52,6 +55,16 @@ static unsigned checkpoint;
|
||||
/* List of checkpoint actions */
|
||||
static struct checkpoint_action *checkpoint_action, *checkpoint_action_tail;
|
||||
|
||||
/* State of the checkpoint system */
|
||||
enum {
|
||||
CHKP_INIT, /* Needs initialization */
|
||||
CHKP_COMPILE, /* Actions are being compiled */
|
||||
CHKP_RUN /* Actions are being run */
|
||||
};
|
||||
static int checkpoint_state;
|
||||
/* Blocked signals */
|
||||
static sigset_t sigs;
|
||||
|
||||
static struct checkpoint_action *
|
||||
alloc_action (enum checkpoint_opcode opcode)
|
||||
{
|
||||
@@ -85,6 +98,12 @@ checkpoint_compile_action (const char *str)
|
||||
{
|
||||
struct checkpoint_action *act;
|
||||
|
||||
if (checkpoint_state == CHKP_INIT)
|
||||
{
|
||||
sigemptyset (&sigs);
|
||||
checkpoint_state = CHKP_COMPILE;
|
||||
}
|
||||
|
||||
if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
|
||||
alloc_action (cop_dot);
|
||||
else if (strcmp (str, "bell") == 0)
|
||||
@@ -117,6 +136,12 @@ checkpoint_compile_action (const char *str)
|
||||
}
|
||||
else if (strcmp (str, "totals") == 0)
|
||||
alloc_action (cop_totals);
|
||||
else if (strncmp (str, "wait=", 5) == 0)
|
||||
{
|
||||
act = alloc_action (cop_wait);
|
||||
act->v.signal = decode_signal (str + 5);
|
||||
sigaddset (&sigs, act->v.signal);
|
||||
}
|
||||
else
|
||||
FATAL_ERROR ((0, 0, _("%s: unknown checkpoint action"), str));
|
||||
}
|
||||
@@ -124,15 +149,24 @@ checkpoint_compile_action (const char *str)
|
||||
void
|
||||
checkpoint_finish_compile (void)
|
||||
{
|
||||
if (checkpoint_option)
|
||||
if (checkpoint_state == CHKP_INIT
|
||||
&& checkpoint_option
|
||||
&& !checkpoint_action)
|
||||
{
|
||||
if (!checkpoint_action)
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
}
|
||||
|
||||
if (checkpoint_state == CHKP_COMPILE)
|
||||
{
|
||||
sigprocmask (SIG_BLOCK, &sigs, NULL);
|
||||
|
||||
if (!checkpoint_option)
|
||||
/* set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
|
||||
checkpoint_state = CHKP_RUN;
|
||||
}
|
||||
else if (checkpoint_action)
|
||||
/* Otherwise, set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
}
|
||||
|
||||
static const char *checkpoint_total_format[] = {
|
||||
@@ -390,6 +424,13 @@ run_checkpoint_actions (bool do_write)
|
||||
case cop_totals:
|
||||
compute_duration ();
|
||||
print_total_stats ();
|
||||
break;
|
||||
|
||||
case cop_wait:
|
||||
{
|
||||
int n;
|
||||
sigwait (&sigs, &n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
67
src/common.h
67
src/common.h
@@ -1,7 +1,6 @@
|
||||
/* Common declarations for the tar program.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2012-2016 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -44,6 +43,12 @@
|
||||
# define GLOBAL extern
|
||||
#endif
|
||||
|
||||
#if 7 <= __GNUC__
|
||||
# define FALLTHROUGH __attribute__ ((__fallthrough__))
|
||||
#else
|
||||
# define FALLTHROUGH ((void) 0)
|
||||
#endif
|
||||
|
||||
#define TAREXIT_SUCCESS PAXEXIT_SUCCESS
|
||||
#define TAREXIT_DIFFERS PAXEXIT_DIFFERS
|
||||
#define TAREXIT_FAILURE PAXEXIT_FAILURE
|
||||
@@ -296,6 +301,10 @@ enum hole_detection_method
|
||||
|
||||
GLOBAL enum hole_detection_method hole_detection;
|
||||
|
||||
/* The first entry in names.c:namelist specifies the member name to
|
||||
start extracting from. Set by add_starting_file() upon seeing the
|
||||
-K option.
|
||||
*/
|
||||
GLOBAL bool starting_file_option;
|
||||
|
||||
/* Specified maximum byte length of each tape volume (multiple of 1024). */
|
||||
@@ -331,6 +340,9 @@ GLOBAL const char *volume_label_option;
|
||||
|
||||
/* Other global variables. */
|
||||
|
||||
/* Force POSIX-compliance */
|
||||
GLOBAL bool posixly_correct;
|
||||
|
||||
/* File descriptor for archive file. */
|
||||
GLOBAL int archive;
|
||||
|
||||
@@ -414,9 +426,6 @@ GLOBAL bool show_transformed_names_option;
|
||||
timestamps from archives with an unusual member order. It is automatically
|
||||
set for incremental archives. */
|
||||
GLOBAL bool delay_directory_restore_option;
|
||||
|
||||
/* When set, tar will not refuse to create empty archives */
|
||||
GLOBAL bool files_from_option;
|
||||
|
||||
/* Declarations for each module. */
|
||||
|
||||
@@ -622,7 +631,11 @@ void skip_member (void);
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
char const *quote_n_colon (int n, char const *arg);
|
||||
void assign_string (char **dest, const char *src);
|
||||
void assign_string_n (char **string, const char *value, size_t n);
|
||||
#define ASSIGN_STRING_N(s,v) assign_string_n (s, v, sizeof (v))
|
||||
int unquote_string (char *str);
|
||||
char *zap_slashes (char *name);
|
||||
char *normalize_filename (int cdidx, const char *name);
|
||||
@@ -729,7 +742,21 @@ int set_file_atime (int fd, int parentfd, char const *file,
|
||||
|
||||
/* Module names.c. */
|
||||
|
||||
extern size_t name_count;
|
||||
enum files_count
|
||||
{
|
||||
FILES_NONE,
|
||||
FILES_ONE,
|
||||
FILES_MANY
|
||||
};
|
||||
extern enum files_count filename_args;
|
||||
|
||||
/* Return true if there are file names in the list */
|
||||
static inline bool
|
||||
name_more_files (void)
|
||||
{
|
||||
return filename_args != FILES_NONE;
|
||||
}
|
||||
|
||||
extern struct name *gnu_list_name;
|
||||
|
||||
void gid_to_gname (gid_t gid, char **gname);
|
||||
@@ -738,12 +765,14 @@ void uid_to_uname (uid_t uid, char **uname);
|
||||
int uname_to_uid (char const *uname, uid_t *puid);
|
||||
|
||||
void name_init (void);
|
||||
bool name_more_files (void);
|
||||
void name_add_name (const char *name);
|
||||
void name_term (void);
|
||||
const char *name_next (int change_dirs);
|
||||
void name_gather (void);
|
||||
struct name *addname (char const *string, int change_dir,
|
||||
bool cmdline, struct name *parent);
|
||||
void add_starting_file (char const *file_name);
|
||||
void remname (struct name *name);
|
||||
bool name_match (const char *name);
|
||||
void names_notfound (void);
|
||||
@@ -785,6 +814,8 @@ void set_exit_status (int val);
|
||||
|
||||
void request_stdin (const char *option);
|
||||
|
||||
int decode_signal (const char *);
|
||||
|
||||
/* Where an option comes from: */
|
||||
enum option_source
|
||||
{
|
||||
@@ -803,6 +834,24 @@ struct option_locus
|
||||
class */
|
||||
};
|
||||
|
||||
struct tar_args /* Variables used during option parsing */
|
||||
{
|
||||
struct option_locus *loc;
|
||||
|
||||
struct textual_date *textual_date; /* Keeps the arguments to --newer-mtime
|
||||
and/or --date option if they are
|
||||
textual dates */
|
||||
bool o_option; /* True if -o option was given */
|
||||
bool pax_option; /* True if --pax-option was given */
|
||||
bool compress_autodetect; /* True if compression autodetection should
|
||||
be attempted when creating archives */
|
||||
char const *backup_suffix_string; /* --suffix option argument */
|
||||
char const *version_control_string; /* --backup option argument */
|
||||
};
|
||||
|
||||
#define TAR_ARGS_INITIALIZER(loc) \
|
||||
{ loc, NULL, false, false, false, NULL, NULL }
|
||||
|
||||
void more_options (int argc, char **argv, struct option_locus *loc);
|
||||
|
||||
/* Module update.c. */
|
||||
@@ -823,6 +872,7 @@ void xheader_store (char const *keyword, struct tar_stat_info *st,
|
||||
void xheader_read (struct xheader *xhdr, union block *header, off_t size);
|
||||
void xheader_write (char type, char *name, time_t t, struct xheader *xhdr);
|
||||
void xheader_write_global (struct xheader *xhdr);
|
||||
void xheader_forbid_global (void);
|
||||
void xheader_finish (struct xheader *hdr);
|
||||
void xheader_destroy (struct xheader *hdr);
|
||||
char *xheader_xhdr_name (struct tar_stat_info *st);
|
||||
@@ -927,6 +977,7 @@ void checkpoint_flush_actions (void);
|
||||
#define WARN_EXISTING_FILE 0x00100000
|
||||
#define WARN_XATTR_WRITE 0x00200000
|
||||
#define WARN_RECORD_SIZE 0x00400000
|
||||
#define WARN_FAILED_READ 0x00800000
|
||||
|
||||
/* These warnings are enabled by default in verbose mode: */
|
||||
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY|\
|
||||
@@ -938,10 +989,12 @@ void set_warning_option (const char *arg);
|
||||
|
||||
extern int warning_option;
|
||||
|
||||
#define WARNING_ENABLED(opt) (warning_option & (opt))
|
||||
|
||||
#define WARNOPT(opt,args) \
|
||||
do \
|
||||
{ \
|
||||
if (warning_option & opt) WARN (args); \
|
||||
if (WARNING_ENABLED(opt)) WARN (args); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* Diff files from a tar archive.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2007,
|
||||
2009-2010, 2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -51,6 +50,8 @@ diff_init (void)
|
||||
read_directory_file ();
|
||||
}
|
||||
|
||||
enum { QUOTE_ARG, QUOTE_NAME };
|
||||
|
||||
/* Sigh about something that differs by writing a MESSAGE to stdlis,
|
||||
given MESSAGE is nonzero. Also set the exit status if not already. */
|
||||
void
|
||||
@@ -60,7 +61,7 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stdlis, "%s: ", quotearg_colon (st->file_name));
|
||||
fprintf (stdlis, "%s: ", quote_n_colon (QUOTE_NAME, st->file_name));
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stdlis, fmt, ap);
|
||||
va_end (ap);
|
||||
@@ -263,7 +264,8 @@ diff_link (void)
|
||||
&& !sys_compare_links (&file_data, &link_data))
|
||||
report_difference (¤t_stat_info,
|
||||
_("Not linked to %s"),
|
||||
quote (current_stat_info.link_name));
|
||||
quote_n_colon (QUOTE_ARG,
|
||||
current_stat_info.link_name));
|
||||
}
|
||||
|
||||
#ifdef HAVE_READLINK
|
||||
@@ -477,8 +479,7 @@ diff_archive (void)
|
||||
ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
|
||||
quotearg_colon (current_stat_info.file_name),
|
||||
current_header->header.typeflag));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case AREGTYPE:
|
||||
case REGTYPE:
|
||||
case GNUTYPE_SPARSE:
|
||||
|
||||
70
src/create.c
70
src/create.c
@@ -1,7 +1,6 @@
|
||||
/* Create a tar archive.
|
||||
|
||||
Copyright 1985, 1992-1994, 1996-1997, 1999-2001, 2003-2007,
|
||||
2009-2010, 2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1985-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -202,8 +201,8 @@ to_base256 (int negative, uintmax_t value, char *where, size_t size)
|
||||
#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))
|
||||
#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,
|
||||
@@ -518,8 +517,8 @@ start_private_header (const char *name, size_t size, time_t t)
|
||||
MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
|
||||
UID_TO_CHARS (0, header->header.uid);
|
||||
GID_TO_CHARS (0, header->header.gid);
|
||||
strncpy (header->header.magic, TMAGIC, TMAGLEN);
|
||||
strncpy (header->header.version, TVERSION, TVERSLEN);
|
||||
memcpy (header->header.magic, TMAGIC, TMAGLEN);
|
||||
memcpy (header->header.version, TVERSION, TVERSLEN);
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -542,15 +541,19 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
size_t size = strlen (p) + 1;
|
||||
size_t bufsize;
|
||||
union block *header;
|
||||
char *tmpname;
|
||||
|
||||
header = start_private_header ("././@LongLink", size, 0);
|
||||
uid_to_uname (0, &tmpname);
|
||||
UNAME_TO_CHARS (tmpname, header->header.uname);
|
||||
free (tmpname);
|
||||
gid_to_gname (0, &tmpname);
|
||||
GNAME_TO_CHARS (tmpname, header->header.gname);
|
||||
free (tmpname);
|
||||
if (! numeric_owner_option)
|
||||
{
|
||||
static char *uname, *gname;
|
||||
if (!uname)
|
||||
{
|
||||
uid_to_uname (0, &uname);
|
||||
gid_to_gname (0, &gname);
|
||||
}
|
||||
UNAME_TO_CHARS (uname, header->header.uname);
|
||||
GNAME_TO_CHARS (gname, header->header.gname);
|
||||
}
|
||||
|
||||
strcpy (header->buffer + offsetof (struct posix_header, magic),
|
||||
OLDGNU_MAGIC);
|
||||
@@ -743,7 +746,7 @@ start_header (struct tar_stat_info *st)
|
||||
union block *header;
|
||||
char const *uname = NULL;
|
||||
char const *gname = NULL;
|
||||
|
||||
|
||||
header = write_header_name (st);
|
||||
if (!header)
|
||||
return NULL;
|
||||
@@ -830,11 +833,11 @@ start_header (struct tar_stat_info *st)
|
||||
case USE_FILE_MTIME:
|
||||
mtime = st->mtime;
|
||||
break;
|
||||
|
||||
|
||||
case FORCE_MTIME:
|
||||
mtime = mtime_option;
|
||||
break;
|
||||
|
||||
|
||||
case CLAMP_MTIME:
|
||||
mtime = timespec_cmp (st->mtime, mtime_option) > 0
|
||||
? mtime_option : st->mtime;
|
||||
@@ -913,8 +916,8 @@ start_header (struct tar_stat_info *st)
|
||||
|
||||
case POSIX_FORMAT:
|
||||
case USTAR_FORMAT:
|
||||
strncpy (header->header.magic, TMAGIC, TMAGLEN);
|
||||
strncpy (header->header.version, TVERSION, TVERSLEN);
|
||||
memcpy (header->header.magic, TMAGIC, TMAGLEN);
|
||||
memcpy (header->header.version, TVERSION, TVERSLEN);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1345,15 +1348,15 @@ create_archive (void)
|
||||
{
|
||||
struct name const *p;
|
||||
|
||||
trivial_link_count = name_count <= 1 && ! dereference_option;
|
||||
trivial_link_count = filename_args != FILES_MANY && ! dereference_option;
|
||||
|
||||
open_archive (ACCESS_WRITE);
|
||||
buffer_write_global_xheader ();
|
||||
|
||||
if (incremental_option)
|
||||
{
|
||||
size_t buffer_size = 1000;
|
||||
char *buffer = xmalloc (buffer_size);
|
||||
size_t buffer_size = 0;
|
||||
char *buffer = NULL;
|
||||
const char *q;
|
||||
|
||||
collect_and_sort_names ();
|
||||
@@ -1368,12 +1371,8 @@ create_archive (void)
|
||||
{
|
||||
struct tar_stat_info st;
|
||||
size_t plen = strlen (p->name);
|
||||
if (buffer_size <= plen)
|
||||
{
|
||||
while ((buffer_size *= 2) <= plen)
|
||||
continue;
|
||||
buffer = xrealloc (buffer, buffer_size);
|
||||
}
|
||||
while (buffer_size <= plen)
|
||||
buffer = x2realloc (buffer, &buffer_size);
|
||||
memcpy (buffer, p->name, plen);
|
||||
if (! ISSLASH (buffer[plen - 1]))
|
||||
buffer[plen++] = DIRECTORY_SEPARATOR;
|
||||
@@ -1391,23 +1390,21 @@ create_archive (void)
|
||||
open_searchdir_flags);
|
||||
if (fd < 0)
|
||||
{
|
||||
open_diag (p->name);
|
||||
file_removed_diag (p->name, !p->parent,
|
||||
open_diag);
|
||||
break;
|
||||
}
|
||||
st.fd = fd;
|
||||
if (fstat (fd, &st.stat) != 0)
|
||||
{
|
||||
stat_diag (p->name);
|
||||
file_removed_diag (p->name, !p->parent,
|
||||
stat_diag);
|
||||
break;
|
||||
}
|
||||
st.orig_file_name = xstrdup (p->name);
|
||||
}
|
||||
if (buffer_size < plen + qlen)
|
||||
{
|
||||
while ((buffer_size *=2 ) < plen + qlen)
|
||||
continue;
|
||||
buffer = xrealloc (buffer, buffer_size);
|
||||
}
|
||||
while (buffer_size < plen + qlen)
|
||||
buffer = x2realloc (buffer, &buffer_size);
|
||||
strcpy (buffer + plen, q + 1);
|
||||
dump_file (&st, q + 1, buffer);
|
||||
}
|
||||
@@ -1528,7 +1525,8 @@ file_count_links (struct tar_stat_info *st)
|
||||
char *linkname = NULL;
|
||||
struct link *lp;
|
||||
|
||||
assign_string (&linkname, st->orig_file_name);
|
||||
assign_string (&linkname, safer_name_suffix (st->orig_file_name, true,
|
||||
absolute_names_option));
|
||||
transform_name (&linkname, XFORM_LINK);
|
||||
|
||||
lp = xmalloc (offsetof (struct link, name)
|
||||
|
||||
219
src/delete.c
219
src/delete.c
@@ -1,7 +1,6 @@
|
||||
/* Delete entries from a tar archive.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996-1997, 2000-2001, 2003-2006, 2010,
|
||||
2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -148,6 +147,23 @@ write_recent_bytes (char *data, size_t bytes)
|
||||
write_record (1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
flush_file (void)
|
||||
{
|
||||
off_t blocks_to_skip;
|
||||
|
||||
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);
|
||||
flush_archive ();
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
}
|
||||
|
||||
void
|
||||
delete_archive_members (void)
|
||||
{
|
||||
@@ -156,7 +172,6 @@ delete_archive_members (void)
|
||||
|
||||
/* FIXME: Should clean the routine before cleaning these variables :-( */
|
||||
struct name *name;
|
||||
off_t blocks_to_skip = 0;
|
||||
off_t blocks_to_keep = 0;
|
||||
int kept_blocks_in_record;
|
||||
|
||||
@@ -164,11 +179,12 @@ delete_archive_members (void)
|
||||
open_archive (ACCESS_UPDATE);
|
||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||
|
||||
/* Skip to the first member that matches the name list. */
|
||||
do
|
||||
{
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
read_header_x_raw);
|
||||
¤t_stat_info,
|
||||
read_header_x_raw);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
@@ -182,13 +198,12 @@ delete_archive_members (void)
|
||||
break;
|
||||
}
|
||||
name->found_count++;
|
||||
if (!ISFOUND(name))
|
||||
if (!ISFOUND (name))
|
||||
{
|
||||
skip_member ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
logical_status = status;
|
||||
break;
|
||||
@@ -199,7 +214,7 @@ delete_archive_members (void)
|
||||
set_next_block_after (current_header);
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_END_OF_FILE:
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
@@ -210,14 +225,12 @@ delete_archive_members (void)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_FAILURE:
|
||||
break;
|
||||
|
||||
@@ -247,15 +260,12 @@ delete_archive_members (void)
|
||||
|
||||
if (logical_status == HEADER_SUCCESS)
|
||||
{
|
||||
/* FIXME: Pheew! This is crufty code! */
|
||||
logical_status = HEADER_STILL_UNREAD;
|
||||
goto flush_file;
|
||||
flush_file ();
|
||||
}
|
||||
|
||||
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
|
||||
"delete.c", line 223: warning: loop not entered at top
|
||||
Reported by Bruno Haible. */
|
||||
while (1)
|
||||
/* Skip matching members and move the rest up the archive. */
|
||||
while (logical_status != HEADER_END_OF_FILE)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
@@ -263,105 +273,108 @@ delete_archive_members (void)
|
||||
|
||||
if (current_block == record_end)
|
||||
flush_archive ();
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
read_header_auto);
|
||||
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
|
||||
switch (status)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
|
||||
{
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
}
|
||||
case HEADER_STILL_UNREAD:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
|
||||
if (status == HEADER_FAILURE)
|
||||
{
|
||||
ERROR ((0, 0, _("Deleting non-header from archive")));
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
case HEADER_SUCCESS:
|
||||
/* Found another header. */
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
/* Found another header. */
|
||||
|
||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
name->found_count++;
|
||||
if (ISFOUND(name))
|
||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
flush_file:
|
||||
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)
|
||||
name->found_count++;
|
||||
if (ISFOUND (name))
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
flush_archive ();
|
||||
flush_file ();
|
||||
break;
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
blocks_to_skip = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Copy header. */
|
||||
/* Copy header. */
|
||||
|
||||
if (current_stat_info.xhdr.size)
|
||||
{
|
||||
write_recent_bytes (current_stat_info.xhdr.buffer,
|
||||
current_stat_info.xhdr.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
write_recent_blocks (recent_long_name, recent_long_name_blocks);
|
||||
write_recent_blocks (recent_long_link, recent_long_link_blocks);
|
||||
}
|
||||
new_record[new_blocks] = *current_header;
|
||||
new_blocks++;
|
||||
blocks_to_keep
|
||||
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
set_next_block_after (current_header);
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
|
||||
/* Copy data. */
|
||||
|
||||
kept_blocks_in_record = record_end - current_block;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
|
||||
while (blocks_to_keep)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (current_block == record_end)
|
||||
if (current_stat_info.xhdr.size)
|
||||
{
|
||||
flush_read ();
|
||||
current_block = record_start;
|
||||
kept_blocks_in_record = blocking_factor;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
write_recent_bytes (current_stat_info.xhdr.buffer,
|
||||
current_stat_info.xhdr.size);
|
||||
}
|
||||
count = kept_blocks_in_record;
|
||||
if (blocking_factor - new_blocks < count)
|
||||
count = blocking_factor - new_blocks;
|
||||
|
||||
if (! count)
|
||||
abort ();
|
||||
|
||||
memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
|
||||
new_blocks += count;
|
||||
current_block += count;
|
||||
blocks_to_keep -= count;
|
||||
kept_blocks_in_record -= count;
|
||||
|
||||
else
|
||||
{
|
||||
write_recent_blocks (recent_long_name,
|
||||
recent_long_name_blocks);
|
||||
write_recent_blocks (recent_long_link,
|
||||
recent_long_link_blocks);
|
||||
}
|
||||
new_record[new_blocks] = *current_header;
|
||||
new_blocks++;
|
||||
blocks_to_keep
|
||||
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
set_next_block_after (current_header);
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
|
||||
/* Copy data. */
|
||||
|
||||
kept_blocks_in_record = record_end - current_block;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
|
||||
while (blocks_to_keep)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (current_block == record_end)
|
||||
{
|
||||
flush_read ();
|
||||
current_block = record_start;
|
||||
kept_blocks_in_record = blocking_factor;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
}
|
||||
count = kept_blocks_in_record;
|
||||
if (blocking_factor - new_blocks < count)
|
||||
count = blocking_factor - new_blocks;
|
||||
|
||||
if (! count)
|
||||
abort ();
|
||||
|
||||
memcpy (new_record + new_blocks, current_block,
|
||||
count * BLOCKSIZE);
|
||||
new_blocks += count;
|
||||
current_block += count;
|
||||
blocks_to_keep -= count;
|
||||
kept_blocks_in_record -= count;
|
||||
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
}
|
||||
break;
|
||||
|
||||
case HEADER_ZERO_BLOCK:
|
||||
if (ignore_zeros_option)
|
||||
set_next_block_after (current_header);
|
||||
else
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
|
||||
case HEADER_FAILURE:
|
||||
ERROR ((0, 0, _("Deleting non-header from archive")));
|
||||
set_next_block_after (current_header);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
}
|
||||
|
||||
if (logical_status == HEADER_END_OF_FILE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Per-directory exclusion files for tar.
|
||||
|
||||
Copyright 2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2014-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -104,7 +104,8 @@ info_attach_exclist (struct tar_stat_info *dir)
|
||||
vcsfile->data = vcsfile->initfn (vcsfile->data);
|
||||
|
||||
if (add_exclude_fp (vcsfile->addfn, ex, fp,
|
||||
EXCLUDE_WILDCARDS|EXCLUDE_ANCHORED, '\n',
|
||||
FNM_FILE_NAME|EXCLUDE_WILDCARDS|EXCLUDE_ANCHORED,
|
||||
'\n',
|
||||
vcsfile->data))
|
||||
{
|
||||
int e = errno;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Exit from GNU tar.
|
||||
|
||||
Copyright 2009, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2009-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
487
src/extract.c
487
src/extract.c
@@ -1,7 +1,6 @@
|
||||
/* Extract files from a tar archive.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2014,
|
||||
2016 Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -195,7 +194,7 @@ extr_init (void)
|
||||
|
||||
/* Use fchmod if possible, fchmodat otherwise. */
|
||||
static int
|
||||
fd_chmod (int fd, char const *file, mode_t mode, int atflag)
|
||||
fd_i_chmod (int fd, char const *file, mode_t mode, int atflag)
|
||||
{
|
||||
if (0 <= fd)
|
||||
{
|
||||
@@ -206,6 +205,42 @@ fd_chmod (int fd, char const *file, mode_t mode, int atflag)
|
||||
return fchmodat (chdir_fd, file, mode, atflag);
|
||||
}
|
||||
|
||||
/* A version of fd_i_chmod which gracefully handles several common error
|
||||
conditions. Additional argument TYPEFLAG is the type of file in tar
|
||||
notation.
|
||||
*/
|
||||
static int
|
||||
fd_chmod(int fd, char const *file_name, int mode, int atflag, int typeflag)
|
||||
{
|
||||
int chmod_errno = fd_i_chmod (fd, file_name, mode, atflag) == 0 ? 0 : errno;
|
||||
|
||||
/* On Solaris, chmod may fail if we don't have PRIV_ALL, because
|
||||
setuid-root files would otherwise be a backdoor. See
|
||||
http://opensolaris.org/jive/thread.jspa?threadID=95826
|
||||
(2009-09-03). */
|
||||
if (chmod_errno == EPERM && (mode & S_ISUID)
|
||||
&& priv_set_restore_linkdir () == 0)
|
||||
{
|
||||
chmod_errno = fd_i_chmod (fd, file_name, mode, atflag) == 0 ? 0 : errno;
|
||||
priv_set_remove_linkdir ();
|
||||
}
|
||||
|
||||
/* Linux fchmodat does not support AT_SYMLINK_NOFOLLOW, and
|
||||
returns ENOTSUP even when operating on non-symlinks, try
|
||||
again with the flag disabled if it does not appear to be
|
||||
supported and if the file is not a symlink. This
|
||||
introduces a race, alas. */
|
||||
if (atflag && typeflag != SYMTYPE && ! implemented (chmod_errno))
|
||||
chmod_errno = fd_i_chmod (fd, file_name, mode, 0) == 0 ? 0 : errno;
|
||||
|
||||
if (chmod_errno && (typeflag != SYMTYPE || implemented (chmod_errno)))
|
||||
{
|
||||
errno = chmod_errno;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use fchown if possible, fchownat otherwise. */
|
||||
static int
|
||||
fd_chown (int fd, char const *file, uid_t uid, gid_t gid, int atflag)
|
||||
@@ -260,35 +295,8 @@ set_mode (char const *file_name,
|
||||
|
||||
if (current_mode != mode)
|
||||
{
|
||||
int chmod_errno =
|
||||
fd_chmod (fd, file_name, mode, atflag) == 0 ? 0 : errno;
|
||||
|
||||
/* On Solaris, chmod may fail if we don't have PRIV_ALL, because
|
||||
setuid-root files would otherwise be a backdoor. See
|
||||
http://opensolaris.org/jive/thread.jspa?threadID=95826
|
||||
(2009-09-03). */
|
||||
if (chmod_errno == EPERM && (mode & S_ISUID)
|
||||
&& priv_set_restore_linkdir () == 0)
|
||||
{
|
||||
chmod_errno =
|
||||
fd_chmod (fd, file_name, mode, atflag) == 0 ? 0 : errno;
|
||||
priv_set_remove_linkdir ();
|
||||
}
|
||||
|
||||
/* Linux fchmodat does not support AT_SYMLINK_NOFOLLOW, and
|
||||
returns ENOTSUP even when operating on non-symlinks, try
|
||||
again with the flag disabled if it does not appear to be
|
||||
supported and if the file is not a symlink. This
|
||||
introduces a race, alas. */
|
||||
if (atflag && typeflag != SYMTYPE && ! implemented (chmod_errno))
|
||||
chmod_errno = fd_chmod (fd, file_name, mode, 0) == 0 ? 0 : errno;
|
||||
|
||||
if (chmod_errno
|
||||
&& (typeflag != SYMTYPE || implemented (chmod_errno)))
|
||||
{
|
||||
errno = chmod_errno;
|
||||
chmod_error_details (file_name, mode);
|
||||
}
|
||||
if (fd_chmod (fd, file_name, mode, atflag, typeflag))
|
||||
chmod_error_details (file_name, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,6 +401,24 @@ set_stat (char const *file_name,
|
||||
xattrs_selinux_set (st, file_name, typeflag);
|
||||
}
|
||||
|
||||
/* Find the direct ancestor of FILE_NAME in the delayed_set_stat list.
|
||||
*/
|
||||
static struct delayed_set_stat *
|
||||
find_direct_ancestor (char const *file_name)
|
||||
{
|
||||
struct delayed_set_stat *h = delayed_set_stat_head;
|
||||
while (h)
|
||||
{
|
||||
if (! h->after_links
|
||||
&& strncmp (file_name, h->file_name, h->file_name_len) == 0
|
||||
&& ISSLASH (file_name[h->file_name_len])
|
||||
&& (last_component (file_name) == file_name + h->file_name_len + 1))
|
||||
break;
|
||||
h = h->next;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/* For each entry H in the leading prefix of entries in HEAD that do
|
||||
not have after_links marked, mark H and fill in its dev and ino
|
||||
members. Assume HEAD && ! HEAD->after_links. */
|
||||
@@ -441,25 +467,56 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
|
||||
mode_t mode, int atflag)
|
||||
{
|
||||
size_t file_name_len = strlen (file_name);
|
||||
struct delayed_set_stat *data = xmalloc (sizeof (*data));
|
||||
data->next = delayed_set_stat_head;
|
||||
struct delayed_set_stat *data;
|
||||
|
||||
for (data = delayed_set_stat_head; data; data = data->next)
|
||||
if (strcmp (data->file_name, file_name) == 0)
|
||||
break;
|
||||
|
||||
if (data)
|
||||
{
|
||||
if (data->interdir)
|
||||
{
|
||||
struct stat real_st;
|
||||
if (fstatat (chdir_fd, data->file_name,
|
||||
&real_st, data->atflag) != 0)
|
||||
{
|
||||
stat_error (data->file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
data->dev = real_st.st_dev;
|
||||
data->ino = real_st.st_ino;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = xmalloc (sizeof (*data));
|
||||
data->next = delayed_set_stat_head;
|
||||
delayed_set_stat_head = data;
|
||||
data->file_name_len = file_name_len;
|
||||
data->file_name = xstrdup (file_name);
|
||||
data->after_links = false;
|
||||
if (st)
|
||||
{
|
||||
data->dev = st->stat.st_dev;
|
||||
data->ino = st->stat.st_ino;
|
||||
}
|
||||
}
|
||||
|
||||
data->mode = mode;
|
||||
if (st)
|
||||
{
|
||||
data->dev = st->stat.st_dev;
|
||||
data->ino = st->stat.st_ino;
|
||||
data->uid = st->stat.st_uid;
|
||||
data->gid = st->stat.st_gid;
|
||||
data->atime = st->atime;
|
||||
data->mtime = st->mtime;
|
||||
}
|
||||
data->file_name_len = file_name_len;
|
||||
data->file_name = xstrdup (file_name);
|
||||
data->current_mode = current_mode;
|
||||
data->current_mode_mask = current_mode_mask;
|
||||
data->interdir = ! st;
|
||||
data->atflag = atflag;
|
||||
data->after_links = 0;
|
||||
data->change_dir = chdir_current;
|
||||
data->cntx_name = NULL;
|
||||
if (st)
|
||||
@@ -491,8 +548,6 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
|
||||
data->xattr_map = NULL;
|
||||
data->xattr_map_size = 0;
|
||||
}
|
||||
strcpy (data->file_name, file_name);
|
||||
delayed_set_stat_head = data;
|
||||
if (must_be_dot_or_slash (file_name))
|
||||
mark_after_links (data);
|
||||
}
|
||||
@@ -506,7 +561,7 @@ repair_delayed_set_stat (char const *dir,
|
||||
struct stat const *dir_stat_info)
|
||||
{
|
||||
struct delayed_set_stat *data;
|
||||
for (data = delayed_set_stat_head; data; data = data->next)
|
||||
for (data = delayed_set_stat_head; data; data = data->next)
|
||||
{
|
||||
struct stat st;
|
||||
if (fstatat (chdir_fd, data->file_name, &st, data->atflag) != 0)
|
||||
@@ -740,10 +795,9 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
break;
|
||||
stp = &st;
|
||||
}
|
||||
|
||||
/* The caller tried to open a symbolic link with O_NOFOLLOW.
|
||||
Fall through, treating it as an already-existing file. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case EEXIST:
|
||||
/* Remove an old file, if the options allow this. */
|
||||
|
||||
@@ -760,8 +814,7 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
case KEEP_NEWER_FILES:
|
||||
if (file_newer_p (file_name, stp, ¤t_stat_info))
|
||||
break;
|
||||
/* FALL THROUGH */
|
||||
|
||||
FALLTHROUGH;
|
||||
case DEFAULT_OLD_FILES:
|
||||
case NO_OVERWRITE_DIR_OLD_FILES:
|
||||
case OVERWRITE_OLD_FILES:
|
||||
@@ -772,6 +825,7 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
case UNLINK_FIRST_OLD_FILES:
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
|
||||
case ENOENT:
|
||||
/* Attempt creating missing intermediate directories. */
|
||||
@@ -795,13 +849,13 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
in advance dramatically improves the following performance of reading and
|
||||
writing a file). If not restoring permissions, invert the INVERT_PERMISSIONS
|
||||
bits from the file's current permissions. TYPEFLAG specifies the type of the
|
||||
file. FILE_CREATED indicates set_xattr has created the file */
|
||||
file. Returns non-zero when error occurs (while un-available xattrs is not
|
||||
an error, rather no-op). Non-zero FILE_CREATED indicates set_xattr has
|
||||
created the file. */
|
||||
static int
|
||||
set_xattr (char const *file_name, struct tar_stat_info const *st,
|
||||
mode_t invert_permissions, char typeflag, int *file_created)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
bool interdir_made = false;
|
||||
|
||||
@@ -809,17 +863,32 @@ set_xattr (char const *file_name, struct tar_stat_info const *st,
|
||||
{
|
||||
mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
|
||||
|
||||
do
|
||||
status = mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0);
|
||||
while (status && maybe_recoverable ((char *)file_name, false,
|
||||
&interdir_made));
|
||||
for (;;)
|
||||
{
|
||||
if (!mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0))
|
||||
{
|
||||
/* Successfully created file */
|
||||
xattrs_xattrs_set (st, file_name, typeflag, 0);
|
||||
*file_created = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
xattrs_xattrs_set (st, file_name, typeflag, 0);
|
||||
*file_created = 1;
|
||||
switch (maybe_recoverable ((char *)file_name, false, &interdir_made))
|
||||
{
|
||||
case RECOVER_OK:
|
||||
continue;
|
||||
case RECOVER_NO:
|
||||
skip_member ();
|
||||
open_error (file_name);
|
||||
return 1;
|
||||
case RECOVER_SKIP:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return(status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fix the statuses of all directories whose statuses need fixing, and
|
||||
@@ -906,7 +975,7 @@ is_directory_link (const char *file_name)
|
||||
struct stat st;
|
||||
int e = errno;
|
||||
int res;
|
||||
|
||||
|
||||
res = (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 &&
|
||||
S_ISLNK (st.st_mode) &&
|
||||
fstatat (chdir_fd, file_name, &st, 0) == 0 &&
|
||||
@@ -915,6 +984,26 @@ is_directory_link (const char *file_name)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given struct stat of a directory (or directory member) whose ownership
|
||||
or permissions of will be restored later, return the temporary permissions
|
||||
for that directory, sufficiently restrictive so that in the meantime
|
||||
processes owned by other users do not inadvertently create files under this
|
||||
directory that inherit the wrong owner, group, or permissions from the
|
||||
directory.
|
||||
|
||||
If not root, though, make the directory writeable and searchable at first,
|
||||
so that files can be created under it.
|
||||
*/
|
||||
static inline int
|
||||
safe_dir_mode (struct stat const *st)
|
||||
{
|
||||
return ((st->st_mode
|
||||
& (0 < same_owner_option || 0 < same_permissions_option
|
||||
? S_IRWXU
|
||||
: MODE_RWX))
|
||||
| (we_are_root ? 0 : MODE_WXUSR));
|
||||
}
|
||||
|
||||
/* Extractor functions for various member types */
|
||||
|
||||
static int
|
||||
@@ -944,18 +1033,7 @@ extract_dir (char *file_name, int typeflag)
|
||||
else if (typeflag == GNUTYPE_DUMPDIR)
|
||||
skip_member ();
|
||||
|
||||
/* If ownership or permissions will be restored later, create the
|
||||
directory with restrictive permissions at first, so that in the
|
||||
meantime processes owned by other users do not inadvertently
|
||||
create files under this directory that inherit the wrong owner,
|
||||
group, or permissions from the directory. If not root, though,
|
||||
make the directory writeable and searchable at first, so that
|
||||
files can be created under it. */
|
||||
mode = ((current_stat_info.stat.st_mode
|
||||
& (0 < same_owner_option || 0 < same_permissions_option
|
||||
? S_IRWXU
|
||||
: MODE_RWX))
|
||||
| (we_are_root ? 0 : MODE_WXUSR));
|
||||
mode = safe_dir_mode (¤t_stat_info.stat);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -971,6 +1049,7 @@ extract_dir (char *file_name, int typeflag)
|
||||
if (errno == EEXIST
|
||||
&& (interdir_made
|
||||
|| keep_directory_symlink_option
|
||||
|| old_files_option == NO_OVERWRITE_DIR_OLD_FILES
|
||||
|| old_files_option == DEFAULT_OLD_FILES
|
||||
|| old_files_option == OVERWRITE_OLD_FILES))
|
||||
{
|
||||
@@ -978,7 +1057,7 @@ extract_dir (char *file_name, int typeflag)
|
||||
|
||||
if (keep_directory_symlink_option && is_directory_link (file_name))
|
||||
return 0;
|
||||
|
||||
|
||||
if (deref_stat (file_name, &st) == 0)
|
||||
{
|
||||
current_mode = st.st_mode;
|
||||
@@ -991,6 +1070,31 @@ extract_dir (char *file_name, int typeflag)
|
||||
repair_delayed_set_stat (file_name, &st);
|
||||
return 0;
|
||||
}
|
||||
else if (old_files_option == NO_OVERWRITE_DIR_OLD_FILES)
|
||||
{
|
||||
/* Temporarily change the directory mode to a safe
|
||||
value, to be able to create files in it, should
|
||||
the need be.
|
||||
*/
|
||||
mode = safe_dir_mode (&st);
|
||||
status = fd_chmod(-1, file_name, mode,
|
||||
AT_SYMLINK_NOFOLLOW, DIRTYPE);
|
||||
if (status == 0)
|
||||
{
|
||||
/* Store the actual directory mode, to be restored
|
||||
later.
|
||||
*/
|
||||
current_stat_info.stat = st;
|
||||
current_mode = mode & ~ current_umask;
|
||||
current_mode_mask = MODE_RWX;
|
||||
atflag = AT_SYMLINK_NOFOLLOW;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
chmod_error_details (file_name, mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1136,11 +1240,7 @@ extract_file (char *file_name, int typeflag)
|
||||
int file_created = 0;
|
||||
if (set_xattr (file_name, ¤t_stat_info, invert_permissions,
|
||||
typeflag, &file_created))
|
||||
{
|
||||
skip_member ();
|
||||
open_error (file_name);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
while ((fd = open_output_file (file_name, typeflag, mode,
|
||||
file_created, ¤t_mode,
|
||||
@@ -1223,20 +1323,69 @@ extract_file (char *file_name, int typeflag)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Find a delayed_link structure corresponding to the source NAME.
|
||||
Such a structure exists in the delayed link list only if the link
|
||||
placeholder file has been created. Therefore, try to stat the NAME
|
||||
first. If it doesn't exist, there is no matching entry in the list.
|
||||
Otherwise, look for the entry in list which has the matching dev
|
||||
and ino numbers.
|
||||
|
||||
This approach avoids scanning the singly-linked list in obvious cases
|
||||
and does not rely on comparing file names, which may differ for
|
||||
various reasons (e.g. relative vs. absolute file names).
|
||||
*/
|
||||
static struct delayed_link *
|
||||
find_delayed_link_source (char const *name)
|
||||
{
|
||||
struct delayed_link *dl;
|
||||
struct stat st;
|
||||
|
||||
if (!delayed_link_head)
|
||||
return NULL;
|
||||
|
||||
if (fstatat (chdir_fd, name, &st, AT_SYMLINK_NOFOLLOW))
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
stat_error (name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (dl = delayed_link_head; dl; dl = dl->next)
|
||||
{
|
||||
if (dl->dev == st.st_dev && dl->ino == st.st_ino)
|
||||
break;
|
||||
}
|
||||
return dl;
|
||||
}
|
||||
|
||||
/* Create a placeholder file with name FILE_NAME, which will be
|
||||
replaced after other extraction is done by a symbolic link if
|
||||
IS_SYMLINK is true, and by a hard link otherwise. Set
|
||||
*INTERDIR_MADE if an intermediate directory is made in the
|
||||
process. */
|
||||
process.
|
||||
Install the created struct delayed_link after PREV, unless the
|
||||
latter is NULL, in which case insert it at the head of the delayed
|
||||
link list.
|
||||
*/
|
||||
|
||||
static int
|
||||
create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made,
|
||||
struct delayed_link *prev)
|
||||
{
|
||||
int fd;
|
||||
struct stat st;
|
||||
|
||||
while ((fd = openat (chdir_fd, file_name, O_WRONLY | O_CREAT | O_EXCL, 0)) < 0)
|
||||
{
|
||||
if (errno == EEXIST && find_delayed_link_source (file_name))
|
||||
{
|
||||
/* The placeholder file has already been created. This means
|
||||
that the link being extracted is a duplicate of an already
|
||||
processed one. Skip it.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (maybe_recoverable (file_name, false, interdir_made))
|
||||
{
|
||||
case RECOVER_OK:
|
||||
@@ -1265,8 +1414,16 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
xmalloc (offsetof (struct delayed_link, target)
|
||||
+ strlen (current_stat_info.link_name)
|
||||
+ 1);
|
||||
p->next = delayed_link_head;
|
||||
delayed_link_head = p;
|
||||
if (prev)
|
||||
{
|
||||
p->next = prev->next;
|
||||
prev->next = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->next = delayed_link_head;
|
||||
delayed_link_head = p;
|
||||
}
|
||||
p->dev = st.st_dev;
|
||||
p->ino = st.st_ino;
|
||||
p->birthtime = get_stat_birthtime (&st);
|
||||
@@ -1281,7 +1438,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
}
|
||||
p->change_dir = chdir_current;
|
||||
p->sources = xmalloc (offsetof (struct string_list, string)
|
||||
+ strlen (file_name) + 1);
|
||||
+ strlen (file_name) + 1);
|
||||
p->sources->next = 0;
|
||||
strcpy (p->sources->string, file_name);
|
||||
p->cntx_name = NULL;
|
||||
@@ -1290,14 +1447,11 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
p->acls_a_len = 0;
|
||||
p->acls_d_ptr = NULL;
|
||||
p->acls_d_len = 0;
|
||||
xheader_xattr_copy (¤t_stat_info, &p->xattr_map, &p->xattr_map_size);
|
||||
xheader_xattr_copy (¤t_stat_info, &p->xattr_map,
|
||||
&p->xattr_map_size);
|
||||
strcpy (p->target, current_stat_info.link_name);
|
||||
|
||||
h = delayed_set_stat_head;
|
||||
if (h && ! h->after_links
|
||||
&& strncmp (file_name, h->file_name, h->file_name_len) == 0
|
||||
&& ISSLASH (file_name[h->file_name_len])
|
||||
&& (last_component (file_name) == file_name + h->file_name_len + 1))
|
||||
if ((h = find_direct_ancestor (file_name)) != NULL)
|
||||
mark_after_links (h);
|
||||
|
||||
return 0;
|
||||
@@ -1312,12 +1466,16 @@ extract_link (char *file_name, int typeflag)
|
||||
bool interdir_made = false;
|
||||
char const *link_name;
|
||||
int rc;
|
||||
|
||||
struct delayed_link *dl;
|
||||
|
||||
link_name = current_stat_info.link_name;
|
||||
|
||||
if (! absolute_names_option && contains_dot_dot (link_name))
|
||||
return create_placeholder_file (file_name, false, &interdir_made);
|
||||
|
||||
return create_placeholder_file (file_name, false, &interdir_made, NULL);
|
||||
dl = find_delayed_link_source (link_name);
|
||||
if (dl)
|
||||
return create_placeholder_file (file_name, false, &interdir_made, dl);
|
||||
|
||||
do
|
||||
{
|
||||
struct stat st1, st2;
|
||||
@@ -1379,7 +1537,7 @@ extract_symlink (char *file_name, int typeflag)
|
||||
if (! absolute_names_option
|
||||
&& (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name)
|
||||
|| contains_dot_dot (current_stat_info.link_name)))
|
||||
return create_placeholder_file (file_name, true, &interdir_made);
|
||||
return create_placeholder_file (file_name, true, &interdir_made, NULL);
|
||||
|
||||
while (symlinkat (current_stat_info.link_name, chdir_fd, file_name) != 0)
|
||||
switch (maybe_recoverable (file_name, false, &interdir_made))
|
||||
@@ -1472,47 +1630,23 @@ extract_fifo (char *file_name, int typeflag)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
extract_volhdr (char *file_name, int typeflag)
|
||||
{
|
||||
skip_member ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extract_failure (char *file_name, int typeflag)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
extract_skip (char *file_name, int typeflag)
|
||||
{
|
||||
skip_member ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*tar_extractor_t) (char *file_name, int typeflag);
|
||||
|
||||
|
||||
|
||||
/* Prepare to extract a file. Find extractor function.
|
||||
Return zero if extraction should not proceed. */
|
||||
Return true to proceed with the extraction, false to skip the current
|
||||
member. */
|
||||
|
||||
static int
|
||||
static bool
|
||||
prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (EXTRACT_OVER_PIPE)
|
||||
rc = 0;
|
||||
tar_extractor_t extractor = NULL;
|
||||
|
||||
/* Select the extractor */
|
||||
switch (typeflag)
|
||||
{
|
||||
case GNUTYPE_SPARSE:
|
||||
*fun = extract_file;
|
||||
rc = 1;
|
||||
extractor = extract_file;
|
||||
break;
|
||||
|
||||
case AREGTYPE:
|
||||
@@ -1521,106 +1655,106 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
/* Appears to be a file. But BSD tar uses the convention that a slash
|
||||
suffix means a directory. */
|
||||
if (current_stat_info.had_trailing_slash)
|
||||
*fun = extract_dir;
|
||||
extractor = extract_dir;
|
||||
else
|
||||
{
|
||||
*fun = extract_file;
|
||||
rc = 1;
|
||||
}
|
||||
extractor = extract_file;
|
||||
break;
|
||||
|
||||
case SYMTYPE:
|
||||
*fun = extract_symlink;
|
||||
extractor = extract_symlink;
|
||||
break;
|
||||
|
||||
case LNKTYPE:
|
||||
*fun = extract_link;
|
||||
extractor = extract_link;
|
||||
break;
|
||||
|
||||
#if S_IFCHR
|
||||
case CHRTYPE:
|
||||
current_stat_info.stat.st_mode |= S_IFCHR;
|
||||
*fun = extract_node;
|
||||
extractor = extract_node;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if S_IFBLK
|
||||
case BLKTYPE:
|
||||
current_stat_info.stat.st_mode |= S_IFBLK;
|
||||
*fun = extract_node;
|
||||
extractor = extract_node;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if HAVE_MKFIFO || defined mkfifo
|
||||
case FIFOTYPE:
|
||||
*fun = extract_fifo;
|
||||
extractor = extract_fifo;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case DIRTYPE:
|
||||
case GNUTYPE_DUMPDIR:
|
||||
*fun = extract_dir;
|
||||
extractor = extract_dir;
|
||||
if (current_stat_info.is_dumpdir)
|
||||
delay_directory_restore_option = true;
|
||||
break;
|
||||
|
||||
case GNUTYPE_VOLHDR:
|
||||
*fun = extract_volhdr;
|
||||
break;
|
||||
|
||||
return false;
|
||||
|
||||
case GNUTYPE_MULTIVOL:
|
||||
ERROR ((0, 0,
|
||||
_("%s: Cannot extract -- file is continued from another volume"),
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
*fun = extract_skip;
|
||||
break;
|
||||
return false;
|
||||
|
||||
case GNUTYPE_LONGNAME:
|
||||
case GNUTYPE_LONGLINK:
|
||||
ERROR ((0, 0, _("Unexpected long name header")));
|
||||
*fun = extract_failure;
|
||||
break;
|
||||
return false;
|
||||
|
||||
default:
|
||||
WARNOPT (WARN_UNKNOWN_CAST,
|
||||
(0, 0,
|
||||
_("%s: Unknown file type '%c', extracted as normal file"),
|
||||
quotearg_colon (file_name), typeflag));
|
||||
*fun = extract_file;
|
||||
extractor = extract_file;
|
||||
}
|
||||
|
||||
/* Determine whether the extraction should proceed */
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
|
||||
switch (old_files_option)
|
||||
if (EXTRACT_OVER_PIPE)
|
||||
{
|
||||
case UNLINK_FIRST_OLD_FILES:
|
||||
if (!remove_any_file (file_name,
|
||||
recursive_unlink_option ? RECURSIVE_REMOVE_OPTION
|
||||
: ORDINARY_REMOVE_OPTION)
|
||||
&& errno && errno != ENOENT)
|
||||
{
|
||||
unlink_error (file_name);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEEP_NEWER_FILES:
|
||||
if (file_newer_p (file_name, 0, ¤t_stat_info))
|
||||
{
|
||||
WARNOPT (WARN_IGNORE_NEWER,
|
||||
(0, 0, _("Current %s is newer or same age"),
|
||||
quote (file_name)));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
if (extractor != extract_file)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (old_files_option)
|
||||
{
|
||||
case UNLINK_FIRST_OLD_FILES:
|
||||
if (!remove_any_file (file_name,
|
||||
recursive_unlink_option
|
||||
? RECURSIVE_REMOVE_OPTION
|
||||
: ORDINARY_REMOVE_OPTION)
|
||||
&& errno && errno != ENOENT)
|
||||
{
|
||||
unlink_error (file_name);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
return 1;
|
||||
case KEEP_NEWER_FILES:
|
||||
if (file_newer_p (file_name, 0, ¤t_stat_info))
|
||||
{
|
||||
WARNOPT (WARN_IGNORE_NEWER,
|
||||
(0, 0, _("Current %s is newer or same age"),
|
||||
quote (file_name)));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*fun = extractor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Extract a file from the archive. */
|
||||
@@ -1629,12 +1763,20 @@ extract_archive (void)
|
||||
{
|
||||
char typeflag;
|
||||
tar_extractor_t fun;
|
||||
bool skip_dotdot_name;
|
||||
|
||||
fatal_exit_hook = extract_finish;
|
||||
|
||||
set_next_block_after (current_header);
|
||||
|
||||
skip_dotdot_name = (!absolute_names_option
|
||||
&& contains_dot_dot (current_stat_info.orig_file_name));
|
||||
if (skip_dotdot_name)
|
||||
ERROR ((0, 0, _("%s: Member name contains '..'"),
|
||||
quotearg_colon (current_stat_info.orig_file_name)));
|
||||
|
||||
if (!current_stat_info.file_name[0]
|
||||
|| skip_dotdot_name
|
||||
|| (interactive_option
|
||||
&& !confirm ("extract", current_stat_info.file_name)))
|
||||
{
|
||||
@@ -1675,13 +1817,14 @@ extract_archive (void)
|
||||
|
||||
if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun))
|
||||
{
|
||||
if (fun && (*fun) (current_stat_info.file_name, typeflag)
|
||||
&& backup_option)
|
||||
undo_last_backup ();
|
||||
if (fun (current_stat_info.file_name, typeflag) == 0)
|
||||
return;
|
||||
}
|
||||
else
|
||||
skip_member ();
|
||||
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
}
|
||||
|
||||
/* Extract the links whose final extraction were delayed. */
|
||||
@@ -1754,8 +1897,8 @@ apply_delayed_links (void)
|
||||
sources = next;
|
||||
}
|
||||
|
||||
xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
|
||||
free (ds->cntx_name);
|
||||
xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
|
||||
free (ds->cntx_name);
|
||||
|
||||
{
|
||||
struct delayed_link *next = ds->next;
|
||||
|
||||
115
src/incremen.c
115
src/incremen.c
@@ -1,7 +1,6 @@
|
||||
/* GNU dump extensions to tar.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2009,
|
||||
2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -39,7 +38,15 @@ enum children
|
||||
#define DIRF_FOUND 0x0004 /* directory is found on fs */
|
||||
#define DIRF_NEW 0x0008 /* directory is new (not found
|
||||
in the previous dump) */
|
||||
#define DIRF_RENAMED 0x0010 /* directory is renamed */
|
||||
#define DIRF_RENAMED 0x0010 /* Last target in a chain of renames */
|
||||
/* A directory which is renamed from another one is recognized by its
|
||||
orig member, which is not-NULL. This directory may eventually be
|
||||
the source for another rename, in which case it will be pointed to by
|
||||
the orig member of another directory structure. The last directory
|
||||
in such a chain of renames (the one which is not pointed to by any
|
||||
other orig) is marked with the DIRF_RENAMED flag. This marks a starting
|
||||
point from which append_incremental_renames starts encoding renames for
|
||||
this chain. */
|
||||
|
||||
#define DIR_IS_INITED(d) ((d)->flags & DIRF_INIT)
|
||||
#define DIR_IS_NFS(d) ((d)->flags & DIRF_NFS)
|
||||
@@ -496,6 +503,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
quote_n (1, d->name)));
|
||||
directory->orig = d;
|
||||
DIR_SET_FLAG (directory, DIRF_RENAMED);
|
||||
DIR_CLEAR_FLAG (d, DIRF_RENAMED);
|
||||
dirlist_replace_prefix (d->name, name_buffer);
|
||||
}
|
||||
directory->children = CHANGED_CHILDREN;
|
||||
@@ -538,6 +546,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
quote_n (1, d->name)));
|
||||
directory->orig = d;
|
||||
DIR_SET_FLAG (directory, DIRF_RENAMED);
|
||||
DIR_CLEAR_FLAG (d, DIRF_RENAMED);
|
||||
dirlist_replace_prefix (d->name, name_buffer);
|
||||
}
|
||||
directory->children = CHANGED_CHILDREN;
|
||||
@@ -650,7 +659,7 @@ makedumpdir (struct directory *directory, const char *dir)
|
||||
|
||||
if (directory->children == ALL_CHILDREN)
|
||||
dump = NULL;
|
||||
else if (DIR_IS_RENAMED (directory))
|
||||
else if (directory->orig)
|
||||
dump = directory->orig->idump ?
|
||||
directory->orig->idump : directory->orig->dump;
|
||||
else
|
||||
@@ -879,43 +888,36 @@ obstack_code_rename (struct obstack *stk, char const *from, char const *to)
|
||||
static void
|
||||
store_rename (struct directory *dir, struct obstack *stk)
|
||||
{
|
||||
if (DIR_IS_RENAMED (dir))
|
||||
struct directory *prev, *p;
|
||||
|
||||
/* Detect eventual cycles. If the chain forms a cycle, prev points to
|
||||
the entry DIR is renamed from.*/
|
||||
for (prev = dir; prev && prev->orig != dir; prev = prev->orig)
|
||||
;
|
||||
|
||||
if (prev == NULL)
|
||||
{
|
||||
struct directory *prev, *p;
|
||||
|
||||
/* Detect eventual cycles and clear DIRF_RENAMED flag, so these entries
|
||||
are ignored when hit by this function next time.
|
||||
If the chain forms a cycle, prev points to the entry DIR is renamed
|
||||
from. In this case it still retains DIRF_RENAMED flag, which will be
|
||||
cleared in the 'else' branch below */
|
||||
for (prev = dir; prev && prev->orig != dir; prev = prev->orig)
|
||||
DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
|
||||
|
||||
if (prev == NULL)
|
||||
{
|
||||
for (p = dir; p && p->orig; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *temp_name;
|
||||
|
||||
DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
|
||||
|
||||
/* Break the cycle by using a temporary name for one of its
|
||||
elements.
|
||||
First, create a temp name stub entry. */
|
||||
temp_name = dir_name (dir->name);
|
||||
obstack_1grow (stk, 'X');
|
||||
obstack_grow (stk, temp_name, strlen (temp_name) + 1);
|
||||
|
||||
obstack_code_rename (stk, dir->name, "");
|
||||
|
||||
for (p = dir; p != prev; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->name);
|
||||
|
||||
obstack_code_rename (stk, "", prev->name);
|
||||
}
|
||||
for (p = dir; p && p->orig; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *temp_name;
|
||||
|
||||
/* Break the cycle by using a temporary name for one of its
|
||||
elements.
|
||||
First, create a temp name stub entry. */
|
||||
temp_name = dir_name (dir->name);
|
||||
obstack_1grow (stk, 'X');
|
||||
obstack_grow (stk, temp_name, strlen (temp_name) + 1);
|
||||
|
||||
obstack_code_rename (stk, dir->name, "");
|
||||
|
||||
for (p = dir; p != prev; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->name);
|
||||
|
||||
obstack_code_rename (stk, "", prev->name);
|
||||
free (temp_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -941,7 +943,8 @@ append_incremental_renames (struct directory *dir)
|
||||
size = 0;
|
||||
|
||||
for (dp = dirhead; dp; dp = dp->next)
|
||||
store_rename (dp, &stk);
|
||||
if (DIR_IS_RENAMED (dp))
|
||||
store_rename (dp, &stk);
|
||||
|
||||
/* FIXME: Is this the right thing to do when DIR is null? */
|
||||
if (dir && obstack_object_size (&stk) != size)
|
||||
@@ -997,10 +1000,10 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
newer_mtime_option = decode_timespec (buf, &ebuf, false);
|
||||
|
||||
if (! valid_timespec (newer_mtime_option))
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option),
|
||||
lineno,
|
||||
_("Invalid time stamp")));
|
||||
FATAL_ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option),
|
||||
lineno,
|
||||
_("Invalid time stamp")));
|
||||
else
|
||||
{
|
||||
if (version == 1 && *ebuf)
|
||||
@@ -1042,9 +1045,9 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
mtime = decode_timespec (strp, &ebuf, false);
|
||||
strp = ebuf;
|
||||
if (!valid_timespec (mtime) || *strp != ' ')
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time")));
|
||||
FATAL_ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time")));
|
||||
|
||||
errno = 0;
|
||||
u = strtoumax (strp, &ebuf, 10);
|
||||
@@ -1052,9 +1055,9 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
errno = ERANGE;
|
||||
if (errno || strp == ebuf || *ebuf != ' ')
|
||||
{
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time (nanoseconds)")));
|
||||
FATAL_ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time (nanoseconds)")));
|
||||
mtime.tv_nsec = -1;
|
||||
}
|
||||
else
|
||||
@@ -1068,17 +1071,17 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t));
|
||||
strp = ebuf;
|
||||
if (errno || *strp != ' ')
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
FATAL_ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid device number")));
|
||||
_("Invalid device number")));
|
||||
|
||||
ino = strtosysint (strp, &ebuf,
|
||||
TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t));
|
||||
strp = ebuf;
|
||||
if (errno || *strp != ' ')
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid inode number")));
|
||||
FATAL_ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid inode number")));
|
||||
|
||||
strp++;
|
||||
unquote_string (strp);
|
||||
|
||||
74
src/list.c
74
src/list.c
@@ -1,7 +1,6 @@
|
||||
/* List a tar archive, with support routines for reading a tar archive.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2016 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -23,7 +22,7 @@
|
||||
#include <system.h>
|
||||
#include <inttostr.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include <time.h>
|
||||
#include "common.h"
|
||||
|
||||
union block *current_header; /* points to current archive header */
|
||||
@@ -120,7 +119,7 @@ enforce_one_top_level (char **pfile_name)
|
||||
{
|
||||
char *file_name = *pfile_name;
|
||||
char *p;
|
||||
|
||||
|
||||
for (p = file_name; *p && (ISSLASH (*p) || *p == '.'); p++)
|
||||
;
|
||||
|
||||
@@ -132,7 +131,7 @@ enforce_one_top_level (char **pfile_name)
|
||||
if (ISSLASH (p[pos]) || p[pos] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
*pfile_name = make_file_name (one_top_level_dir, file_name);
|
||||
normalize_filename_x (*pfile_name);
|
||||
}
|
||||
@@ -218,7 +217,7 @@ read_and (void (*do_something) (void))
|
||||
if (show_omitted_dirs_option)
|
||||
WARN ((0, 0, _("%s: Omitting"),
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
skip_member ();
|
||||
continue;
|
||||
@@ -273,8 +272,7 @@ read_and (void (*do_something) (void))
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
ERROR ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_ZERO_BLOCK:
|
||||
case HEADER_SUCCESS:
|
||||
if (block_number_option)
|
||||
@@ -410,26 +408,27 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
enum read_header_mode mode)
|
||||
{
|
||||
union block *header;
|
||||
union block *header_copy;
|
||||
char *bp;
|
||||
union block *data_block;
|
||||
size_t size, written;
|
||||
union block *next_long_name = 0;
|
||||
union block *next_long_link = 0;
|
||||
union block *next_long_name = NULL;
|
||||
union block *next_long_link = NULL;
|
||||
size_t next_long_name_blocks = 0;
|
||||
size_t next_long_link_blocks = 0;
|
||||
|
||||
enum read_header status = HEADER_SUCCESS;
|
||||
|
||||
while (1)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
header = find_next_block ();
|
||||
*return_block = header;
|
||||
if (!header)
|
||||
return HEADER_END_OF_FILE;
|
||||
{
|
||||
status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
|
||||
return status;
|
||||
break;
|
||||
|
||||
/* Good block. Decode file size and return. */
|
||||
|
||||
@@ -439,7 +438,10 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
{
|
||||
info->stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
if (info->stat.st_size < 0)
|
||||
return HEADER_FAILURE;
|
||||
{
|
||||
status = HEADER_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
@@ -449,10 +451,14 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
|| header->header.typeflag == SOLARIS_XHDTYPE)
|
||||
{
|
||||
if (mode == read_header_x_raw)
|
||||
return HEADER_SUCCESS_EXTENDED;
|
||||
{
|
||||
status = HEADER_SUCCESS_EXTENDED;
|
||||
break;
|
||||
}
|
||||
else if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
||||
{
|
||||
union block *header_copy;
|
||||
size_t name_size = info->stat.st_size;
|
||||
size_t n = name_size % BLOCKSIZE;
|
||||
size = name_size + BLOCKSIZE;
|
||||
@@ -519,7 +525,10 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
xheader_decode_global (&xhdr);
|
||||
xheader_destroy (&xhdr);
|
||||
if (mode == read_header_x_global)
|
||||
return HEADER_SUCCESS_EXTENDED;
|
||||
{
|
||||
status = HEADER_SUCCESS_EXTENDED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop! */
|
||||
@@ -538,6 +547,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
name = next_long_name->buffer + BLOCKSIZE;
|
||||
recent_long_name = next_long_name;
|
||||
recent_long_name_blocks = next_long_name_blocks;
|
||||
next_long_name = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -569,6 +579,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
name = next_long_link->buffer + BLOCKSIZE;
|
||||
recent_long_link = next_long_link;
|
||||
recent_long_link_blocks = next_long_link_blocks;
|
||||
next_long_link = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -580,9 +591,12 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
}
|
||||
assign_string (&info->link_name, name);
|
||||
|
||||
return HEADER_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (next_long_name);
|
||||
free (next_long_link);
|
||||
return status;
|
||||
}
|
||||
|
||||
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
|
||||
@@ -632,10 +646,12 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
stat_info->stat.st_mode = mode;
|
||||
stat_info->mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
|
||||
stat_info->mtime.tv_nsec = 0;
|
||||
assign_string (&stat_info->uname,
|
||||
header->header.uname[0] ? header->header.uname : NULL);
|
||||
assign_string (&stat_info->gname,
|
||||
header->header.gname[0] ? header->header.gname : NULL);
|
||||
assign_string_n (&stat_info->uname,
|
||||
header->header.uname[0] ? header->header.uname : NULL,
|
||||
sizeof (header->header.uname));
|
||||
assign_string_n (&stat_info->gname,
|
||||
header->header.gname[0] ? header->header.gname : NULL,
|
||||
sizeof (header->header.gname));
|
||||
|
||||
xheader_xattr_init (stat_info);
|
||||
|
||||
@@ -1050,15 +1066,11 @@ tartime (struct timespec t, bool full_time)
|
||||
{
|
||||
if (full_time)
|
||||
{
|
||||
sprintf (buffer, "%04ld-%02d-%02d %02d:%02d:%02d",
|
||||
tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
strftime (buffer, sizeof buffer, "%Y-%m-%d %H:%M:%S", tm);
|
||||
code_ns_fraction (ns, buffer + strlen (buffer));
|
||||
}
|
||||
else
|
||||
sprintf (buffer, "%04ld-%02d-%02d %02d:%02d",
|
||||
tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min);
|
||||
strftime (buffer, sizeof buffer, "%Y-%m-%d %H:%M", tm);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -1444,7 +1456,7 @@ test_archive_label (void)
|
||||
decode_header (current_header,
|
||||
¤t_stat_info, ¤t_format, 0);
|
||||
if (current_header->header.typeflag == GNUTYPE_VOLHDR)
|
||||
assign_string (&volume_label, current_header->header.name);
|
||||
ASSIGN_STRING_N (&volume_label, current_header->header.name);
|
||||
|
||||
if (volume_label)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Owner/group mapping for tar
|
||||
|
||||
Copyright 2015-2016 Free Software Foundation, Inc.
|
||||
Copyright 2015-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
121
src/misc.c
121
src/misc.c
@@ -1,7 +1,6 @@
|
||||
/* Miscellaneous functions, not really specific to GNU tar.
|
||||
|
||||
Copyright 1988, 1992, 1994-1997, 1999-2001, 2003-2007, 2009-2010,
|
||||
2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 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
|
||||
@@ -33,6 +32,11 @@ static void namebuf_add_dir (namebuf_t, char const *);
|
||||
static char *namebuf_finish (namebuf_t);
|
||||
static const char *tar_getcdpath (int);
|
||||
|
||||
char const *
|
||||
quote_n_colon (int n, char const *arg)
|
||||
{
|
||||
return quotearg_n_style_colon (n, get_quoting_style (NULL), arg);
|
||||
}
|
||||
|
||||
/* Handling strings. */
|
||||
|
||||
@@ -45,6 +49,20 @@ assign_string (char **string, const char *value)
|
||||
*string = value ? xstrdup (value) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
assign_string_n (char **string, const char *value, size_t n)
|
||||
{
|
||||
free (*string);
|
||||
if (value)
|
||||
{
|
||||
size_t l = strnlen (value, n);
|
||||
char *p = xmalloc (l + 1);
|
||||
memcpy (p, value, l);
|
||||
p[l] = 0;
|
||||
*string = p;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This function is currently unused; perhaps it should be removed? */
|
||||
|
||||
@@ -296,8 +314,6 @@ normalize_filename (int cdidx, const char *name)
|
||||
size_t copylen;
|
||||
bool need_separator;
|
||||
|
||||
if (!cdpath)
|
||||
call_arg_fatal ("getcwd", ".");
|
||||
copylen = strlen (cdpath);
|
||||
need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT
|
||||
&& copylen == 2 && ISSLASH (cdpath[1]));
|
||||
@@ -722,7 +738,7 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
&& (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
|
||||
return true;
|
||||
|
||||
after_backup_name = find_backup_file_name (file_name, backup_type);
|
||||
after_backup_name = find_backup_file_name (chdir_fd, file_name, backup_type);
|
||||
if (! after_backup_name)
|
||||
xalloc_die ();
|
||||
|
||||
@@ -892,8 +908,6 @@ chdir_count (void)
|
||||
int
|
||||
chdir_arg (char const *dir)
|
||||
{
|
||||
char *absdir;
|
||||
|
||||
if (wd_count == wd_alloc)
|
||||
{
|
||||
if (wd_alloc == 0)
|
||||
@@ -903,7 +917,7 @@ chdir_arg (char const *dir)
|
||||
if (! wd_count)
|
||||
{
|
||||
wd[wd_count].name = ".";
|
||||
wd[wd_count].abspath = xgetcwd ();
|
||||
wd[wd_count].abspath = NULL;
|
||||
wd[wd_count].fd = AT_FDCWD;
|
||||
wd_count++;
|
||||
}
|
||||
@@ -920,22 +934,8 @@ chdir_arg (char const *dir)
|
||||
return wd_count - 1;
|
||||
}
|
||||
|
||||
|
||||
/* If the given name is absolute, use it to represent this directory;
|
||||
otherwise, construct a name based on the previous -C option. */
|
||||
if (IS_ABSOLUTE_FILE_NAME (dir))
|
||||
absdir = xstrdup (dir);
|
||||
else if (wd[wd_count - 1].abspath)
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath);
|
||||
namebuf_add_dir (nbuf, dir);
|
||||
absdir = namebuf_finish (nbuf);
|
||||
}
|
||||
else
|
||||
absdir = 0;
|
||||
|
||||
wd[wd_count].name = dir;
|
||||
wd[wd_count].abspath = absdir;
|
||||
wd[wd_count].abspath = NULL;
|
||||
wd[wd_count].fd = 0;
|
||||
return wd_count++;
|
||||
}
|
||||
@@ -1029,9 +1029,47 @@ tar_getcdpath (int idx)
|
||||
{
|
||||
static char *cwd;
|
||||
if (!cwd)
|
||||
cwd = xgetcwd ();
|
||||
{
|
||||
cwd = xgetcwd ();
|
||||
if (!cwd)
|
||||
call_arg_fatal ("getcwd", ".");
|
||||
}
|
||||
return cwd;
|
||||
}
|
||||
|
||||
if (!wd[idx].abspath)
|
||||
{
|
||||
int i;
|
||||
int save_cwdi = chdir_current;
|
||||
|
||||
for (i = idx; i >= 0; i--)
|
||||
if (wd[i].abspath)
|
||||
break;
|
||||
|
||||
while (++i <= idx)
|
||||
{
|
||||
chdir_do (i);
|
||||
if (i == 0)
|
||||
{
|
||||
if ((wd[i].abspath = xgetcwd ()) == NULL)
|
||||
call_arg_fatal ("getcwd", ".");
|
||||
}
|
||||
else if (IS_ABSOLUTE_FILE_NAME (wd[i].name))
|
||||
/* If the given name is absolute, use it to represent this
|
||||
directory; otherwise, construct a name based on the
|
||||
previous -C option. */
|
||||
wd[i].abspath = xstrdup (wd[i].name);
|
||||
else
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (wd[i - 1].abspath);
|
||||
namebuf_add_dir (nbuf, wd[i].name);
|
||||
wd[i].abspath = namebuf_finish (nbuf);
|
||||
}
|
||||
}
|
||||
|
||||
chdir_do (save_cwdi);
|
||||
}
|
||||
|
||||
return wd[idx].abspath;
|
||||
}
|
||||
|
||||
@@ -1039,7 +1077,10 @@ void
|
||||
close_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
close_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
close_warn (name);
|
||||
}
|
||||
else
|
||||
close_error (name);
|
||||
}
|
||||
@@ -1048,7 +1089,10 @@ void
|
||||
open_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
open_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
open_warn (name);
|
||||
}
|
||||
else
|
||||
open_error (name);
|
||||
}
|
||||
@@ -1057,7 +1101,10 @@ void
|
||||
read_diag_details (char const *name, off_t offset, size_t size)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
read_warn_details (name, offset, size);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
read_warn_details (name, offset, size);
|
||||
}
|
||||
else
|
||||
read_error_details (name, offset, size);
|
||||
}
|
||||
@@ -1066,7 +1113,10 @@ void
|
||||
readlink_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
readlink_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
readlink_warn (name);
|
||||
}
|
||||
else
|
||||
readlink_error (name);
|
||||
}
|
||||
@@ -1075,7 +1125,10 @@ void
|
||||
savedir_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
savedir_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
savedir_warn (name);
|
||||
}
|
||||
else
|
||||
savedir_error (name);
|
||||
}
|
||||
@@ -1084,7 +1137,10 @@ void
|
||||
seek_diag_details (char const *name, off_t offset)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
seek_warn_details (name, offset);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
seek_warn_details (name, offset);
|
||||
}
|
||||
else
|
||||
seek_error_details (name, offset);
|
||||
}
|
||||
@@ -1093,7 +1149,10 @@ void
|
||||
stat_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
stat_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
stat_warn (name);
|
||||
}
|
||||
else
|
||||
stat_error (name);
|
||||
}
|
||||
|
||||
375
src/names.c
375
src/names.c
@@ -1,7 +1,6 @@
|
||||
/* Various processing of names.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996-2001, 2003-2007, 2009, 2013-2016
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 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
|
||||
@@ -32,7 +31,8 @@ static void name_add_file (const char *name);
|
||||
|
||||
enum
|
||||
{
|
||||
EXCLUDE_BACKUPS_OPTION = 256,
|
||||
ADD_FILE_OPTION = 256,
|
||||
EXCLUDE_BACKUPS_OPTION,
|
||||
EXCLUDE_CACHES_OPTION,
|
||||
EXCLUDE_CACHES_UNDER_OPTION,
|
||||
EXCLUDE_CACHES_ALL_OPTION,
|
||||
@@ -62,104 +62,121 @@ enum
|
||||
WILDCARDS_OPTION
|
||||
};
|
||||
|
||||
static struct argp_option names_options[] = {
|
||||
#define GRID 100
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("Local file name selection:"), GRID },
|
||||
enum
|
||||
{
|
||||
GRH_LOCAL,
|
||||
GRID_LOCAL,
|
||||
GRH_MATCH,
|
||||
GRID_MATCH,
|
||||
};
|
||||
|
||||
{"add-file", ARGP_KEY_ARG, N_("FILE"), 0,
|
||||
N_("add given FILE to the archive (useful if its name starts with a dash)"), GRID+1 },
|
||||
static struct argp_option names_options[] = {
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("Local file name selection:"), GRH_LOCAL },
|
||||
|
||||
{"add-file", ADD_FILE_OPTION, N_("FILE"), 0,
|
||||
N_("add given FILE to the archive (useful if its name starts with a dash)"), GRID_LOCAL },
|
||||
{"directory", 'C', N_("DIR"), 0,
|
||||
N_("change to directory DIR"), GRID+1 },
|
||||
N_("change to directory DIR"), GRID_LOCAL },
|
||||
{"files-from", 'T', N_("FILE"), 0,
|
||||
N_("get names to extract or create from FILE"), GRID+1 },
|
||||
N_("get names to extract or create from FILE"), GRID_LOCAL },
|
||||
{"null", NULL_OPTION, 0, 0,
|
||||
N_("-T reads null-terminated names; implies --verbatim-files-from"),
|
||||
GRID+1 },
|
||||
GRID_LOCAL },
|
||||
{"no-null", NO_NULL_OPTION, 0, 0,
|
||||
N_("disable the effect of the previous --null option"), GRID+1 },
|
||||
N_("disable the effect of the previous --null option"), GRID_LOCAL },
|
||||
{"unquote", UNQUOTE_OPTION, 0, 0,
|
||||
N_("unquote input file or member names (default)"), GRID+1 },
|
||||
N_("unquote input file or member names (default)"), GRID_LOCAL },
|
||||
{"no-unquote", NO_UNQUOTE_OPTION, 0, 0,
|
||||
N_("do not unquote input file or member names"), GRID+1 },
|
||||
N_("do not unquote input file or member names"), GRID_LOCAL },
|
||||
{"verbatim-files-from", VERBATIM_FILES_FROM_OPTION, 0, 0,
|
||||
N_("-T reads file names verbatim (no option handling)"), GRID+1 },
|
||||
N_("-T reads file names verbatim (no escape or option handling)"), GRID_LOCAL },
|
||||
{"no-verbatim-files-from", NO_VERBATIM_FILES_FROM_OPTION, 0, 0,
|
||||
N_("-T treats file names starting with dash as options (default)"),
|
||||
GRID+1 },
|
||||
GRID_LOCAL },
|
||||
{"exclude", EXCLUDE_OPTION, N_("PATTERN"), 0,
|
||||
N_("exclude files, given as a PATTERN"), GRID+1 },
|
||||
N_("exclude files, given as a PATTERN"), GRID_LOCAL },
|
||||
{"exclude-from", 'X', N_("FILE"), 0,
|
||||
N_("exclude patterns listed in FILE"), GRID+1 },
|
||||
N_("exclude patterns listed in FILE"), GRID_LOCAL },
|
||||
{"exclude-caches", EXCLUDE_CACHES_OPTION, 0, 0,
|
||||
N_("exclude contents of directories containing CACHEDIR.TAG, "
|
||||
"except for the tag file itself"), GRID+1 },
|
||||
"except for the tag file itself"), GRID_LOCAL },
|
||||
{"exclude-caches-under", EXCLUDE_CACHES_UNDER_OPTION, 0, 0,
|
||||
N_("exclude everything under directories containing CACHEDIR.TAG"),
|
||||
GRID+1 },
|
||||
GRID_LOCAL },
|
||||
{"exclude-caches-all", EXCLUDE_CACHES_ALL_OPTION, 0, 0,
|
||||
N_("exclude directories containing CACHEDIR.TAG"), GRID+1 },
|
||||
N_("exclude directories containing CACHEDIR.TAG"), GRID_LOCAL },
|
||||
{"exclude-tag", EXCLUDE_TAG_OPTION, N_("FILE"), 0,
|
||||
N_("exclude contents of directories containing FILE, except"
|
||||
" for FILE itself"), GRID+1 },
|
||||
" for FILE itself"), GRID_LOCAL },
|
||||
{"exclude-ignore", EXCLUDE_IGNORE_OPTION, N_("FILE"), 0,
|
||||
N_("read exclude patterns for each directory from FILE, if it exists"),
|
||||
GRID+1 },
|
||||
GRID_LOCAL },
|
||||
{"exclude-ignore-recursive", EXCLUDE_IGNORE_RECURSIVE_OPTION, N_("FILE"), 0,
|
||||
N_("read exclude patterns for each directory and its subdirectories "
|
||||
"from FILE, if it exists"), GRID+1 },
|
||||
"from FILE, if it exists"), GRID_LOCAL },
|
||||
{"exclude-tag-under", EXCLUDE_TAG_UNDER_OPTION, N_("FILE"), 0,
|
||||
N_("exclude everything under directories containing FILE"), GRID+1 },
|
||||
N_("exclude everything under directories containing FILE"), GRID_LOCAL },
|
||||
{"exclude-tag-all", EXCLUDE_TAG_ALL_OPTION, N_("FILE"), 0,
|
||||
N_("exclude directories containing FILE"), GRID+1 },
|
||||
N_("exclude directories containing FILE"), GRID_LOCAL },
|
||||
{"exclude-vcs", EXCLUDE_VCS_OPTION, NULL, 0,
|
||||
N_("exclude version control system directories"), GRID+1 },
|
||||
N_("exclude version control system directories"), GRID_LOCAL },
|
||||
{"exclude-vcs-ignores", EXCLUDE_VCS_IGNORES_OPTION, NULL, 0,
|
||||
N_("read exclude patterns from the VCS ignore files"), GRID+1 },
|
||||
N_("read exclude patterns from the VCS ignore files"), GRID_LOCAL },
|
||||
{"exclude-backups", EXCLUDE_BACKUPS_OPTION, NULL, 0,
|
||||
N_("exclude backup and lock files"), GRID+1 },
|
||||
N_("exclude backup and lock files"), GRID_LOCAL },
|
||||
{"recursion", RECURSION_OPTION, 0, 0,
|
||||
N_("recurse into directories (default)"), GRID+1 },
|
||||
N_("recurse into directories (default)"), GRID_LOCAL },
|
||||
{"no-recursion", NO_RECURSION_OPTION, 0, 0,
|
||||
N_("avoid descending automatically in directories"), GRID+1 },
|
||||
#undef GRID
|
||||
N_("avoid descending automatically in directories"), GRID_LOCAL },
|
||||
|
||||
#define GRID 120
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("File name matching options (affect both exclude and include patterns):"),
|
||||
GRID },
|
||||
GRH_MATCH },
|
||||
{"anchored", ANCHORED_OPTION, 0, 0,
|
||||
N_("patterns match file name start"), GRID+1 },
|
||||
N_("patterns match file name start"), GRID_MATCH },
|
||||
{"no-anchored", NO_ANCHORED_OPTION, 0, 0,
|
||||
N_("patterns match after any '/' (default for exclusion)"), GRID+1 },
|
||||
N_("patterns match after any '/' (default for exclusion)"), GRID_MATCH },
|
||||
{"ignore-case", IGNORE_CASE_OPTION, 0, 0,
|
||||
N_("ignore case"), GRID+1 },
|
||||
N_("ignore case"), GRID_MATCH },
|
||||
{"no-ignore-case", NO_IGNORE_CASE_OPTION, 0, 0,
|
||||
N_("case sensitive matching (default)"), GRID+1 },
|
||||
N_("case sensitive matching (default)"), GRID_MATCH },
|
||||
{"wildcards", WILDCARDS_OPTION, 0, 0,
|
||||
N_("use wildcards (default for exclusion)"), GRID+1 },
|
||||
N_("use wildcards (default for exclusion)"), GRID_MATCH },
|
||||
{"no-wildcards", NO_WILDCARDS_OPTION, 0, 0,
|
||||
N_("verbatim string matching"), GRID+1 },
|
||||
N_("verbatim string matching"), GRID_MATCH },
|
||||
{"wildcards-match-slash", WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
|
||||
N_("wildcards match '/' (default for exclusion)"), GRID+1 },
|
||||
N_("wildcards match '/' (default for exclusion)"), GRID_MATCH },
|
||||
{"no-wildcards-match-slash", NO_WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
|
||||
N_("wildcards do not match '/'"), GRID+1 },
|
||||
#undef GRID
|
||||
|
||||
N_("wildcards do not match '/'"), GRID_MATCH },
|
||||
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static bool
|
||||
is_file_selection_option (int key)
|
||||
static struct argp_option const *
|
||||
file_selection_option (int key)
|
||||
{
|
||||
struct argp_option *p;
|
||||
|
||||
for (p = names_options;
|
||||
!(p->name == NULL && p->key == 0 && p->doc == NULL); p++)
|
||||
if (p->key == key)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char const *
|
||||
file_selection_option_name (int key)
|
||||
{
|
||||
struct argp_option const *opt = file_selection_option (key);
|
||||
return opt ? opt->name : NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_file_selection_option (int key)
|
||||
{
|
||||
return file_selection_option (key) != NULL;
|
||||
}
|
||||
|
||||
/* Either NL or NUL, as decided by the --null option. */
|
||||
static char filename_terminator = '\n';
|
||||
@@ -177,17 +194,30 @@ names_parse_opt (int key, char *arg, struct argp_state *state)
|
||||
|
||||
case 'T':
|
||||
name_add_file (arg);
|
||||
/* Indicate we've been given -T option. This is for backward
|
||||
compatibility only, so that `tar cfT archive /dev/null will
|
||||
succeed */
|
||||
files_from_option = true;
|
||||
break;
|
||||
|
||||
case ADD_FILE_OPTION:
|
||||
name_add_name (arg);
|
||||
break;
|
||||
|
||||
case ARGP_KEY_ERROR:
|
||||
{
|
||||
struct tar_args *args = state->input;
|
||||
if (args->loc->source == OPTS_FILE)
|
||||
{
|
||||
error (0, 0, _("%s:%lu: unrecognized option"), args->loc->name,
|
||||
(unsigned long) args->loc->line);
|
||||
set_exit_status (TAREXIT_FAILURE);
|
||||
}
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
default:
|
||||
if (is_file_selection_option (key))
|
||||
name_add_option (key, arg);
|
||||
else
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -207,7 +237,7 @@ static int matching_flags = 0;
|
||||
/* exclude_fnmatch options */
|
||||
static int include_anchored = EXCLUDE_ANCHORED;
|
||||
/* Pattern anchoring options used for file inclusion */
|
||||
|
||||
|
||||
#define EXCLUDE_OPTIONS \
|
||||
(((wildcards != disable_wildcards) ? EXCLUDE_WILDCARDS : 0) \
|
||||
| matching_flags \
|
||||
@@ -406,7 +436,7 @@ handle_file_selection_option (int key, const char *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static struct argp names_argp = {
|
||||
struct argp names_argp = {
|
||||
names_options,
|
||||
names_parse_opt,
|
||||
NULL,
|
||||
@@ -416,10 +446,6 @@ static struct argp names_argp = {
|
||||
NULL
|
||||
};
|
||||
|
||||
struct argp_child names_argp_children[] = {
|
||||
{ &names_argp, 0, "", 0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* User and group names. */
|
||||
|
||||
@@ -638,8 +664,10 @@ struct name_elt /* A name_array element. */
|
||||
} v;
|
||||
};
|
||||
|
||||
static struct name_elt *name_head; /* store a list of names */
|
||||
size_t name_count; /* how many of the entries are names? */
|
||||
static struct name_elt *name_head; /* store a list of names */
|
||||
|
||||
/* how many of the entries are file names? */
|
||||
enum files_count filename_args = FILES_NONE;
|
||||
|
||||
static struct name_elt *
|
||||
name_elt_alloc (void)
|
||||
@@ -670,7 +698,86 @@ name_list_adjust (void)
|
||||
while (name_head->prev)
|
||||
name_head = name_head->prev;
|
||||
}
|
||||
|
||||
/* For error-reporting purposes, keep a doubly-linked list of unconsumed file
|
||||
selection options. The option is deemed unconsumed unless followed by one
|
||||
or more file/member name arguments. When archive creation is requested,
|
||||
each file selection option encountered is pushed into the list. The list
|
||||
is cleared upon encountering a file name argument.
|
||||
|
||||
If the list is not empty when all arguments have been processed, an error
|
||||
message is issued reporting the options that had no effect.
|
||||
|
||||
For simplicity, only a tail pointer of the list is maintained.
|
||||
*/
|
||||
|
||||
struct name_elt *unconsumed_option_tail;
|
||||
|
||||
/* Push an option to the list */
|
||||
static void
|
||||
unconsumed_option_push (struct name_elt *elt)
|
||||
{
|
||||
elt->next = NULL;
|
||||
elt->prev = unconsumed_option_tail;
|
||||
if (unconsumed_option_tail)
|
||||
unconsumed_option_tail->next = elt;
|
||||
unconsumed_option_tail = elt;
|
||||
}
|
||||
|
||||
/* Clear the unconsumed option list */
|
||||
static void
|
||||
unconsumed_option_free (void)
|
||||
{
|
||||
while (unconsumed_option_tail)
|
||||
{
|
||||
struct name_elt *elt = unconsumed_option_tail;
|
||||
unconsumed_option_tail = unconsumed_option_tail->prev;
|
||||
free (elt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Report any options that have not been consumed */
|
||||
static void
|
||||
unconsumed_option_report (void)
|
||||
{
|
||||
if (unconsumed_option_tail)
|
||||
{
|
||||
struct name_elt *elt;
|
||||
|
||||
ERROR ((0, 0, _("The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.")));
|
||||
|
||||
elt = unconsumed_option_tail;
|
||||
while (elt->prev)
|
||||
elt = elt->prev;
|
||||
|
||||
while (elt)
|
||||
{
|
||||
switch (elt->type)
|
||||
{
|
||||
case NELT_CHDIR:
|
||||
ERROR ((0, 0, _("-C %s has no effect"), quote (elt->v.name)));
|
||||
break;
|
||||
|
||||
case NELT_OPTION:
|
||||
if (elt->v.opt.arg)
|
||||
ERROR ((0, 0, _("--%s %s has no effect"),
|
||||
file_selection_option_name (elt->v.opt.option),
|
||||
quote (elt->v.opt.arg)));
|
||||
else
|
||||
ERROR ((0, 0, _("--%s has no effect"),
|
||||
file_selection_option_name (elt->v.opt.option)));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
elt = elt->next;
|
||||
}
|
||||
|
||||
unconsumed_option_free ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
name_list_advance (void)
|
||||
{
|
||||
@@ -678,10 +785,20 @@ name_list_advance (void)
|
||||
name_head = elt->next;
|
||||
if (name_head)
|
||||
name_head->prev = NULL;
|
||||
free (elt);
|
||||
if (elt->type == NELT_OPTION || elt->type == NELT_CHDIR)
|
||||
{
|
||||
if (subcommand_option == CREATE_SUBCOMMAND
|
||||
|| subcommand_option == UPDATE_SUBCOMMAND)
|
||||
unconsumed_option_push (elt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (elt->type != NELT_NOOP)
|
||||
unconsumed_option_free ();
|
||||
free (elt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add to name_array the file NAME with fnmatch options MATFLAGS */
|
||||
void
|
||||
name_add_name (const char *name)
|
||||
@@ -690,7 +807,20 @@ name_add_name (const char *name)
|
||||
|
||||
ep->type = NELT_NAME;
|
||||
ep->v.name = name;
|
||||
name_count++;
|
||||
|
||||
switch (filename_args)
|
||||
{
|
||||
case FILES_NONE:
|
||||
filename_args = FILES_ONE;
|
||||
break;
|
||||
|
||||
case FILES_ONE:
|
||||
filename_args = FILES_MANY;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -720,6 +850,10 @@ name_add_file (const char *name)
|
||||
ep->v.file.name = name;
|
||||
ep->v.file.line = 0;
|
||||
ep->v.file.fp = NULL;
|
||||
|
||||
/* We don't know beforehand how many files are listed.
|
||||
Assume more than one. */
|
||||
filename_args = FILES_MANY;
|
||||
}
|
||||
|
||||
/* Names from external name file. */
|
||||
@@ -856,7 +990,7 @@ handle_option (const char *str, struct name_elt const *ent)
|
||||
struct wordsplit ws;
|
||||
int i;
|
||||
struct option_locus loc;
|
||||
|
||||
|
||||
while (*str && isspace (*str))
|
||||
++str;
|
||||
if (*str != '-')
|
||||
@@ -914,14 +1048,17 @@ read_next_name (struct name_elt *ent, struct name_elt *ret)
|
||||
(0, 0, N_("%s: file name read contains nul character"),
|
||||
quotearg_colon (ent->v.file.name)));
|
||||
ent->v.file.term = 0;
|
||||
/* fall through */
|
||||
FALLTHROUGH;
|
||||
case file_list_success:
|
||||
if (unquote_option)
|
||||
unquote_string (name_buffer);
|
||||
if (!ent->v.file.verbatim && handle_option (name_buffer, ent) == 0)
|
||||
if (!ent->v.file.verbatim)
|
||||
{
|
||||
name_list_adjust ();
|
||||
return 1;
|
||||
if (unquote_option)
|
||||
unquote_string (name_buffer);
|
||||
if (handle_option (name_buffer, ent) == 0)
|
||||
{
|
||||
name_list_adjust ();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
ret->type = NELT_NAME;
|
||||
ret->v.name = name_buffer;
|
||||
@@ -945,19 +1082,8 @@ copy_name (struct name_elt *ep)
|
||||
|
||||
source = ep->v.name;
|
||||
source_len = strlen (source);
|
||||
if (name_buffer_length < source_len)
|
||||
{
|
||||
do
|
||||
{
|
||||
name_buffer_length *= 2;
|
||||
if (! name_buffer_length)
|
||||
xalloc_die ();
|
||||
}
|
||||
while (name_buffer_length < source_len);
|
||||
|
||||
free (name_buffer);
|
||||
name_buffer = xmalloc(name_buffer_length + 2);
|
||||
}
|
||||
while (name_buffer_length <= source_len)
|
||||
name_buffer = x2realloc(name_buffer, &name_buffer_length);
|
||||
strcpy (name_buffer, source);
|
||||
chopslash (name_buffer);
|
||||
}
|
||||
@@ -996,7 +1122,7 @@ name_next_elt (int change_dirs)
|
||||
name_list_advance ();
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
FALLTHROUGH;
|
||||
case NELT_NAME:
|
||||
copy_name (ep);
|
||||
if (unquote_option)
|
||||
@@ -1013,6 +1139,8 @@ name_next_elt (int change_dirs)
|
||||
}
|
||||
}
|
||||
|
||||
unconsumed_option_report ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1111,6 +1239,34 @@ addname (char const *string, int change_dir, bool cmdline, struct name *parent)
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
add_starting_file (char const *file_name)
|
||||
{
|
||||
struct name *name = make_name (file_name);
|
||||
|
||||
if (starting_file_option)
|
||||
{
|
||||
struct name *head = namelist;
|
||||
remname (head);
|
||||
free_name (head);
|
||||
}
|
||||
|
||||
name->prev = NULL;
|
||||
name->next = namelist;
|
||||
namelist = name;
|
||||
if (!nametail)
|
||||
nametail = namelist;
|
||||
|
||||
name->found_count = 0;
|
||||
name->matching_flags = INCLUDE_OPTIONS;
|
||||
name->change_dir = 0;
|
||||
name->directory = NULL;
|
||||
name->parent = NULL;
|
||||
name->cmdline = true;
|
||||
|
||||
starting_file_option = true;
|
||||
}
|
||||
|
||||
/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
|
||||
list. */
|
||||
static struct name *
|
||||
@@ -1167,19 +1323,22 @@ name_match (const char *file_name)
|
||||
}
|
||||
|
||||
cursor = namelist_match (file_name, length);
|
||||
if (starting_file_option)
|
||||
{
|
||||
/* If starting_file_option is set, the head of the list is the name
|
||||
of the member to start extraction from. Skip the match unless it
|
||||
is head. */
|
||||
if (cursor == namelist)
|
||||
starting_file_option = false;
|
||||
else
|
||||
cursor = NULL;
|
||||
}
|
||||
if (cursor)
|
||||
{
|
||||
if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
|
||||
|| cursor->found_count == 0)
|
||||
cursor->found_count++; /* remember it matched */
|
||||
if (starting_file_option)
|
||||
{
|
||||
free (namelist);
|
||||
namelist = NULL;
|
||||
nametail = NULL;
|
||||
}
|
||||
chdir_do (cursor->change_dir);
|
||||
|
||||
/* We got a match. */
|
||||
return ISFOUND (cursor);
|
||||
}
|
||||
@@ -1445,9 +1604,8 @@ add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
|
||||
size_t name_length = name->length;
|
||||
size_t allocated_length = (name_length >= NAME_FIELD_SIZE
|
||||
? name_length + NAME_FIELD_SIZE
|
||||
: NAME_FIELD_SIZE);
|
||||
char *namebuf = xmalloc (allocated_length + 1);
|
||||
/* FIXME: + 2 above? */
|
||||
: NAME_FIELD_SIZE) + 2;
|
||||
char *namebuf = xmalloc (allocated_length);
|
||||
const char *string;
|
||||
size_t string_length;
|
||||
int change_dir = name->change_dir;
|
||||
@@ -1468,18 +1626,10 @@ add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
|
||||
struct tar_stat_info subdir;
|
||||
int subfd;
|
||||
|
||||
if (allocated_length <= name_length + string_length)
|
||||
{
|
||||
do
|
||||
{
|
||||
allocated_length *= 2;
|
||||
if (! allocated_length)
|
||||
xalloc_die ();
|
||||
}
|
||||
while (allocated_length <= name_length + string_length);
|
||||
|
||||
namebuf = xrealloc (namebuf, allocated_length + 1);
|
||||
}
|
||||
/* need to have at least string_length bytes above the
|
||||
name_length, this includes the trailing null character */
|
||||
while (allocated_length < name_length + string_length)
|
||||
namebuf = x2realloc (namebuf, &allocated_length);
|
||||
strcpy (namebuf + name_length, string + 1);
|
||||
np = addname (namebuf, change_dir, false, name);
|
||||
if (!child_head)
|
||||
@@ -1651,6 +1801,11 @@ collect_and_sort_names (void)
|
||||
name->found_count++;
|
||||
add_hierarchy_to_namelist (&st, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
open_diag (name->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1675,7 +1830,7 @@ collect_and_sort_names (void)
|
||||
{
|
||||
if (p->child)
|
||||
rebase_child_list (p->child, name);
|
||||
hash_delete (nametab, name);
|
||||
hash_remove (nametab, name);
|
||||
/* FIXME: remove_directory (p->caname); ? */
|
||||
remname (p);
|
||||
free_name (p);
|
||||
@@ -1705,7 +1860,7 @@ collect_and_sort_names (void)
|
||||
|
||||
if (listed_incremental_option)
|
||||
{
|
||||
for (name = namelist; name && name->name[0] == 0; name++)
|
||||
for (name = namelist; name && name->name[0] == 0; name = name->next)
|
||||
;
|
||||
if (name)
|
||||
append_incremental_renames (name->directory);
|
||||
|
||||
61
src/sparse.c
61
src/sparse.c
@@ -1,6 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright 2003-2007, 2010, 2013-2016 Free Software Foundation, Inc.
|
||||
Copyright 2003-2021 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
|
||||
@@ -361,11 +361,12 @@ sparse_scan_file (struct tar_sparse_file *file)
|
||||
/* fall back to "raw" for this and all other files */
|
||||
hole_detection = HOLE_DETECTION_RAW;
|
||||
#endif
|
||||
FALLTHROUGH;
|
||||
case HOLE_DETECTION_RAW:
|
||||
if (sparse_scan_file_raw (file))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -426,6 +427,30 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
bufsize);
|
||||
return false;
|
||||
}
|
||||
else if (bytes_read == 0)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
struct stat st;
|
||||
size_t n;
|
||||
if (fstat (file->fd, &st) == 0)
|
||||
n = file->stat_info->stat.st_size - st.st_size;
|
||||
else
|
||||
n = file->stat_info->stat.st_size
|
||||
- (file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].numbytes
|
||||
- bytes_left);
|
||||
|
||||
WARNOPT (WARN_FILE_SHRANK,
|
||||
(0, 0,
|
||||
ngettext ("%s: File shrank by %s byte; padding with zeros",
|
||||
"%s: File shrank by %s bytes; padding with zeros",
|
||||
n),
|
||||
quotearg_colon (file->stat_info->orig_file_name),
|
||||
STRINGIFY_BIGINT (n, buf)));
|
||||
if (! ignore_failed_read_option)
|
||||
set_exit_status (TAREXIT_DIFFERS);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
|
||||
bytes_left -= bytes_read;
|
||||
@@ -463,9 +488,9 @@ sparse_extract_region (struct tar_sparse_file *file, size_t i)
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
file->dumped_size += BLOCKSIZE;
|
||||
count = blocking_write (file->fd, blk->buffer, wrbytes);
|
||||
write_size -= count;
|
||||
file->dumped_size += count;
|
||||
mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
|
||||
file->offset += count;
|
||||
if (count != wrbytes)
|
||||
@@ -597,6 +622,12 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
rdsize);
|
||||
return false;
|
||||
}
|
||||
else if (bytes_read == 0)
|
||||
{
|
||||
report_difference (file->stat_info, _("Size differs"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!zero_block_p (diff_buffer, bytes_read))
|
||||
{
|
||||
char begbuf[INT_BUFSIZE_BOUND (off_t)];
|
||||
@@ -608,6 +639,7 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
|
||||
beg += bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -634,6 +666,7 @@ check_data_region (struct tar_sparse_file *file, size_t i)
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
file->dumped_size += BLOCKSIZE;
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
@@ -644,10 +677,14 @@ check_data_region (struct tar_sparse_file *file, size_t i)
|
||||
rdsize);
|
||||
return false;
|
||||
}
|
||||
file->dumped_size += bytes_read;
|
||||
else if (bytes_read == 0)
|
||||
{
|
||||
report_difference (¤t_stat_info, _("Size differs"));
|
||||
return false;
|
||||
}
|
||||
size_left -= bytes_read;
|
||||
mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
|
||||
if (memcmp (blk->buffer, diff_buffer, rdsize))
|
||||
if (memcmp (blk->buffer, diff_buffer, bytes_read))
|
||||
{
|
||||
report_difference (file->stat_info, _("Contents differ"));
|
||||
return false;
|
||||
@@ -665,7 +702,7 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
|
||||
off_t offset = 0;
|
||||
|
||||
if (!tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
return false;
|
||||
|
||||
file.stat_info = st;
|
||||
file.fd = fd;
|
||||
@@ -1212,7 +1249,8 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
union block *blk;
|
||||
char *p;
|
||||
size_t i;
|
||||
|
||||
off_t start;
|
||||
|
||||
#define COPY_BUF(b,buf,src) do \
|
||||
{ \
|
||||
char *endp = b->buffer + BLOCKSIZE; \
|
||||
@@ -1228,8 +1266,9 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
if (src == endp) \
|
||||
{ \
|
||||
set_next_block_after (b); \
|
||||
file->dumped_size += BLOCKSIZE; \
|
||||
b = find_next_block (); \
|
||||
if (!b) \
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive"))); \
|
||||
src = b->buffer; \
|
||||
endp = b->buffer + BLOCKSIZE; \
|
||||
} \
|
||||
@@ -1239,9 +1278,11 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
dst[-1] = 0; \
|
||||
} while (0)
|
||||
|
||||
start = current_block_ordinal ();
|
||||
set_next_block_after (current_header);
|
||||
file->dumped_size += BLOCKSIZE;
|
||||
blk = find_next_block ();
|
||||
if (!blk)
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
p = blk->buffer;
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
|
||||
@@ -1277,6 +1318,8 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
sparse_add_map (file->stat_info, &sp);
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
|
||||
file->dumped_size += BLOCKSIZE * (current_block_ordinal () - start);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
15
src/suffix.c
15
src/suffix.c
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2007, 2009, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2007-2021 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff.
|
||||
|
||||
@@ -45,6 +45,8 @@ static struct compression_suffix compression_suffixes[] = {
|
||||
{ S(lzo, LZOP) },
|
||||
{ S(xz, XZ) },
|
||||
{ S(txz, XZ) }, /* Slackware */
|
||||
{ S(zst, ZSTD) },
|
||||
{ S(tzst, ZSTD) },
|
||||
{ NULL }
|
||||
#undef S
|
||||
#undef __CAT2__
|
||||
@@ -59,7 +61,7 @@ find_compression_suffix (const char *name, size_t *ret_len)
|
||||
{
|
||||
size_t len;
|
||||
struct compression_suffix *p;
|
||||
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
@@ -98,10 +100,14 @@ strip_compression_suffix (const char *name)
|
||||
{
|
||||
char *s = NULL;
|
||||
size_t len;
|
||||
struct compression_suffix const *p = find_compression_suffix (name, &len);
|
||||
|
||||
if (find_compression_suffix (name, &len))
|
||||
if (p)
|
||||
{
|
||||
if (strncmp (name + len - 4, ".tar", 4) == 0)
|
||||
/* Strip an additional ".tar" suffix, but only if the just-stripped
|
||||
"outer" suffix did not begin with "t". */
|
||||
if (len > 4 && strncmp (name + len - 4, ".tar", 4) == 0
|
||||
&& p->suffix[0] != 't')
|
||||
len -= 4;
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
@@ -111,4 +117,3 @@ strip_compression_suffix (const char *name)
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright 2003-2008, 2010, 2013-2014, 2016 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2003-2021 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
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* GNU tar Archive Format description.
|
||||
|
||||
Copyright 1988-1989, 1991-1997, 2000-2001, 2003-2007, 2012-2014, 2016
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -328,9 +327,13 @@ struct tar_stat_info
|
||||
struct sp_array *sparse_map;
|
||||
|
||||
off_t real_size; /* The real size of sparse file */
|
||||
int real_size_set; /* True when GNU.sparse.realsize is set in
|
||||
bool real_size_set; /* True when GNU.sparse.realsize is set in
|
||||
archived file */
|
||||
|
||||
bool sparse_name_done; /* Set to true if 'GNU.sparse.name' header was
|
||||
processed pax header parsing. Following 'path'
|
||||
header (lower priority) will be ignored. */
|
||||
|
||||
size_t xattr_map_size; /* Size of the xattr map */
|
||||
struct xattr_array *xattr_map;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2006-2008, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2006-2021 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
|
||||
@@ -100,7 +100,7 @@ add_segment (struct transform *tf)
|
||||
}
|
||||
|
||||
static void
|
||||
add_literal_segment (struct transform *tf, char *str, char *end)
|
||||
add_literal_segment (struct transform *tf, const char *str, const char *end)
|
||||
{
|
||||
size_t len = end - str;
|
||||
if (len)
|
||||
@@ -208,6 +208,8 @@ parse_transform_expr (const char *expr)
|
||||
}
|
||||
|
||||
delim = expr[1];
|
||||
if (!delim)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
|
||||
/* Scan regular expression */
|
||||
for (i = 2; expr[i] && expr[i] != delim; i++)
|
||||
@@ -272,7 +274,7 @@ parse_transform_expr (const char *expr)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
|
||||
}
|
||||
|
||||
if (str[0] == '^' || str[strlen (str) - 1] == '$')
|
||||
if (str[0] == '^' || (i > 2 && str[i - 3] == '$'))
|
||||
tf->transform_type = transform_first;
|
||||
|
||||
free (str);
|
||||
@@ -402,6 +404,7 @@ parse_transform_expr (const char *expr)
|
||||
cur++;
|
||||
}
|
||||
add_literal_segment (tf, beg, cur);
|
||||
free(str);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -549,7 +552,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
FALLTHROUGH;
|
||||
|
||||
case ctl_upcase:
|
||||
case ctl_locase:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Unlink files.
|
||||
|
||||
Copyright 2009, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2009-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -127,7 +127,9 @@ flush_deferred_unlinks (bool force)
|
||||
case EEXIST:
|
||||
/* OpenSolaris >=10 sets EEXIST instead of ENOTEMPTY
|
||||
if trying to remove a non-empty directory */
|
||||
#if defined ENOTEMPTY && ENOTEMPTY != EEXIST
|
||||
case ENOTEMPTY:
|
||||
#endif
|
||||
/* Keep the record in list, in the hope we'll
|
||||
be able to remove it later */
|
||||
prev = p;
|
||||
|
||||
13
src/update.c
13
src/update.c
@@ -1,7 +1,6 @@
|
||||
/* Update a tar archive.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996-1997, 1999-2001, 2003-2005, 2007,
|
||||
2010, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 1988-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -111,7 +110,7 @@ update_archive (void)
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
buffer_write_global_xheader ();
|
||||
xheader_forbid_global ();
|
||||
|
||||
while (!found_end)
|
||||
{
|
||||
@@ -152,7 +151,7 @@ update_archive (void)
|
||||
|
||||
for (p = dirp; *p; p += strlen (p) + 1)
|
||||
addname (namebuf_name (nbuf, p),
|
||||
0, false, NULL);
|
||||
name->change_dir, false, NULL);
|
||||
|
||||
namebuf_free (nbuf);
|
||||
free (dirp);
|
||||
@@ -186,13 +185,11 @@ update_archive (void)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_FAILURE:
|
||||
break;
|
||||
|
||||
|
||||
33
src/utf8.c
33
src/utf8.c
@@ -1,7 +1,6 @@
|
||||
/* Charset handling for GNU tar.
|
||||
|
||||
Copyright 2004, 2006-2007, 2013-2014, 2016 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -36,11 +35,14 @@
|
||||
# define iconv_open(tocode, fromcode) ((iconv_t) -1)
|
||||
|
||||
# undef iconv
|
||||
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) ((size_t) 0)
|
||||
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) (errno = ENOSYS, (size_t) -1)
|
||||
|
||||
# undef iconv_close
|
||||
# define iconv_close(cd) 0
|
||||
|
||||
# undef iconv_t
|
||||
# define iconv_t int
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -65,10 +67,9 @@ bool
|
||||
utf8_convert (bool to_utf, char const *input, char **output)
|
||||
{
|
||||
char ICONV_CONST *ib;
|
||||
char *ob;
|
||||
char *ob, *ret;
|
||||
size_t inlen;
|
||||
size_t outlen;
|
||||
size_t rc;
|
||||
iconv_t cd = utf8_init (to_utf);
|
||||
|
||||
if (cd == 0)
|
||||
@@ -81,11 +82,27 @@ utf8_convert (bool to_utf, char const *input, char **output)
|
||||
|
||||
inlen = strlen (input) + 1;
|
||||
outlen = inlen * MB_LEN_MAX + 1;
|
||||
ob = *output = xmalloc (outlen);
|
||||
ob = ret = xmalloc (outlen);
|
||||
ib = (char ICONV_CONST *) input;
|
||||
rc = iconv (cd, &ib, &inlen, &ob, &outlen);
|
||||
/* According to POSIX, "if iconv() encounters a character in the input
|
||||
buffer that is valid, but for which an identical character does not
|
||||
exist in the target codeset, iconv() shall perform an
|
||||
implementation-defined conversion on this character." It will "update
|
||||
the variables pointed to by the arguments to reflect the extent of the
|
||||
conversion and return the number of non-identical conversions performed".
|
||||
On error, it returns -1.
|
||||
In other words, non-zero return always indicates failure, either because
|
||||
the input was not fully converted, or because it was converted in a
|
||||
non-reversible way.
|
||||
*/
|
||||
if (iconv (cd, &ib, &inlen, &ob, &outlen) != 0)
|
||||
{
|
||||
free (ret);
|
||||
return false;
|
||||
}
|
||||
*ob = 0;
|
||||
return rc != -1;
|
||||
*output = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Warnings for GNU tar.
|
||||
|
||||
Copyright 2009, 2012-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright 2009-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -47,6 +47,7 @@ static char const *const warning_args[] = {
|
||||
"existing-file",
|
||||
"xattr-write",
|
||||
"record-size",
|
||||
"failed-read",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -74,7 +75,8 @@ static int warning_types[] = {
|
||||
WARN_DECOMPRESS_PROGRAM,
|
||||
WARN_EXISTING_FILE,
|
||||
WARN_XATTR_WRITE,
|
||||
WARN_RECORD_SIZE
|
||||
WARN_RECORD_SIZE,
|
||||
WARN_FAILED_READ
|
||||
};
|
||||
|
||||
ARGMATCH_VERIFY (warning_args, warning_types);
|
||||
|
||||
56
src/xattrs.c
56
src/xattrs.c
@@ -1,6 +1,6 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -246,13 +246,36 @@ xattrs__acls_set (struct tar_stat_info const *st,
|
||||
acl_free (acl);
|
||||
}
|
||||
|
||||
/* Cleanup textual representation of the ACL in VAL by eliminating tab
|
||||
characters and comments */
|
||||
static void
|
||||
xattrs_acls_cleanup (char *val, size_t *plen)
|
||||
{
|
||||
char *p, *q;
|
||||
|
||||
p = q = val + strcspn (val, "#\t");
|
||||
while (*q)
|
||||
{
|
||||
if (*q == '\t')
|
||||
q++;
|
||||
else if (*q == '#')
|
||||
{
|
||||
while (*q != '\n')
|
||||
q++;
|
||||
}
|
||||
else
|
||||
*p++ = *q++;
|
||||
}
|
||||
*plen = p - val;
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xattrs__acls_get_a (int parentfd, const char *file_name,
|
||||
struct tar_stat_info *st,
|
||||
char **ret_ptr, size_t * ret_len)
|
||||
{
|
||||
char *val = NULL;
|
||||
ssize_t len;
|
||||
acl_t acl;
|
||||
|
||||
if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_ACCESS)))
|
||||
@@ -262,7 +285,7 @@ xattrs__acls_get_a (int parentfd, const char *file_name,
|
||||
return;
|
||||
}
|
||||
|
||||
val = acl_to_text (acl, &len);
|
||||
val = acl_to_text (acl, NULL);
|
||||
acl_free (acl);
|
||||
|
||||
if (!val)
|
||||
@@ -272,8 +295,7 @@ xattrs__acls_get_a (int parentfd, const char *file_name,
|
||||
}
|
||||
|
||||
*ret_ptr = xstrdup (val);
|
||||
*ret_len = len;
|
||||
|
||||
xattrs_acls_cleanup (*ret_ptr, ret_len);
|
||||
acl_free (val);
|
||||
}
|
||||
|
||||
@@ -284,7 +306,6 @@ xattrs__acls_get_d (int parentfd, char const *file_name,
|
||||
char **ret_ptr, size_t * ret_len)
|
||||
{
|
||||
char *val = NULL;
|
||||
ssize_t len;
|
||||
acl_t acl;
|
||||
|
||||
if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_DEFAULT)))
|
||||
@@ -294,7 +315,7 @@ xattrs__acls_get_d (int parentfd, char const *file_name,
|
||||
return;
|
||||
}
|
||||
|
||||
val = acl_to_text (acl, &len);
|
||||
val = acl_to_text (acl, NULL);
|
||||
acl_free (acl);
|
||||
|
||||
if (!val)
|
||||
@@ -304,8 +325,7 @@ xattrs__acls_get_d (int parentfd, char const *file_name,
|
||||
}
|
||||
|
||||
*ret_ptr = xstrdup (val);
|
||||
*ret_len = len;
|
||||
|
||||
xattrs_acls_cleanup (*ret_ptr, ret_len);
|
||||
acl_free (val);
|
||||
}
|
||||
#endif /* HAVE_POSIX_ACLS */
|
||||
@@ -336,6 +356,7 @@ acls_one_line (const char *prefix, char delim,
|
||||
obstack_grow (&stk, prefix, pref_len);
|
||||
obstack_grow (&stk, aclstring, move);
|
||||
|
||||
pos += move + 1;
|
||||
aclstring += move + 1;
|
||||
}
|
||||
|
||||
@@ -434,8 +455,12 @@ xattrs_clear_setup (void)
|
||||
clear_mask_map (&xattrs_setup.excl);
|
||||
}
|
||||
|
||||
/* get all xattrs from file given by FILE_NAME or FD (when non-zero). This
|
||||
includes all the user.*, security.*, system.*, etc. available domains */
|
||||
static bool xattrs_masked_out (const char *kw, bool archiving);
|
||||
|
||||
/* get xattrs from file given by FILE_NAME or FD (when non-zero)
|
||||
xattrs are checked against the user supplied include/exclude mask
|
||||
if no mask is given this includes all the user.*, security.*, system.*,
|
||||
etc. available domains */
|
||||
void
|
||||
xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd)
|
||||
@@ -480,8 +505,6 @@ xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
size_t len = strlen (attr);
|
||||
ssize_t aret = 0;
|
||||
|
||||
/* Archive all xattrs during creation, decide at extraction time
|
||||
* which ones are of interest/use for the target filesystem. */
|
||||
while (((fd == 0)
|
||||
? ((aret = lgetxattrat (parentfd, file_name, attr,
|
||||
val, asz)) == -1)
|
||||
@@ -492,7 +515,10 @@ xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
}
|
||||
|
||||
if (aret != -1)
|
||||
xheader_xattr_add (st, attr, val, aret);
|
||||
{
|
||||
if (!xattrs_masked_out (attr, true))
|
||||
xheader_xattr_add (st, attr, val, aret);
|
||||
}
|
||||
else if (errno != ENOATTR)
|
||||
call_arg_warn ((fd == 0) ? "lgetxattrat"
|
||||
: "fgetxattr", file_name);
|
||||
@@ -735,6 +761,8 @@ xattrs_print (struct tar_stat_info const *st)
|
||||
{
|
||||
fprintf (stdlis, " a: ");
|
||||
acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len);
|
||||
if (st->acls_a_len && st->acls_d_len)
|
||||
fprintf (stdlis, ",");
|
||||
acls_one_line ("default:", ',', st->acls_d_ptr, st->acls_d_len);
|
||||
fprintf (stdlis, "\n");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014, 2016 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
143
src/xheader.c
143
src/xheader.c
@@ -1,7 +1,6 @@
|
||||
/* POSIX extended headers for tar.
|
||||
|
||||
Copyright (C) 2003-2007, 2009-2010, 2012-2014, 2016 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright (C) 2003-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -185,6 +184,9 @@ xheader_set_keyword_equal (char *kw, char *eq)
|
||||
bool global = true;
|
||||
char *p = eq;
|
||||
|
||||
if (eq == kw)
|
||||
USAGE_ERROR ((0, 0, _("Malformed pax option: %s"), quote (kw)));
|
||||
|
||||
if (eq[-1] == ':')
|
||||
{
|
||||
p--;
|
||||
@@ -255,7 +257,7 @@ char *
|
||||
xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
|
||||
{
|
||||
char *buf;
|
||||
size_t len = strlen (fmt);
|
||||
size_t len;
|
||||
char *q;
|
||||
const char *p;
|
||||
char *dirp = NULL;
|
||||
@@ -266,43 +268,51 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char const *nptr = NULL;
|
||||
|
||||
for (p = fmt; *p && (p = strchr (p, '%')); )
|
||||
len = 0;
|
||||
for (p = fmt; *p; p++)
|
||||
{
|
||||
switch (p[1])
|
||||
if (*p == '%' && p[1])
|
||||
{
|
||||
case '%':
|
||||
len--;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (st)
|
||||
switch (*++p)
|
||||
{
|
||||
if (!dirp)
|
||||
dirp = dir_name (st->orig_file_name);
|
||||
dir = safer_name_suffix (dirp, false, absolute_names_option);
|
||||
len += strlen (dir) - 2;
|
||||
case '%':
|
||||
len++;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (st)
|
||||
{
|
||||
if (!dirp)
|
||||
dirp = dir_name (st->orig_file_name);
|
||||
dir = safer_name_suffix (dirp, false, absolute_names_option);
|
||||
len += strlen (dir);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (st)
|
||||
{
|
||||
base = last_component (st->orig_file_name);
|
||||
len += strlen (base);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pptr = umaxtostr (getpid (), pidbuf);
|
||||
len += pidbuf + sizeof pidbuf - 1 - pptr;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
nptr = umaxtostr (n, nbuf);
|
||||
len += nbuf + sizeof nbuf - 1 - nptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
len += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (st)
|
||||
{
|
||||
base = last_component (st->orig_file_name);
|
||||
len += strlen (base) - 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pptr = umaxtostr (getpid (), pidbuf);
|
||||
len += pidbuf + sizeof pidbuf - 1 - pptr - 2;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
nptr = umaxtostr (n, nbuf);
|
||||
len += nbuf + sizeof nbuf - 1 - nptr - 2;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
buf = xmalloc (len + 1);
|
||||
@@ -359,29 +369,46 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Table of templates for the names of POSIX extended headers.
|
||||
Indexed by the the type of the header (per-file or global)
|
||||
and POSIX compliance mode (0 or q depending on whether
|
||||
POSIXLY_CORRECT environment variable is set. */
|
||||
static const char *header_template[][2] = {
|
||||
/* Individual header templates: */
|
||||
{ "%d/PaxHeaders/%f", "%d/PaxHeaders.%p/%f" },
|
||||
/* Global header templates: */
|
||||
{ "/GlobalHead.%n", "/GlobalHead.%p.%n" }
|
||||
};
|
||||
/* Indices to the above table */
|
||||
enum {
|
||||
pax_file_header,
|
||||
pax_global_header
|
||||
};
|
||||
/* Return the name for the POSIX extended header T */
|
||||
#define HEADER_TEMPLATE(t) header_template[t][posixly_correct]
|
||||
|
||||
char *
|
||||
xheader_xhdr_name (struct tar_stat_info *st)
|
||||
{
|
||||
if (!exthdr_name)
|
||||
assign_string (&exthdr_name, "%d/PaxHeaders.%p/%f");
|
||||
assign_string (&exthdr_name, HEADER_TEMPLATE (pax_file_header));
|
||||
return xheader_format_name (st, exthdr_name, 0);
|
||||
}
|
||||
|
||||
#define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n"
|
||||
|
||||
char *
|
||||
xheader_ghdr_name (void)
|
||||
{
|
||||
if (!globexthdr_name)
|
||||
{
|
||||
size_t len;
|
||||
const char *global_header_template = HEADER_TEMPLATE (pax_global_header);
|
||||
const char *tmp = getenv ("TMPDIR");
|
||||
if (!tmp)
|
||||
tmp = "/tmp";
|
||||
len = strlen (tmp) + sizeof (GLOBAL_HEADER_TEMPLATE); /* Includes nul */
|
||||
len = strlen (tmp) + strlen (global_header_template) + 1;
|
||||
globexthdr_name = xmalloc (len);
|
||||
strcpy(globexthdr_name, tmp);
|
||||
strcat(globexthdr_name, GLOBAL_HEADER_TEMPLATE);
|
||||
strcat(globexthdr_name, global_header_template);
|
||||
}
|
||||
|
||||
return xheader_format_name (NULL, globexthdr_name, global_header_count + 1);
|
||||
@@ -458,6 +485,14 @@ xheader_write_global (struct xheader *xhdr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Forbid modifications of the global extended header */
|
||||
void
|
||||
xheader_forbid_global (void)
|
||||
{
|
||||
if (keyword_global_override_list)
|
||||
USAGE_ERROR ((0, 0, _("can't update global extended header record")));
|
||||
}
|
||||
|
||||
void
|
||||
xheader_xattr_init (struct tar_stat_info *st)
|
||||
{
|
||||
@@ -1290,15 +1325,33 @@ path_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
code_string (st->file_name, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
raw_path_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
decode_string (&st->orig_file_name, arg);
|
||||
decode_string (&st->file_name, arg);
|
||||
st->had_trailing_slash = strip_trailing_slashes (st->file_name);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&st->orig_file_name, arg);
|
||||
decode_string (&st->file_name, arg);
|
||||
st->had_trailing_slash = strip_trailing_slashes (st->file_name);
|
||||
if (! st->sparse_name_done)
|
||||
raw_path_decoder (st, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
st->sparse_name_done = true;
|
||||
raw_path_decoder (st, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1371,7 +1424,7 @@ sparse_size_decoder (struct tar_stat_info *st,
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
{
|
||||
st->real_size_set = 1;
|
||||
st->real_size_set = true;
|
||||
st->real_size = u;
|
||||
}
|
||||
}
|
||||
@@ -1730,7 +1783,7 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
{ "uname", uname_coder, uname_decoder, 0, false },
|
||||
|
||||
/* Sparse file handling */
|
||||
{ "GNU.sparse.name", path_coder, path_decoder,
|
||||
{ "GNU.sparse.name", path_coder, sparse_path_decoder,
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
|
||||
XHDR_PROTECTED, false },
|
||||
|
||||
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@@ -12,3 +12,4 @@ download
|
||||
ttyemu
|
||||
checkseekhole
|
||||
ckmtime
|
||||
/compress-*.at
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Makefile for GNU tar regression tests.
|
||||
|
||||
# Copyright 1996-1997, 1999-2001, 2003-2007, 2009, 2012-2015 Free Software
|
||||
# Copyright 1996-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 star/README star/quicktest.sh
|
||||
EXTRA_DIST = $(TESTSUITE_AT) \
|
||||
testsuite package.m4 star/README star/quicktest.sh \
|
||||
compress.m4
|
||||
|
||||
DISTCLEANFILES = atconfig $(check_SCRIPTS)
|
||||
MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
|
||||
CLEANFILES =
|
||||
|
||||
## ------------ ##
|
||||
## package.m4. ##
|
||||
@@ -42,6 +46,8 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
## ------------ ##
|
||||
|
||||
TESTSUITE_AT = \
|
||||
testsuite.at\
|
||||
compress.m4\
|
||||
T-cd.at\
|
||||
T-dir00.at\
|
||||
T-dir01.at\
|
||||
@@ -54,7 +60,7 @@ TESTSUITE_AT = \
|
||||
T-nonl.at\
|
||||
T-mult.at\
|
||||
T-nest.at\
|
||||
testsuite.at\
|
||||
add-file.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
append02.at\
|
||||
@@ -65,11 +71,17 @@ TESTSUITE_AT = \
|
||||
chtype.at\
|
||||
comprec.at\
|
||||
comperr.at\
|
||||
checkpoint/defaults.at\
|
||||
checkpoint/interval.at\
|
||||
checkpoint/dot.at\
|
||||
checkpoint/dot-compat.at\
|
||||
checkpoint/dot-int.at\
|
||||
delete01.at\
|
||||
delete02.at\
|
||||
delete03.at\
|
||||
delete04.at\
|
||||
delete05.at\
|
||||
difflink.at\
|
||||
exclude.at\
|
||||
exclude01.at\
|
||||
exclude02.at\
|
||||
@@ -106,8 +118,15 @@ TESTSUITE_AT = \
|
||||
extrac17.at\
|
||||
extrac18.at\
|
||||
extrac19.at\
|
||||
extrac20.at\
|
||||
extrac21.at\
|
||||
extrac22.at\
|
||||
extrac23.at\
|
||||
extrac24.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
dirrem01.at\
|
||||
dirrem02.at\
|
||||
gzip.at\
|
||||
grow.at\
|
||||
incremental.at\
|
||||
@@ -153,6 +172,7 @@ TESTSUITE_AT = \
|
||||
multiv07.at\
|
||||
multiv08.at\
|
||||
multiv09.at\
|
||||
multiv10.at\
|
||||
numeric.at\
|
||||
old.at\
|
||||
onetop01.at\
|
||||
@@ -166,8 +186,12 @@ TESTSUITE_AT = \
|
||||
opcomp04.at\
|
||||
opcomp05.at\
|
||||
opcomp06.at\
|
||||
positional01.at\
|
||||
positional02.at\
|
||||
positional03.at\
|
||||
options.at\
|
||||
options02.at\
|
||||
options03.at\
|
||||
owner.at\
|
||||
pipe.at\
|
||||
recurse.at\
|
||||
@@ -177,6 +201,7 @@ TESTSUITE_AT = \
|
||||
rename03.at\
|
||||
rename04.at\
|
||||
rename05.at\
|
||||
rename06.at\
|
||||
remfiles01.at\
|
||||
remfiles02.at\
|
||||
remfiles03.at\
|
||||
@@ -211,17 +236,22 @@ TESTSUITE_AT = \
|
||||
sparse04.at\
|
||||
sparse05.at\
|
||||
sparse06.at\
|
||||
sparse07.at\
|
||||
sparsemv.at\
|
||||
sparsemvp.at\
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
sptrcreat.at\
|
||||
sptrdiff00.at\
|
||||
sptrdiff01.at\
|
||||
time01.at\
|
||||
time02.at\
|
||||
truncate.at\
|
||||
update.at\
|
||||
update01.at\
|
||||
update02.at\
|
||||
update03.at\
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
@@ -230,6 +260,7 @@ TESTSUITE_AT = \
|
||||
xform-h.at\
|
||||
xform01.at\
|
||||
xform02.at\
|
||||
xform03.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
star/multi-fail.at\
|
||||
@@ -241,6 +272,8 @@ TESTSUITE_AT = \
|
||||
xattr03.at\
|
||||
xattr04.at\
|
||||
xattr05.at\
|
||||
xattr06.at\
|
||||
xattr07.at\
|
||||
acls01.at\
|
||||
acls02.at\
|
||||
acls03.at\
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
@@ -19,7 +19,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([-C in file lists])
|
||||
AT_KEYWORDS([files-from T-cd])
|
||||
AT_KEYWORDS([files-from T-cd chdir])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2014-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2014-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2006-2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
@@ -29,9 +29,8 @@ AT_KEYWORDS([files-from nonewline nonl T-nonl])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --length=0 --file empty
|
||||
AS_ECHO_N(c) > 1.nonl
|
||||
echo d > 2.nonl
|
||||
AS_ECHO_N(e) >> 2.nonl
|
||||
printf c > 1.nonl
|
||||
printf 'd\ne' > 2.nonl
|
||||
touch a b c d e
|
||||
AT_DATA([filelist],[a
|
||||
b
|
||||
@@ -59,4 +58,3 @@ c
|
||||
[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2006-2007, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This file is part of test suite for GNU tar. -*- Autotest -*-
|
||||
# Copyright 2015-2016 Free Software Foundation, Inc.
|
||||
# Copyright 2015-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -25,11 +25,13 @@ AT_TAR_CHECK([
|
||||
AT_DATA([file-list],[a
|
||||
-b
|
||||
--c d
|
||||
:\\.jpg
|
||||
])
|
||||
|
||||
genfile -f a
|
||||
genfile -f -b
|
||||
genfile -f '--c d'
|
||||
genfile -f ':\\.jpg'
|
||||
|
||||
cat file-list | tr '\n' '\0' | tar -c -f archive -v --null -T -
|
||||
],
|
||||
@@ -37,6 +39,7 @@ cat file-list | tr '\n' '\0' | tar -c -f archive -v --null -T -
|
||||
[a
|
||||
-b
|
||||
--c d
|
||||
:\\\\.jpg
|
||||
],
|
||||
[],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2015-2016 Free Software Foundation, Inc.
|
||||
# Copyright 2015-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2011, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2011-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2011, 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2011-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
# This is basic test for acl support.
|
||||
|
||||
AT_SETUP([acls: work with -C])
|
||||
AT_KEYWORDS([xattrs acls acls02])
|
||||
AT_KEYWORDS([xattrs acls acls02 chdir])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_XATTRS_UTILS_PREREQ
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# http://www.mail-archive.com/bug-tar@gnu.org/msg04355.html
|
||||
|
||||
AT_SETUP([acls: default ACLs])
|
||||
AT_KEYWORDS([xattrs acls acls03])
|
||||
AT_KEYWORDS([xattrs acls acls03 chdir])
|
||||
|
||||
m4_define([ACL_LISTDIR], [
|
||||
cd $1
|
||||
|
||||
67
tests/add-file.at
Normal file
67
tests/add-file.at
Normal file
@@ -0,0 +1,67 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2016-2021 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
# GNU tar 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GNU tar 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([The --add-file option])
|
||||
AT_KEYWORDS([add-file])
|
||||
|
||||
# Version 1.29 would give "tar: Cowardly refusing to create an empty archive"
|
||||
# if only --add-file arguments were used, and would give "tar: unhandled
|
||||
# positional option 0" when handling the --add-file if at least one file was
|
||||
# also given normally.
|
||||
#
|
||||
# Reported by: James Clarke <jrtc27@jrtc27.com>
|
||||
# References: <20161112000246.77013-1-jrtc27@jrtc27.com>,
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2016-11/msg00013.html
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --file -File
|
||||
genfile --file foo
|
||||
genfile --file bar
|
||||
|
||||
echo 1:
|
||||
tar -cvf arc.tar --add-file foo --add-file -File
|
||||
|
||||
echo 2:
|
||||
tar -cvf arc.tar foo --add-file -File bar
|
||||
|
||||
|
||||
AT_DATA([input],[foo
|
||||
--add-file=-File
|
||||
bar
|
||||
])
|
||||
|
||||
echo 3:
|
||||
tar -cvf arc.tar -T input
|
||||
],
|
||||
[0],
|
||||
[1:
|
||||
foo
|
||||
-File
|
||||
2:
|
||||
foo
|
||||
-File
|
||||
bar
|
||||
3:
|
||||
foo
|
||||
-File
|
||||
bar
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,8 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2004, 2006-2007, 2013-2014, 2016 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user