Compare commits
218 Commits
release_1_
...
v1.35
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e545d446df | ||
|
|
e7a5e12445 | ||
|
|
31f68bbe2a | ||
|
|
10954cf163 | ||
|
|
b3a71dbdb9 | ||
|
|
cf16a23945 | ||
|
|
d6a60bba76 | ||
|
|
2ccd643d01 | ||
|
|
fdff045d4b | ||
|
|
90cceec4bb | ||
|
|
826c5eb64e | ||
|
|
2096772fbe | ||
|
|
c542d3d0c8 | ||
|
|
4c7a3798d8 | ||
|
|
5d6736e394 | ||
|
|
9ee30c9804 | ||
|
|
4695adfd59 | ||
|
|
a484178a18 | ||
|
|
e39b93d822 | ||
|
|
8ccfc4e416 | ||
|
|
e7987b72c6 | ||
|
|
06805b9281 | ||
|
|
5461025569 | ||
|
|
3f2b847ddd | ||
|
|
6af0596726 | ||
|
|
204b414d11 | ||
|
|
6a1581240b | ||
|
|
4f814e0e4c | ||
|
|
4177c98bcc | ||
|
|
5e8a915b16 | ||
|
|
edf38d13a4 | ||
|
|
3da78400ea | ||
|
|
02402920f8 | ||
|
|
021845e54d | ||
|
|
0f289d7238 | ||
|
|
71d1619abd | ||
|
|
719d3b44b7 | ||
|
|
a65f01ac35 | ||
|
|
2cde05fa10 | ||
|
|
e89c7a45eb | ||
|
|
24c8306965 | ||
|
|
ba26ec86e2 | ||
|
|
de64229632 | ||
|
|
17debecd73 | ||
|
|
02f9af1b8d | ||
|
|
87f9e42108 | ||
|
|
0f0722df45 | ||
|
|
7324326b1d | ||
|
|
705bb09317 | ||
|
|
4ba281eca3 | ||
|
|
bc277c7069 | ||
|
|
f8e14746d2 | ||
|
|
35d9845d5d | ||
|
|
0b74885e81 | ||
|
|
258d1c44e5 | ||
|
|
e49537dcdf | ||
|
|
66be5a789e | ||
|
|
badd509078 | ||
|
|
4e9e55fbf9 | ||
|
|
fffc6149fd | ||
|
|
8ed180b03c | ||
|
|
131ceea7a5 | ||
|
|
4986147986 | ||
|
|
e5aac38c80 | ||
|
|
5c4f8cadbd | ||
|
|
496cf61638 | ||
|
|
d935dc7d1c | ||
|
|
9f0e54ab2f | ||
|
|
c7b69f05bc | ||
|
|
4eb9d052b2 | ||
|
|
5209d1dfe0 | ||
|
|
b2ed3caefe | ||
|
|
79d1ac38c1 | ||
|
|
79a442d7b0 | ||
|
|
7a37621e5b | ||
|
|
c1027eb5ae | ||
|
|
bc7e758b27 | ||
|
|
de72aa0cd6 | ||
|
|
eeda008a59 | ||
|
|
5c713540e3 | ||
|
|
88ccec5d6c | ||
|
|
399c08b3bf | ||
|
|
7f8fe36040 | ||
|
|
b846956c60 | ||
|
|
ac119c80e4 | ||
|
|
d43adc97d6 | ||
|
|
1f73735ba0 | ||
|
|
39cd8c6586 | ||
|
|
84a08f530d | ||
|
|
c366383852 | ||
|
|
738de9ecde | ||
|
|
771ca7b686 | ||
|
|
8184adddab | ||
|
|
7868054c03 | ||
|
|
4f3824743f | ||
|
|
c5b86d7672 | ||
|
|
c0bf6a723b | ||
|
|
b44c612f5d | ||
|
|
066f7729e0 | ||
|
|
7958eb97e6 | ||
|
|
66262c10d1 | ||
|
|
a339f05cd2 | ||
|
|
cc8f5f78b2 | ||
|
|
193eb8f81d | ||
|
|
93082d6eb8 | ||
|
|
e5bc23efcc | ||
|
|
12d67f44de | ||
|
|
3730dddb3f | ||
|
|
8e82f367d4 | ||
|
|
66b59fccb1 | ||
|
|
91c031678d | ||
|
|
5227d66b3c | ||
|
|
f51461d8be | ||
|
|
6efa8de409 | ||
|
|
c67d223854 | ||
|
|
55f2a0772e | ||
|
|
daf634c44e | ||
|
|
5f8f129415 | ||
|
|
dc101747e8 | ||
|
|
7fb1b6877f | ||
|
|
f4e2411bf5 | ||
|
|
ace146f6a4 | ||
|
|
df6de51574 | ||
|
|
8378991cba | ||
|
|
fa6d317bc7 | ||
|
|
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 |
46
.gitignore
vendored
46
.gitignore
vendored
@@ -1,30 +1,32 @@
|
||||
*.a
|
||||
*.[aios]
|
||||
*.[gx]z
|
||||
*.bz2
|
||||
*.cache
|
||||
*.diff
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.orig
|
||||
*.patch
|
||||
*.rej
|
||||
*.so
|
||||
*DISTFILES
|
||||
*~
|
||||
.bootstrap
|
||||
.deps
|
||||
.emacs*
|
||||
.libs
|
||||
ABOUT-NLS
|
||||
ChangeLog
|
||||
INSTALL
|
||||
Make.rules
|
||||
.gdbinit
|
||||
/.bootstrap
|
||||
/ABOUT-NLS
|
||||
/ChangeLog
|
||||
/INSTALL
|
||||
/Make.rules
|
||||
/aclocal.m4
|
||||
/build-aux/
|
||||
/conf*
|
||||
!/configure.ac
|
||||
/gnu/
|
||||
/m4/
|
||||
/rmt/
|
||||
/stamp-h1
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
build-aux
|
||||
build-aux/
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
gnu
|
||||
libtool
|
||||
m4
|
||||
rmt
|
||||
stamp-h1
|
||||
TAGS
|
||||
|
||||
8
COPYING
8
COPYING
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
@@ -2,7 +2,7 @@ Currently there is just one ChangeLog file for tar, but
|
||||
there used to be separate ChangeLog files for each subdirectory.
|
||||
This file records what used to be in those separate files.
|
||||
|
||||
Copyright 1989-1997, 2013 Free Software Foundation, Inc.
|
||||
Copyright 1989-1997, 2013, 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ Currently the ChangeLog is generated automatically from the Git
|
||||
revision history, but from 1997 to 2009 the ChangeLog file was
|
||||
maintained by hand, under CVS. This file records the older log.
|
||||
|
||||
Copyright 1997-2001, 2003-2009, 2013 Free Software Foundation, Inc.
|
||||
Copyright 1997-2001, 2003-2009, 2013, 2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Main Makefile for GNU tar.
|
||||
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2007, 2009, 2013-2014, 2016-2017
|
||||
# Free Software Foundation, Inc.
|
||||
# Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
153
NEWS
153
NEWS
@@ -1,5 +1,150 @@
|
||||
GNU tar NEWS - User visible changes. 2017-12-17
|
||||
GNU tar NEWS - User visible changes. 2023-07-18
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
version 1.35 - Sergey Poznyakoff, 2023-07-18
|
||||
|
||||
* Fail when building GNU tar, if the platform supports 64-bit time_t
|
||||
but the build uses only 32-bit time_t.
|
||||
|
||||
* Leave the devmajor and devminor fields empty (rather than zero) for
|
||||
non-special files, as this is more compatible with traditional tar.
|
||||
|
||||
* Bug fixes
|
||||
|
||||
** Fix interaction of --update with --wildcards.
|
||||
|
||||
** When extracting archives into an empty directory, do not create
|
||||
hard links to files outside that directory.
|
||||
|
||||
** Handle partial reads from regular files.
|
||||
|
||||
** Warn "file changed as we read it" less often.
|
||||
Formerly, tar warned if the file's size or ctime changed.
|
||||
However, this generated a false positive if tar read a file
|
||||
while another process hard-linked to it, changing its ctime.
|
||||
Now, tar warns if the file's size, mtime, user ID, group ID,
|
||||
or mode changes. Although neither heuristic is perfect,
|
||||
the new one should work better in practice.
|
||||
|
||||
** Fix --ignore-failed-read to ignore file-changed read errors
|
||||
as far as exit status is concerned. You can now suppress file-changed
|
||||
issues entirely with --ignore-failed-read --warning=no-file-changed.
|
||||
|
||||
** Fix --remove-files to not remove a file that changed while we read it.
|
||||
|
||||
** Fix --atime-preserve=replace to not fail if there was no need to replace,
|
||||
either because we did not read the file, or the atime did not change.
|
||||
|
||||
** Fix race when creating a parent directory while another process is
|
||||
also doing so.
|
||||
|
||||
** Fix handling of prefix keywords not followed by "." in pax headers.
|
||||
|
||||
** Fix handling of out-of-range sparse entries in pax headers.
|
||||
|
||||
** Fix handling of --transform='s/s/@/2'.
|
||||
|
||||
** Fix treatment of options ending in / in files-from list.
|
||||
|
||||
** Fix crash on 'tar --checkpoint-action exec=\"'.
|
||||
|
||||
** Fix low-memory crash when reading incremental dumps.
|
||||
|
||||
** Fix --exclude-vcs-ignores memory allocation misuse.
|
||||
|
||||
|
||||
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
|
||||
@@ -42,7 +187,7 @@ causing subsequent link extractions in that directory to fail.
|
||||
|
||||
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.
|
||||
with the --ignore-failed-read option.
|
||||
|
||||
* The --warnings=none option now suppresses all warnings
|
||||
|
||||
@@ -1641,7 +1786,7 @@ Versions 1.07 back to 1.00 by Jay Fenlason.
|
||||
|
||||
|
||||
|
||||
Copyright 1994-2001, 2003-2010, 2013-2017 Free Software Foundation, Inc.
|
||||
Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -1661,7 +1806,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
Local variables:
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
eval: (add-hook 'write-file-functions #'time-stamp nil t)
|
||||
time-stamp-start: "changes. "
|
||||
time-stamp-format: "%:y-%02m-%02d"
|
||||
time-stamp-end: "\n"
|
||||
|
||||
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1990-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
33
README-alpha
33
README-alpha
@@ -3,40 +3,9 @@ This is GNU tar.
|
||||
This is a *pre-release* version, and not ready for production use yet.
|
||||
Please send comments and problem reports to <bug-tar@gnu.org>.
|
||||
|
||||
If you have taken the sources from CVS you will need the following
|
||||
packages (or later) to build GNU tar. We don't make any extra effort
|
||||
to accommodate older versions of these packages, so please make sure
|
||||
that you have the latest stable version.
|
||||
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Autoconf <http://www.gnu.org/software/autoconf/>
|
||||
- Bison <http://www.gnu.org/software/bison/>
|
||||
- Gettext <http://www.gnu.org/software/gettext/>
|
||||
- Gzip <http://www.gnu.org/software/gzip/>
|
||||
- M4 <http://www.gnu.org/software/m4/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Wget <http://www.gnu.org/software/wget/>
|
||||
|
||||
As of this writing, the latest stable version of Gzip is 1.2.4 but we
|
||||
suggest using test version 1.3.5 (or later, if one becomes available).
|
||||
|
||||
Valgrind <http://valgrind.org/> is also highly recommended, if
|
||||
Valgrind supports your architecture.
|
||||
|
||||
Before building the package, run "bootstrap". It will obtain gnulib
|
||||
and paxutils files from their Git repositories on Savannah. Then, it will
|
||||
fetch the po files from tar page at Translation Project, and, finally, it
|
||||
will start autoconfiguration process. Simply running bootstrap without
|
||||
arguments should do in most cases.
|
||||
|
||||
Bootstrap reads its configuration from file bootstrap.conf located on the
|
||||
top of tar source tree. Several options are provided that modify its
|
||||
behavior. Run 'bootstrap --help' for a list.
|
||||
|
||||
|
||||
|
||||
Copyright 2001, 2003-2005, 2007, 2013-2017 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2001-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -8,11 +8,22 @@ tar. We do not make any efforts to accommodate older versions of
|
||||
these packages, so please make sure that you have the latest stable
|
||||
version.
|
||||
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Autoconf <http://www.gnu.org/software/autoconf/>
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Bison <http://www.gnu.org/software/bison/>
|
||||
- M4 <http://www.gnu.org/software/m4/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Gettext <http://www.gnu.org/software/gettext/>
|
||||
- Git <http://git.or.cz>
|
||||
- Gzip <http://www.gnu.org/software/gzip/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Wget <http://www.gnu.org/software/wget/>
|
||||
|
||||
Up-to-date compilers and libraries are also recommended, for better
|
||||
static checking. You may be able to use an older compiler by building
|
||||
with 'make WERROR_CFLAGS='; if so, don't worry about its false alarms.
|
||||
|
||||
Valgrind <http://valgrind.org/> is also highly recommended, if
|
||||
Valgrind supports your architecture.
|
||||
|
||||
* Bootstrapping
|
||||
|
||||
@@ -34,12 +45,26 @@ INSTALLATION).
|
||||
Normally you will have to run bootstrap only once. However, if you
|
||||
intend to hack on GNU tar, you might need to run it again later.
|
||||
There are lots of options that you may find useful in this case.
|
||||
See 'bootstrap --help' for a detailed list.
|
||||
See './bootstrap --help' for a detailed list.
|
||||
|
||||
Bootstrapping obtains Gnulib and Paxutils files from their Git
|
||||
repositories on Savannah. Then, it fetches translations from the
|
||||
Translation Project, and, finally, it builds files useful for
|
||||
configuration. Simply running ./bootstrap without arguments should do
|
||||
in most cases.
|
||||
|
||||
The file bootstrap.conf contains bootstrapping configuration.
|
||||
Several options are provided that modify its behavior.
|
||||
Run './bootstrap --help' for a list.
|
||||
|
||||
To only fetch auxiliary files from the network, run './bootstrap --pull'.
|
||||
To only generate files such as 'configure', without accessing the
|
||||
network, run './bootstrap --gen'.
|
||||
|
||||
|
||||
* Copyright information
|
||||
|
||||
Copyright 2007-2009, 2013-2017 Free Software Foundation, Inc.
|
||||
Copyright 2007-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
2
THANKS
2
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
|
||||
|
||||
3
TODO
3
TODO
@@ -45,8 +45,7 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright 2003-2004, 2007, 2013-2014, 2016-2017 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright 2003-2023 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-2017 Free Software Foundation, Inc.
|
||||
dnl Copyright 2009-2023 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is part of GNU tar.
|
||||
dnl
|
||||
@@ -21,7 +21,7 @@ AC_DEFUN([TAR_COMPR_PROGRAM],[
|
||||
m4_pushdef([tar_compr_define],translit($1,[a-z+-],[A-ZX_])[_PROGRAM])
|
||||
m4_pushdef([tar_compr_var],[tar_cv_compressor_]translit($1,[+-],[x_]))
|
||||
AC_ARG_WITH($1,
|
||||
AC_HELP_STRING([--with-]$1[=PROG],
|
||||
AS_HELP_STRING([--with-]$1[=PROG],
|
||||
[use PROG as ]$1[ compressor program]),
|
||||
[tar_compr_var=${withval}],
|
||||
[tar_compr_var=m4_if($2,,$1,$2)])
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Bootstrap configuration for GNU tar.
|
||||
|
||||
# Copyright 2006-2009, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -61,21 +60,19 @@ if [ -r .bootstrap ]; then
|
||||
eval set -- "`sed 's/#.*$//;/^$/d' .bootstrap | tr '\n' ' '` $*"
|
||||
fi
|
||||
|
||||
test -d m4 || mkdir m4
|
||||
test -d $source_base || mkdir $source_base
|
||||
bootstrap_post_pull_hook() {
|
||||
mkdir -p m4 $source_base
|
||||
git submodule init
|
||||
git submodule update
|
||||
}
|
||||
|
||||
test -f ChangeLog || cat > ChangeLog <<EOT
|
||||
This file is a placeholder. It will be replaced with the actual ChangeLog
|
||||
by make dist. Run make ChangeLog if you wish to create it earlier.
|
||||
EOT
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
PAXUTILS=paxutils
|
||||
|
||||
# gnulib modules used by this package.
|
||||
# getopt-gnu is for paxutils.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep -h '^[^#]' gnulib.modules $PAXUTILS/gnulib.modules`
|
||||
`grep -h '^[^#]' gnulib.modules`
|
||||
getopt-gnu
|
||||
"
|
||||
|
||||
# copy_files srcdir dstdir
|
||||
@@ -101,27 +98,30 @@ copy_files() {
|
||||
done
|
||||
}
|
||||
|
||||
# Import from paxutils
|
||||
copy_files ${PAXUTILS} .
|
||||
copy_files ${PAXUTILS}/am m4
|
||||
bootstrap_post_import_hook() {
|
||||
|
||||
echo "$0: Creating m4/paxutils.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([${package}_PAXUTILS],["
|
||||
cat ${PAXUTILS}/am/DISTFILES | sed '/^#/d;s/\(.*\)\.m4/pu_\1/' | tr a-z A-Z
|
||||
echo "])") > ./m4/paxutils.m4
|
||||
#FIXME ignorefile m4 paxutils.m4
|
||||
test -f ChangeLog || cat > ChangeLog <<EOT
|
||||
This file is a placeholder. It will be replaced with the actual ChangeLog
|
||||
by make dist. Run make ChangeLog if you wish to create it earlier.
|
||||
EOT
|
||||
|
||||
if [ -d rmt ]; then
|
||||
:
|
||||
else
|
||||
mkdir rmt
|
||||
fi
|
||||
# Import from paxutils
|
||||
copy_files ${PAXUTILS} .
|
||||
copy_files ${PAXUTILS}/am m4
|
||||
|
||||
for dir in doc rmt lib tests
|
||||
do
|
||||
copy_files ${PAXUTILS}/$dir $dir
|
||||
done
|
||||
echo "$0: Creating m4/paxutils.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([${package}_PAXUTILS],["
|
||||
cat ${PAXUTILS}/am/DISTFILES | sed '/^#/d;s/\(.*\)\.m4/pu_\1/' | tr a-z A-Z
|
||||
echo "])") > ./m4/paxutils.m4
|
||||
#FIXME ignorefile m4 paxutils.m4
|
||||
|
||||
copy_files ${PAXUTILS}/paxlib lib pax
|
||||
mkdir -p rmt
|
||||
|
||||
for dir in doc rmt lib tests; do
|
||||
copy_files ${PAXUTILS}/$dir $dir
|
||||
done
|
||||
|
||||
copy_files ${PAXUTILS}/paxlib lib pax
|
||||
}
|
||||
|
||||
67
configure.ac
67
configure.ac
@@ -1,6 +1,6 @@
|
||||
# Configure template for GNU tar. -*- autoconf -*-
|
||||
|
||||
# Copyright 1991, 1994-2010, 2013-2017 Free Software Foundation, Inc.
|
||||
# Copyright 1991, 1994-2010, 2013-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -17,17 +17,17 @@
|
||||
# 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.30], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.35], [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.71])
|
||||
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])
|
||||
|
||||
AC_PROG_CC_STDC
|
||||
AC_PROG_CC
|
||||
AC_EXEEXT
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_YACC
|
||||
@@ -35,7 +35,6 @@ gl_EARLY
|
||||
AC_CHECK_TOOLS([AR], [ar])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_C_INLINE
|
||||
|
||||
AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h memory.h net/errno.h \
|
||||
sgtty.h string.h \
|
||||
@@ -53,10 +52,14 @@ AC_HEADER_MAJOR
|
||||
|
||||
AC_MSG_CHECKING([for st_fstype string in struct stat])
|
||||
AC_CACHE_VAL(diff_cv_st_fstype_string,
|
||||
[AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <sys/stat.h>], [struct stat s; s.st_fstype[0] = 'x';],
|
||||
diff_cv_st_fstype_string=yes,
|
||||
diff_cv_st_fstype_string=no)])
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
]],
|
||||
[[struct stat s; s.st_fstype[0] = 'x';]])],
|
||||
[diff_cv_st_fstype_string=yes],
|
||||
[diff_cv_st_fstype_string=no])])
|
||||
AC_MSG_RESULT($diff_cv_st_fstype_string)
|
||||
if test $diff_cv_st_fstype_string = yes; then
|
||||
AC_DEFINE(HAVE_ST_FSTYPE_STRING, 1,
|
||||
@@ -102,6 +105,32 @@ gt_TYPE_SSIZE_T
|
||||
|
||||
# gnulib modules
|
||||
gl_INIT
|
||||
|
||||
AC_DEFINE([GNULIB_EXCLUDE_SINGLE_THREAD], [1],
|
||||
[Define if all programs in this package call functions of the Gnulib
|
||||
'exclude' module only from a single thread.])
|
||||
AC_DEFINE([GNULIB_MBRTOWC_SINGLE_THREAD], [1],
|
||||
[Define if all programs in this package call functions of the Gnulib
|
||||
'mbtowc' module only from a single thread.])
|
||||
AC_DEFINE([GNULIB_REGEX_SINGLE_THREAD], [1],
|
||||
[Define if all programs in this package call functions of the Gnulib
|
||||
'regex' module only from a single thread.])
|
||||
AC_DEFINE([GNULIB_WCHAR_SINGLE_LOCALE], [1],
|
||||
[Define if all programs in this package call locale-sensitive functions
|
||||
like mbrtowc only after setting the locale, and never change the
|
||||
locale once set.])
|
||||
|
||||
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
|
||||
|
||||
@@ -133,7 +162,7 @@ AC_ARG_ENABLE([gcc-warnings],
|
||||
gl_gcc_warnings=$enableval],
|
||||
[gl_gcc_warnings=no
|
||||
if test -d "$srcdir"/.git; then
|
||||
gl_GCC_VERSION_IFELSE([4], [6], [gl_gcc_warnings=yes])
|
||||
gl_GCC_VERSION_IFELSE([11], [2], [gl_gcc_warnings=yes])
|
||||
fi]
|
||||
)
|
||||
|
||||
@@ -150,6 +179,7 @@ if test "$gl_gcc_warnings" = yes; then
|
||||
nw="$nw -Winline" # It's OK to not inline.
|
||||
nw="$nw -Wstrict-overflow" # It's OK to optimize strictly.
|
||||
nw="$nw -Wsuggest-attribute=pure" # Too many warnings for now.
|
||||
nw="$nw -Wsystem-headers" # Don't let system headers trigger warnings
|
||||
nw="$nw -Wstack-protector"
|
||||
|
||||
gl_MANYWARN_ALL_GCC([ws])
|
||||
@@ -159,12 +189,11 @@ if test "$gl_gcc_warnings" = yes; then
|
||||
done
|
||||
gl_WARN_ADD([-Wno-sign-compare]) # Too many warnings for now
|
||||
gl_WARN_ADD([-Wno-type-limits]) # It's OK to optimize based on types.
|
||||
gl_WARN_ADD([-Wno-unused-parameter]) # Too many warnings for now
|
||||
gl_WARN_ADD([-Wno-format-nonliteral])
|
||||
|
||||
|
||||
gl_WARN_ADD([-fdiagnostics-show-option])
|
||||
gl_WARN_ADD([-funit-at-a-time])
|
||||
|
||||
|
||||
|
||||
AC_SUBST([WARN_CFLAGS])
|
||||
|
||||
@@ -250,6 +279,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)
|
||||
|
||||
@@ -343,7 +373,7 @@ AC_CHECK_TYPE(iconv_t,:,
|
||||
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-formatstring-macros])
|
||||
AM_GNU_GETTEXT_VERSION([0.16])
|
||||
AM_GNU_GETTEXT_VERSION([0.21])
|
||||
|
||||
# Initialize the test suite.
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
@@ -353,8 +383,8 @@ AM_MISSING_PROG([AUTOM4TE], [autom4te])
|
||||
AC_SUBST(BACKUP_LIBEXEC_SCRIPTS)
|
||||
AC_SUBST(BACKUP_SBIN_SCRIPTS)
|
||||
AC_ARG_ENABLE(backup-scripts,
|
||||
AC_HELP_STRING([--enable-backup-scripts],
|
||||
[Create and install backup and restore scripts]),
|
||||
AS_HELP_STRING([--enable-backup-scripts],
|
||||
[Create and install backup and restore scripts]),
|
||||
[case $enableval in
|
||||
yes) BACKUP_LIBEXEC_SCRIPTS='$(BACKUP_LIBEXEC_SCRIPTS_LIST)'
|
||||
BACKUP_SBIN_SCRIPTS='$(BACKUP_SBIN_SCRIPTS_LIST)'
|
||||
@@ -368,7 +398,7 @@ else
|
||||
BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
|
||||
fi
|
||||
|
||||
AC_OUTPUT([Makefile\
|
||||
AC_CONFIG_FILES([Makefile\
|
||||
doc/Makefile\
|
||||
gnu/Makefile\
|
||||
lib/Makefile\
|
||||
@@ -376,3 +406,4 @@ AC_OUTPUT([Makefile\
|
||||
scripts/Makefile\
|
||||
rmt/Makefile\
|
||||
src/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
%%comments:
|
||||
Copyright 2004, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2004-2023 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-2017
|
||||
# Free Software Foundation, Inc.
|
||||
# Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -23,7 +22,6 @@ tar_TEXINFOS = \
|
||||
dumpdir.texi\
|
||||
tar-snapshot-edit.texi\
|
||||
fdl.texi\
|
||||
freemanuals.texi\
|
||||
genfile.texi\
|
||||
header.texi\
|
||||
intern.texi\
|
||||
@@ -140,9 +138,9 @@ check-docs:
|
||||
clean-local:
|
||||
rm -rf manual
|
||||
|
||||
GENDOCS=gendocs.sh
|
||||
GENDOCS=$(srcdir)/gendocs.sh
|
||||
|
||||
TEXI2DVI=texi2dvi -t '@set $(RENDITION)' -E
|
||||
TEXI2DVI=texi2dvi -E
|
||||
|
||||
# Make sure you set TEXINPUTS
|
||||
# Usual value is:
|
||||
@@ -150,5 +148,8 @@ TEXI2DVI=texi2dvi -t '@set $(RENDITION)' -E
|
||||
manual:
|
||||
TEXINPUTS=$(srcdir):$(top_srcdir)/build-tex:$(TEXINPUTS) \
|
||||
MAKEINFO="$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
TEXI2DVI="$(TEXI2DVI) -t @finalout" \
|
||||
TEXI2DVI="$(TEXI2DVI) -t '@set DISTRIB' -t @finalout" \
|
||||
$(GENDOCS) --texi2html tar 'GNU tar manual'
|
||||
|
||||
manual-rebuild: clean-local manual
|
||||
|
||||
|
||||
91
doc/README.manual
Normal file
91
doc/README.manual
Normal file
@@ -0,0 +1,91 @@
|
||||
* Overview
|
||||
|
||||
This file is a short instruction for maintainers on how to create and
|
||||
publish the online version of the Tar Manual.
|
||||
|
||||
In the sections below we assume that the tar project has been properly
|
||||
cloned from the git repo, bootstrapped and configured. We also assume
|
||||
that top-level directory of the project is the current local directory.
|
||||
|
||||
* Creating the web manual
|
||||
|
||||
To create the online version of the documentation, run
|
||||
|
||||
make -C doc manual-rebuild
|
||||
|
||||
This will create the directory doc/manual populated with the tar
|
||||
documentation files in various formats. If the doc/manual directory
|
||||
already exists, it will be removed prior to rebuilding.
|
||||
|
||||
The command produces very copious output. We advise you to examine it
|
||||
closely to make sure no error messages slip your attention.
|
||||
|
||||
For the completeness sake, there are two more Makefile goals related
|
||||
to the online manual:
|
||||
|
||||
** make -C doc clean-local
|
||||
|
||||
Removes the doc/manual directory, if it exists.
|
||||
|
||||
** make -C doc manual
|
||||
|
||||
Builds the doc/manual, unless it already exists.
|
||||
|
||||
* CVS Repository
|
||||
|
||||
The online tar manual[1] is a part of tar web pages[2] and is
|
||||
traditionally maintained in the CVS repository[3]. To publish the
|
||||
generated documentation, you will need first to check out tar web
|
||||
pages from the CVS. To do so, run
|
||||
|
||||
cvs -z3 -d:ext:<username>@cvs.savannah.gnu.org:/web/tar co tar
|
||||
|
||||
where <username> is your user name on Savannah. For the rest of this
|
||||
document we will assume that the checked out version of the tar web
|
||||
pages resides in the ~/websrc/tar directory.
|
||||
|
||||
If you have already checked out the web pages, be sure to update them
|
||||
before publishing:
|
||||
|
||||
cd ~/websrc/tar
|
||||
cvs update
|
||||
|
||||
* Publishing
|
||||
|
||||
To publish the created manual, change to the tar top-level directory
|
||||
and run:
|
||||
|
||||
rsync -avz --exclude CVS --delete manual ~/websrc/tar
|
||||
|
||||
This will synchronize the newly created manual pages with the content
|
||||
of the CVS sandbox. Then, change to the ~/websrc/tar directory and
|
||||
schedule any removed files for removal and any new files for addition
|
||||
to the repository:
|
||||
|
||||
cvs diff --brief 2>&1 | sed -n 's/.*cannot find //p' | xargs cvs rm
|
||||
cvs diff --brief 2>&1 | sed -n 's/^? //p' | xargs cvs add
|
||||
|
||||
Then commit your changes:
|
||||
|
||||
cvs commit
|
||||
|
||||
Once the changes are committed to CVS a job is scheduled on the server,
|
||||
which synchronizes them with the content of the directory served by
|
||||
the httpd daemon. Normally such synchronization happens within
|
||||
several seconds from the commit.
|
||||
|
||||
For more information about CVS, please see its documentation[4].
|
||||
|
||||
* References
|
||||
|
||||
[1] https://www.gnu.org/software/tar/manual/
|
||||
[2] https://www.gnu.org/software/tar/
|
||||
[3] https://web.cvs.savannah.gnu.org/viewvc/tar/
|
||||
[4] https://www.nongnu.org/cvs/#documentation
|
||||
|
||||
|
||||
Local Variables:
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
version-control: never
|
||||
End:
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006-2007, 2014, 2016-2017 Free Software Foundation,
|
||||
@c Inc.
|
||||
@c Copyright (C) 2006--2023 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.
|
||||
|
||||
13
doc/fdl.texi
13
doc/fdl.texi
@@ -5,9 +5,9 @@
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000-2002, 2007-2008, 2014, 2016-2017 Free
|
||||
Software Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
Copyright @copyright{} 2000--2002, 2007--2008, 2022 Free Software
|
||||
Foundation, Inc.
|
||||
@uref{https://fsf.org/}
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
@@ -98,7 +98,7 @@ format, SGML or XML using a publicly available
|
||||
DTD, and standard-conforming simple HTML,
|
||||
PostScript or PDF designed for human modification. Examples
|
||||
of transparent image formats include PNG, XCF and
|
||||
JPG. Opaque formats include proprietary formats that can be
|
||||
JPG@. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, SGML or
|
||||
XML for which the DTD and/or processing tools are
|
||||
not generally available, and the machine-generated HTML,
|
||||
@@ -415,7 +415,7 @@ The Free Software Foundation may publish new, revised versions
|
||||
of the GNU Free Documentation License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns. See
|
||||
@uref{http://www.gnu.org/copyleft/}.
|
||||
@uref{https://www.gnu.org/licenses/}.
|
||||
|
||||
Each version of the License is given a distinguishing version number.
|
||||
If the Document specifies that a particular numbered version of this
|
||||
@@ -482,7 +482,7 @@ license notices just after the title page:
|
||||
@end smallexample
|
||||
|
||||
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
|
||||
replace the ``with@dots{}Texts.'' line with this:
|
||||
replace the ``with@dots{}Texts.''@: line with this:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -504,4 +504,3 @@ to permit their use in free software.
|
||||
@c Local Variables:
|
||||
@c ispell-local-pdict: "ispell-dict"
|
||||
@c End:
|
||||
|
||||
|
||||
@@ -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}.
|
||||
512
doc/gendocs.sh
Executable file
512
doc/gendocs.sh
Executable file
@@ -0,0 +1,512 @@
|
||||
#!/bin/sh -e
|
||||
# gendocs.sh -- generate a GNU manual in many formats. This script is
|
||||
# mentioned in maintain.texi. See the help message below for usage details.
|
||||
|
||||
scriptversion=2021-03-01.13
|
||||
|
||||
# Copyright 2003-2023 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 of the License, 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 <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Original author: Mohit Agarwal.
|
||||
# Send bug reports and any other correspondence to bug-gnulib@gnu.org.
|
||||
#
|
||||
# The latest version of this script, and the companion template, is
|
||||
# available from the Gnulib repository:
|
||||
#
|
||||
# https://git.savannah.gnu.org/cgit/gnulib.git/tree/build-aux/gendocs.sh
|
||||
# https://git.savannah.gnu.org/cgit/gnulib.git/tree/doc/gendocs_template
|
||||
|
||||
# TODO:
|
||||
# - image importing was only implemented for HTML generated by
|
||||
# makeinfo. But it should be simple enough to adjust.
|
||||
# - images are not imported in the source tarball. All the needed
|
||||
# formats (PDF, PNG, etc.) should be included.
|
||||
|
||||
prog=`basename "$0"`
|
||||
srcdir=`pwd`
|
||||
|
||||
scripturl="https://git.savannah.gnu.org/cgit/gnulib.git/plain/build-aux/gendocs.sh"
|
||||
templateurl="https://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/gendocs_template"
|
||||
|
||||
: ${SETLANG="env LANG= LC_MESSAGES= LC_ALL= LANGUAGE="}
|
||||
: ${MAKEINFO="makeinfo"}
|
||||
: ${TEXI2DVI="texi2dvi"}
|
||||
: ${DOCBOOK2HTML="docbook2html"}
|
||||
: ${DOCBOOK2PDF="docbook2pdf"}
|
||||
: ${DOCBOOK2TXT="docbook2txt"}
|
||||
: ${GENDOCS_TEMPLATE_DIR="."}
|
||||
: ${PERL='perl'}
|
||||
: ${TEXI2HTML="texi2html"}
|
||||
unset CDPATH
|
||||
unset use_texi2html
|
||||
|
||||
MANUAL_TITLE=
|
||||
PACKAGE=
|
||||
EMAIL=webmasters@gnu.org # please override with --email
|
||||
commonarg= # passed to all makeinfo/texi2html invcations.
|
||||
dirargs= # passed to all tools (-I dir).
|
||||
dirs= # -I directories.
|
||||
htmlarg="--css-ref=/software/gnulib/manual.css -c TOP_NODE_UP_URL=/manual"
|
||||
default_htmlarg=true
|
||||
infoarg=--no-split
|
||||
generate_ascii=true
|
||||
generate_html=true
|
||||
generate_info=true
|
||||
generate_tex=true
|
||||
outdir=manual
|
||||
source_extra=
|
||||
split=node
|
||||
srcfile=
|
||||
texarg="-t @finalout"
|
||||
|
||||
version="gendocs.sh $scriptversion
|
||||
|
||||
Copyright 2021 Free Software Foundation, Inc.
|
||||
There is NO warranty. You may redistribute this software
|
||||
under the terms of the GNU General Public License.
|
||||
For more information about these matters, see the files named COPYING."
|
||||
|
||||
usage="Usage: $prog [OPTION]... PACKAGE MANUAL-TITLE
|
||||
|
||||
Generate output in various formats from PACKAGE.texinfo (or .texi or
|
||||
.txi) source. See the GNU Maintainers document for a more extensive
|
||||
discussion:
|
||||
https://www.gnu.org/prep/maintain_toc.html
|
||||
|
||||
Options:
|
||||
--email ADR use ADR as contact in generated web pages; always give this.
|
||||
|
||||
-s SRCFILE read Texinfo from SRCFILE, instead of PACKAGE.{texinfo|texi|txi}
|
||||
-o OUTDIR write files into OUTDIR, instead of manual/.
|
||||
-I DIR append DIR to the Texinfo search path.
|
||||
--common ARG pass ARG in all invocations.
|
||||
--html ARG pass ARG to makeinfo or texi2html for HTML targets,
|
||||
instead of '$htmlarg'.
|
||||
--info ARG pass ARG to makeinfo for Info, instead of --no-split.
|
||||
--no-ascii skip generating the plain text output.
|
||||
--no-html skip generating the html output.
|
||||
--no-info skip generating the info output.
|
||||
--no-tex skip generating the dvi and pdf output.
|
||||
--source ARG include ARG in tar archive of sources.
|
||||
--split HOW make split HTML by node, section, chapter; default node.
|
||||
--tex ARG pass ARG to texi2dvi for DVI and PDF, instead of -t @finalout.
|
||||
|
||||
--texi2html use texi2html to make HTML target, with all split versions.
|
||||
--docbook convert through DocBook too (xml, txt, html, pdf).
|
||||
|
||||
--help display this help and exit successfully.
|
||||
--version display version information and exit successfully.
|
||||
|
||||
Simple example: $prog --email bug-gnu-emacs@gnu.org emacs \"GNU Emacs Manual\"
|
||||
|
||||
Typical sequence:
|
||||
cd PACKAGESOURCE/doc
|
||||
wget \"$scripturl\"
|
||||
wget \"$templateurl\"
|
||||
$prog --email BUGLIST MANUAL \"GNU MANUAL - One-line description\"
|
||||
|
||||
Output will be in a new subdirectory \"manual\" (by default;
|
||||
use -o OUTDIR to override). Move all the new files into your web CVS
|
||||
tree, as explained in the Web Pages node of maintain.texi.
|
||||
|
||||
Please use the --email ADDRESS option so your own bug-reporting
|
||||
address will be used in the generated HTML pages.
|
||||
|
||||
MANUAL-TITLE is included as part of the HTML <title> of the overall
|
||||
manual/index.html file. It should include the name of the package being
|
||||
documented. manual/index.html is created by substitution from the file
|
||||
$GENDOCS_TEMPLATE_DIR/gendocs_template. (Feel free to modify the
|
||||
generic template for your own purposes.)
|
||||
|
||||
If you have several manuals, you'll need to run this script several
|
||||
times with different MANUAL values, specifying a different output
|
||||
directory with -o each time. Then write (by hand) an overall index.html
|
||||
with links to them all.
|
||||
|
||||
If a manual's Texinfo sources are spread across several directories,
|
||||
first copy or symlink all Texinfo sources into a single directory.
|
||||
(Part of the script's work is to make a tar.gz of the sources.)
|
||||
|
||||
As implied above, by default monolithic Info files are generated.
|
||||
If you want split Info, or other Info options, use --info to override.
|
||||
|
||||
You can set the environment variables MAKEINFO, TEXI2DVI, TEXI2HTML,
|
||||
and PERL to control the programs that get executed, and
|
||||
GENDOCS_TEMPLATE_DIR to control where the gendocs_template file is
|
||||
looked for. With --docbook, the environment variables DOCBOOK2HTML,
|
||||
DOCBOOK2PDF, and DOCBOOK2TXT are also consulted.
|
||||
|
||||
By default, makeinfo and texi2dvi are run in the default (English)
|
||||
locale, since that's the language of most Texinfo manuals. If you
|
||||
happen to have a non-English manual and non-English web site, see the
|
||||
SETLANG setting in the source.
|
||||
|
||||
Email bug reports or enhancement requests to bug-gnulib@gnu.org.
|
||||
"
|
||||
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
-s) shift; srcfile=$1;;
|
||||
-o) shift; outdir=$1;;
|
||||
-I) shift; dirargs="$dirargs -I '$1'"; dirs="$dirs $1";;
|
||||
--common) shift; commonarg=$1;;
|
||||
--docbook) docbook=yes;;
|
||||
--email) shift; EMAIL=$1;;
|
||||
--html) shift; default_htmlarg=false; htmlarg=$1;;
|
||||
--info) shift; infoarg=$1;;
|
||||
--no-ascii) generate_ascii=false;;
|
||||
--no-html) generate_ascii=false;;
|
||||
--no-info) generate_info=false;;
|
||||
--no-tex) generate_tex=false;;
|
||||
--source) shift; source_extra=$1;;
|
||||
--split) shift; split=$1;;
|
||||
--tex) shift; texarg=$1;;
|
||||
--texi2html) use_texi2html=1;;
|
||||
|
||||
--help) echo "$usage"; exit 0;;
|
||||
--version) echo "$version"; exit 0;;
|
||||
-*)
|
||||
echo "$0: Unknown option \`$1'." >&2
|
||||
echo "$0: Try \`--help' for more information." >&2
|
||||
exit 1;;
|
||||
*)
|
||||
if test -z "$PACKAGE"; then
|
||||
PACKAGE=$1
|
||||
elif test -z "$MANUAL_TITLE"; then
|
||||
MANUAL_TITLE=$1
|
||||
else
|
||||
echo "$0: extra non-option argument \`$1'." >&2
|
||||
exit 1
|
||||
fi;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# makeinfo uses the dirargs, but texi2dvi doesn't.
|
||||
commonarg=" $dirargs $commonarg"
|
||||
|
||||
# For most of the following, the base name is just $PACKAGE
|
||||
base=$PACKAGE
|
||||
|
||||
if $default_htmlarg && test -n "$use_texi2html"; then
|
||||
# The legacy texi2html doesn't support TOP_NODE_UP_URL
|
||||
htmlarg="--css-ref=/software/gnulib/manual.css"
|
||||
fi
|
||||
|
||||
if test -n "$srcfile"; then
|
||||
# but here, we use the basename of $srcfile
|
||||
base=`basename "$srcfile"`
|
||||
case $base in
|
||||
*.txi|*.texi|*.texinfo) base=`echo "$base"|sed 's/\.[texinfo]*$//'`;;
|
||||
esac
|
||||
PACKAGE=$base
|
||||
elif test -s "$srcdir/$PACKAGE.texinfo"; then
|
||||
srcfile=$srcdir/$PACKAGE.texinfo
|
||||
elif test -s "$srcdir/$PACKAGE.texi"; then
|
||||
srcfile=$srcdir/$PACKAGE.texi
|
||||
elif test -s "$srcdir/$PACKAGE.txi"; then
|
||||
srcfile=$srcdir/$PACKAGE.txi
|
||||
else
|
||||
echo "$0: cannot find .texinfo or .texi or .txi for $PACKAGE in $srcdir." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test ! -r $GENDOCS_TEMPLATE_DIR/gendocs_template; then
|
||||
echo "$0: cannot read $GENDOCS_TEMPLATE_DIR/gendocs_template." >&2
|
||||
echo "$0: it is available from $templateurl." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to return size of $1 in something resembling kilobytes.
|
||||
calcsize()
|
||||
{
|
||||
size=`ls -ksl $1 | awk '{print $1}'`
|
||||
echo $size
|
||||
}
|
||||
|
||||
# copy_images OUTDIR HTML-FILE...
|
||||
# -------------------------------
|
||||
# Copy all the images needed by the HTML-FILEs into OUTDIR.
|
||||
# Look for them in . and the -I directories; this is simpler than what
|
||||
# makeinfo supports with -I, but hopefully it will suffice.
|
||||
copy_images()
|
||||
{
|
||||
local odir
|
||||
odir=$1
|
||||
shift
|
||||
$PERL -n -e "
|
||||
BEGIN {
|
||||
\$me = '$prog';
|
||||
\$odir = '$odir';
|
||||
@dirs = qw(. $dirs);
|
||||
}
|
||||
" -e '
|
||||
/<img src="(.*?)"/g && ++$need{$1};
|
||||
|
||||
END {
|
||||
#print "$me: @{[keys %need]}\n"; # for debugging, show images found.
|
||||
FILE: for my $f (keys %need) {
|
||||
for my $d (@dirs) {
|
||||
if (-f "$d/$f") {
|
||||
use File::Basename;
|
||||
my $dest = dirname ("$odir/$f");
|
||||
#
|
||||
use File::Path;
|
||||
-d $dest || mkpath ($dest)
|
||||
|| die "$me: cannot mkdir $dest: $!\n";
|
||||
#
|
||||
use File::Copy;
|
||||
copy ("$d/$f", $dest)
|
||||
|| die "$me: cannot copy $d/$f to $dest: $!\n";
|
||||
next FILE;
|
||||
}
|
||||
}
|
||||
die "$me: $ARGV: cannot find image $f\n";
|
||||
}
|
||||
}
|
||||
' -- "$@" || exit 1
|
||||
}
|
||||
|
||||
case $outdir in
|
||||
/*) abs_outdir=$outdir;;
|
||||
*) abs_outdir=$srcdir/$outdir;;
|
||||
esac
|
||||
|
||||
echo "Making output for $srcfile"
|
||||
echo " in `pwd`"
|
||||
mkdir -p "$outdir/"
|
||||
|
||||
#
|
||||
if $generate_info; then
|
||||
cmd="$SETLANG $MAKEINFO -o $PACKAGE.info $commonarg $infoarg \"$srcfile\""
|
||||
echo "Generating info... ($cmd)"
|
||||
rm -f $PACKAGE.info* # get rid of any strays
|
||||
eval "$cmd"
|
||||
tar czf "$outdir/$PACKAGE.info.tar.gz" $PACKAGE.info*
|
||||
ls -l "$outdir/$PACKAGE.info.tar.gz"
|
||||
info_tgz_size=`calcsize "$outdir/$PACKAGE.info.tar.gz"`
|
||||
# do not mv the info files, there's no point in having them available
|
||||
# separately on the web.
|
||||
fi # end info
|
||||
|
||||
#
|
||||
if $generate_tex; then
|
||||
cmd="$SETLANG $TEXI2DVI $dirargs $texarg \"$srcfile\""
|
||||
printf "\nGenerating dvi... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
# compress/finish dvi:
|
||||
gzip -f -9 $PACKAGE.dvi
|
||||
dvi_gz_size=`calcsize $PACKAGE.dvi.gz`
|
||||
mv $PACKAGE.dvi.gz "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.dvi.gz"
|
||||
|
||||
cmd="$SETLANG $TEXI2DVI --pdf $dirargs $texarg \"$srcfile\""
|
||||
printf "\nGenerating pdf... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
pdf_size=`calcsize $PACKAGE.pdf`
|
||||
mv $PACKAGE.pdf "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.pdf"
|
||||
fi # end tex (dvi + pdf)
|
||||
|
||||
#
|
||||
if $generate_ascii; then
|
||||
opt="-o $PACKAGE.txt --no-split --no-headers $commonarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
|
||||
printf "\nGenerating ascii... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
ascii_size=`calcsize $PACKAGE.txt`
|
||||
gzip -f -9 -c $PACKAGE.txt >"$outdir/$PACKAGE.txt.gz"
|
||||
ascii_gz_size=`calcsize "$outdir/$PACKAGE.txt.gz"`
|
||||
mv $PACKAGE.txt "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.txt" "$outdir/$PACKAGE.txt.gz"
|
||||
fi
|
||||
|
||||
#
|
||||
|
||||
if $generate_html; then
|
||||
# Split HTML at level $1. Used for texi2html.
|
||||
html_split()
|
||||
{
|
||||
opt="--split=$1 --node-files $commonarg $htmlarg"
|
||||
cmd="$SETLANG $TEXI2HTML --output $PACKAGE.html $opt \"$srcfile\""
|
||||
printf "\nGenerating html by $1... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
split_html_dir=$PACKAGE.html
|
||||
(
|
||||
cd ${split_html_dir} || exit 1
|
||||
if [ ! -f index.html ]; then
|
||||
ln -sf ${PACKAGE}.html index.html
|
||||
fi
|
||||
tar -czf "$abs_outdir/${PACKAGE}.html_$1.tar.gz" -- *.html
|
||||
)
|
||||
eval html_$1_tgz_size=`calcsize "$outdir/${PACKAGE}.html_$1.tar.gz"`
|
||||
rm -f "$outdir"/html_$1/*.html
|
||||
mkdir -p "$outdir/html_$1/"
|
||||
mv ${split_html_dir}/*.html "$outdir/html_$1/"
|
||||
rmdir ${split_html_dir}
|
||||
}
|
||||
|
||||
if test -z "$use_texi2html"; then
|
||||
opt="--no-split --html -o $PACKAGE.html $commonarg $htmlarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
|
||||
printf "\nGenerating monolithic html... ($cmd)\n"
|
||||
rm -rf $PACKAGE.html # in case a directory is left over
|
||||
eval "$cmd"
|
||||
html_mono_size=`calcsize $PACKAGE.html`
|
||||
gzip -f -9 -c $PACKAGE.html >"$outdir/$PACKAGE.html.gz"
|
||||
html_mono_gz_size=`calcsize "$outdir/$PACKAGE.html.gz"`
|
||||
copy_images "$outdir/" $PACKAGE.html
|
||||
mv $PACKAGE.html "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.html" "$outdir/$PACKAGE.html.gz"
|
||||
|
||||
# Before Texinfo 5.0, makeinfo did not accept a --split=HOW option,
|
||||
# it just always split by node. So if we're splitting by node anyway,
|
||||
# leave it out.
|
||||
if test "x$split" = xnode; then
|
||||
split_arg=
|
||||
else
|
||||
split_arg=--split=$split
|
||||
fi
|
||||
#
|
||||
opt="--html -o $PACKAGE.html $split_arg $commonarg $htmlarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
|
||||
printf "\nGenerating html by $split... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
split_html_dir=$PACKAGE.html
|
||||
copy_images $split_html_dir/ $split_html_dir/*.html
|
||||
(
|
||||
cd $split_html_dir || exit 1
|
||||
tar -czf "$abs_outdir/$PACKAGE.html_$split.tar.gz" -- *
|
||||
)
|
||||
eval \
|
||||
html_${split}_tgz_size=`calcsize "$outdir/$PACKAGE.html_$split.tar.gz"`
|
||||
rm -rf "$outdir/html_$split/"
|
||||
mv $split_html_dir "$outdir/html_$split/"
|
||||
du -s "$outdir/html_$split/"
|
||||
ls -l "$outdir/$PACKAGE.html_$split.tar.gz"
|
||||
|
||||
else # use texi2html:
|
||||
opt="--output $PACKAGE.html $commonarg $htmlarg"
|
||||
cmd="$SETLANG $TEXI2HTML $opt \"$srcfile\""
|
||||
printf "\nGenerating monolithic html with texi2html... ($cmd)\n"
|
||||
rm -rf $PACKAGE.html # in case a directory is left over
|
||||
eval "$cmd"
|
||||
html_mono_size=`calcsize $PACKAGE.html`
|
||||
gzip -f -9 -c $PACKAGE.html >"$outdir/$PACKAGE.html.gz"
|
||||
html_mono_gz_size=`calcsize "$outdir/$PACKAGE.html.gz"`
|
||||
mv $PACKAGE.html "$outdir/"
|
||||
|
||||
html_split node
|
||||
html_split chapter
|
||||
html_split section
|
||||
fi
|
||||
fi # end html
|
||||
|
||||
#
|
||||
printf "\nMaking .tar.gz for sources...\n"
|
||||
d=`dirname $srcfile`
|
||||
(
|
||||
cd "$d"
|
||||
srcfiles=`ls -d *.texinfo *.texi *.txi *.eps $source_extra 2>/dev/null` || true
|
||||
tar czfh "$abs_outdir/$PACKAGE.texi.tar.gz" $srcfiles
|
||||
ls -l "$abs_outdir/$PACKAGE.texi.tar.gz"
|
||||
)
|
||||
texi_tgz_size=`calcsize "$outdir/$PACKAGE.texi.tar.gz"`
|
||||
|
||||
#
|
||||
# Do everything again through docbook.
|
||||
if test -n "$docbook"; then
|
||||
opt="-o - --docbook $commonarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\" >${srcdir}/$PACKAGE-db.xml"
|
||||
printf "\nGenerating docbook XML... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
docbook_xml_size=`calcsize $PACKAGE-db.xml`
|
||||
gzip -f -9 -c $PACKAGE-db.xml >"$outdir/$PACKAGE-db.xml.gz"
|
||||
docbook_xml_gz_size=`calcsize "$outdir/$PACKAGE-db.xml.gz"`
|
||||
mv $PACKAGE-db.xml "$outdir/"
|
||||
|
||||
split_html_db_dir=html_node_db
|
||||
opt="$commonarg -o $split_html_db_dir"
|
||||
cmd="$DOCBOOK2HTML $opt \"${outdir}/$PACKAGE-db.xml\""
|
||||
printf "\nGenerating docbook HTML... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
(
|
||||
cd ${split_html_db_dir} || exit 1
|
||||
tar -czf "$abs_outdir/${PACKAGE}.html_node_db.tar.gz" -- *.html
|
||||
)
|
||||
html_node_db_tgz_size=`calcsize "$outdir/${PACKAGE}.html_node_db.tar.gz"`
|
||||
rm -f "$outdir"/html_node_db/*.html
|
||||
mkdir -p "$outdir/html_node_db"
|
||||
mv ${split_html_db_dir}/*.html "$outdir/html_node_db/"
|
||||
rmdir ${split_html_db_dir}
|
||||
|
||||
cmd="$DOCBOOK2TXT \"${outdir}/$PACKAGE-db.xml\""
|
||||
printf "\nGenerating docbook ASCII... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
docbook_ascii_size=`calcsize $PACKAGE-db.txt`
|
||||
mv $PACKAGE-db.txt "$outdir/"
|
||||
|
||||
cmd="$DOCBOOK2PDF \"${outdir}/$PACKAGE-db.xml\""
|
||||
printf "\nGenerating docbook PDF... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
docbook_pdf_size=`calcsize $PACKAGE-db.pdf`
|
||||
mv $PACKAGE-db.pdf "$outdir/"
|
||||
fi
|
||||
|
||||
#
|
||||
printf "\nMaking index.html for $PACKAGE...\n"
|
||||
if test -z "$use_texi2html"; then
|
||||
CONDS="/%%IF *HTML_SECTION%%/,/%%ENDIF *HTML_SECTION%%/d;\
|
||||
/%%IF *HTML_CHAPTER%%/,/%%ENDIF *HTML_CHAPTER%%/d"
|
||||
else
|
||||
# should take account of --split here.
|
||||
CONDS="/%%ENDIF.*%%/d;/%%IF *HTML_SECTION%%/d;/%%IF *HTML_CHAPTER%%/d"
|
||||
fi
|
||||
|
||||
curdate=`$SETLANG date '+%B %d, %Y'`
|
||||
sed \
|
||||
-e "s!%%TITLE%%!$MANUAL_TITLE!g" \
|
||||
-e "s!%%EMAIL%%!$EMAIL!g" \
|
||||
-e "s!%%PACKAGE%%!$PACKAGE!g" \
|
||||
-e "s!%%DATE%%!$curdate!g" \
|
||||
-e "s!%%HTML_MONO_SIZE%%!$html_mono_size!g" \
|
||||
-e "s!%%HTML_MONO_GZ_SIZE%%!$html_mono_gz_size!g" \
|
||||
-e "s!%%HTML_NODE_TGZ_SIZE%%!$html_node_tgz_size!g" \
|
||||
-e "s!%%HTML_SECTION_TGZ_SIZE%%!$html_section_tgz_size!g" \
|
||||
-e "s!%%HTML_CHAPTER_TGZ_SIZE%%!$html_chapter_tgz_size!g" \
|
||||
-e "s!%%INFO_TGZ_SIZE%%!$info_tgz_size!g" \
|
||||
-e "s!%%DVI_GZ_SIZE%%!$dvi_gz_size!g" \
|
||||
-e "s!%%PDF_SIZE%%!$pdf_size!g" \
|
||||
-e "s!%%ASCII_SIZE%%!$ascii_size!g" \
|
||||
-e "s!%%ASCII_GZ_SIZE%%!$ascii_gz_size!g" \
|
||||
-e "s!%%TEXI_TGZ_SIZE%%!$texi_tgz_size!g" \
|
||||
-e "s!%%DOCBOOK_HTML_NODE_TGZ_SIZE%%!$html_node_db_tgz_size!g" \
|
||||
-e "s!%%DOCBOOK_ASCII_SIZE%%!$docbook_ascii_size!g" \
|
||||
-e "s!%%DOCBOOK_PDF_SIZE%%!$docbook_pdf_size!g" \
|
||||
-e "s!%%DOCBOOK_XML_SIZE%%!$docbook_xml_size!g" \
|
||||
-e "s!%%DOCBOOK_XML_GZ_SIZE%%!$docbook_xml_gz_size!g" \
|
||||
-e "s,%%SCRIPTURL%%,$scripturl,g" \
|
||||
-e "s!%%SCRIPTNAME%%!$prog!g" \
|
||||
-e "$CONDS" \
|
||||
$GENDOCS_TEMPLATE_DIR/gendocs_template >"$outdir/index.html"
|
||||
|
||||
echo "Done, see $outdir/ subdirectory for new files."
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
||||
174
doc/gendocs_template
Executable file → Normal file
174
doc/gendocs_template
Executable file → Normal file
@@ -1,125 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- $Id: gendocs_template,v 1.5 2007/10/30 14:58:52 gray Exp $ -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<!--#include virtual="/server/header.html" -->
|
||||
<!-- Parent-Version: 1.78 -->
|
||||
|
||||
<head>
|
||||
<title>%%TITLE%% - GNU Project - Free Software Foundation (FSF)</title>
|
||||
<meta http-equiv="content-type" content='text/html; charset=utf-8' />
|
||||
<link rel="stylesheet" type="text/css" href="/gnu.css" />
|
||||
<link rev="made" href="mailto:gray@gnu.org" />
|
||||
<link rel="icon" type="image/png" href="/graphics/gnu-head-icon.png" />
|
||||
</head>
|
||||
<!--
|
||||
Copyright (C) 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
<!-- This document is in XML, and xhtml 1.0 -->
|
||||
<!-- Please make sure to properly nest your tags -->
|
||||
<!-- and ensure that your final document validates -->
|
||||
<!-- consistent with W3C xhtml 1.0 and CSS standards -->
|
||||
<!-- See validator.w3.org -->
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without any warranty.
|
||||
-->
|
||||
|
||||
<body>
|
||||
|
||||
<h3>%%TITLE%%</h3>
|
||||
<title>%%TITLE%% - GNU Project - Free Software Foundation</title>
|
||||
<!--#include virtual="/server/banner.html" -->
|
||||
<h2>%%TITLE%%</h2>
|
||||
|
||||
<address>Free Software Foundation</address>
|
||||
<address>last updated %%DATE%%</address>
|
||||
<p>
|
||||
<a href="/graphics/gnu-head.jpg">
|
||||
<img src="/graphics/gnu-head-sm.jpg"
|
||||
alt=" [image of the head of a GNU] "
|
||||
width="129" height="122" />
|
||||
</a>
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<p>The manual for %%PACKAGE%% is available in the following formats:</p>
|
||||
<p>This manual (%%PACKAGE%%) is available in the following formats:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="%%PACKAGE%%.html">HTML
|
||||
(%%HTML_MONO_SIZE%%K bytes)</a> - entirely on one web page.</li>
|
||||
<li><a href="html_node/index.html">HTML</a> - with one web page per
|
||||
node.</li>
|
||||
<li><a href="%%PACKAGE%%.html">HTML
|
||||
(%%HTML_MONO_SIZE%%K bytes)</a> - entirely on one web page.</li>
|
||||
<li><a href="html_node/index.html">HTML</a> - with one web page per
|
||||
node.</li>
|
||||
%%IF HTML_SECTION%%
|
||||
<li><a href="html_section/index.html">HTML</a> - with one web page per
|
||||
section.</li>
|
||||
<li><a href="html_section/index.html">HTML</a> - with one web page per
|
||||
section.</li>
|
||||
%%ENDIF HTML_SECTION%%
|
||||
%%IF HTML_CHAPTER%%
|
||||
<li><a href="html_chapter/index.html">HTML</a> - with one web page per
|
||||
chapter.</li>
|
||||
<li><a href="html_chapter/index.html">HTML</a> - with one web page per
|
||||
chapter.</li>
|
||||
%%ENDIF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.html.gz">HTML compressed
|
||||
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
|
||||
one web page.</li>
|
||||
<li><a href="%%PACKAGE%%.html_node.tar.gz">HTML compressed
|
||||
(%%HTML_NODE_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per node.</li>
|
||||
<li><a href="%%PACKAGE%%.html.gz">HTML compressed
|
||||
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
|
||||
one web page.</li>
|
||||
<li><a href="%%PACKAGE%%.html_node.tar.gz">HTML compressed
|
||||
(%%HTML_NODE_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per node.</li>
|
||||
%%IF HTML_SECTION%%
|
||||
<li><a href="%%PACKAGE%%.html_section.tar.gz">HTML compressed
|
||||
(%%HTML_SECTION_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per section.</li>
|
||||
<li><a href="%%PACKAGE%%.html_section.tar.gz">HTML compressed
|
||||
(%%HTML_SECTION_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per section.</li>
|
||||
%%ENDIF HTML_SECTION%%
|
||||
%%IF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.html_chapter.tar.gz">HTML compressed
|
||||
(%%HTML_CHAPTER_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per chapter.</li>
|
||||
<li><a href="%%PACKAGE%%.html_chapter.tar.gz">HTML compressed
|
||||
(%%HTML_CHAPTER_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per chapter.</li>
|
||||
%%ENDIF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.info.tar.gz">Info document
|
||||
(%%INFO_TGZ_SIZE%%K characters gzipped tar file)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt">ASCII text
|
||||
(%%ASCII_SIZE%%K characters)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt.gz">ASCII text compressed
|
||||
(%%ASCII_GZ_SIZE%%K gzipped characters)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.dvi.gz">TeX dvi file
|
||||
(%%DVI_GZ_SIZE%%K characters gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.ps.gz">PostScript file
|
||||
(%%PS_GZ_SIZE%%K characters gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.pdf">PDF file
|
||||
(%%PDF_SIZE%%K characters)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.texi.tar.gz">Texinfo source
|
||||
(%%TEXI_TGZ_SIZE%%K characters gzipped tar file)</a></li>
|
||||
<li><a href="%%PACKAGE%%.info.tar.gz">Info document
|
||||
(%%INFO_TGZ_SIZE%%K bytes gzipped tar file)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt">ASCII text
|
||||
(%%ASCII_SIZE%%K bytes)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt.gz">ASCII text compressed
|
||||
(%%ASCII_GZ_SIZE%%K bytes gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.dvi.gz">TeX dvi file
|
||||
(%%DVI_GZ_SIZE%%K bytes gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.pdf">PDF file
|
||||
(%%PDF_SIZE%%K bytes)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.texi.tar.gz">Texinfo source
|
||||
(%%TEXI_TGZ_SIZE%%K bytes gzipped tar file).</a></li>
|
||||
</ul>
|
||||
|
||||
<p>(This page generated by the <a
|
||||
href="%%SCRIPTURL%%">%%SCRIPTNAME%%</a> script.)
|
||||
</p>
|
||||
<p>You can <a href="https://shop.fsf.org/">buy printed copies of
|
||||
some manuals</a> (among other items) from the Free Software Foundation;
|
||||
this helps support FSF activities.</p>
|
||||
|
||||
<p>
|
||||
<a href="http://validator.w3.org/check?uri=referer"><img
|
||||
src="http://www.w3.org/Icons/valid-xhtml10"
|
||||
alt="Valid XHTML 1.0!" height="31" width="88" /></a>
|
||||
</p>
|
||||
<p>(This page generated by the <a href="%%SCRIPTURL%%">%%SCRIPTNAME%%
|
||||
script</a>.)</p>
|
||||
|
||||
<div class="copyright">
|
||||
<p>
|
||||
Return to the <a href="/home.html">GNU Project home page</a>.
|
||||
</p>
|
||||
<!-- If needed, change the copyright block at the bottom. In general,
|
||||
all pages on the GNU web server should have the section about
|
||||
verbatim copying. Please do NOT remove this without talking
|
||||
with the webmasters first.
|
||||
Please make sure the copyright date is consistent with the document
|
||||
and that it is like this: "2001, 2002", not this: "2001-2002". -->
|
||||
</div><!-- for id="content", starts in the include above -->
|
||||
<!--#include virtual="/server/footer.html" -->
|
||||
<div id="footer">
|
||||
<div class="unprintable">
|
||||
|
||||
<p>
|
||||
Please send FSF & GNU inquiries to
|
||||
<a href="mailto:gnu@gnu.org"><em>gnu@gnu.org</em></a>.
|
||||
There are also <a href="/home.html#ContactInfo">other ways to contact</a>
|
||||
the FSF.
|
||||
<br />
|
||||
Please send broken links and other corrections (or suggestions) to
|
||||
<a href="mailto:webmasters@gnu.org"><em>webmasters@gnu.org</em></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Copyright 2004, 2013-2014, 2016-2017 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02111, USA
|
||||
<br />
|
||||
Verbatim copying and distribution of this entire article is
|
||||
permitted in any medium, provided this notice is preserved.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Updated:
|
||||
<!-- timestamp start -->
|
||||
$Date: 2007/10/30 14:58:52 $ $Author: gray $
|
||||
<!-- timestamp end -->
|
||||
</p>
|
||||
<p>Please send general FSF & GNU inquiries to
|
||||
<a href="mailto:gnu@gnu.org"><gnu@gnu.org></a>.
|
||||
There are also <a href="/contact/">other ways to contact</a>
|
||||
the FSF. Broken links and other corrections or suggestions can be sent
|
||||
to <a href="mailto:%%EMAIL%%"><%%EMAIL%%></a>.</p>
|
||||
</div>
|
||||
|
||||
<p>Copyright © 2020 Free Software Foundation, Inc.</p>
|
||||
|
||||
<p>This page is licensed under a <a rel="license"
|
||||
href="https://creativecommons.org/licenses/by-nd/3.0/us/">Creative
|
||||
Commons Attribution-NoDerivs 3.0 United States License</a>.</p>
|
||||
|
||||
<!--#include virtual="/server/bottom-notes.html" -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2014, 2016-2017 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2023 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
@node Standard
|
||||
@unnumberedsec Basic Tar Format
|
||||
@UNREVISED
|
||||
@UNREVISED{}
|
||||
|
||||
While an archive may contain many files, the archive itself is a
|
||||
single ordinary file. Like any other file, an archive file can be
|
||||
@@ -51,7 +51,10 @@ of the file. At the end of the archive file there are two 512-byte blocks
|
||||
filled with binary zeros as an end-of-file marker. A reasonable system
|
||||
should write such end-of-file marker at the end of an archive, but
|
||||
must not assume that such a block exists when reading an archive. In
|
||||
particular @GNUTAR{} always issues a warning if it does not encounter it.
|
||||
particular, @GNUTAR{} does not treat missing end-of-file marker as an
|
||||
error and silently ignores the fact. You can instruct it to issue
|
||||
a warning, however, by using the @option{--warning=missing-zero-blocks}
|
||||
option (@pxref{General Warnings, missing-zero-blocks}).
|
||||
|
||||
The blocks may be @dfn{blocked} for physical I/O operations.
|
||||
Each record of @var{n} blocks (where @var{n} is set by the
|
||||
@@ -111,8 +114,9 @@ The @code{uid} and @code{gid} fields are the numeric user and group
|
||||
not support numeric user or group @acronym{ID}s, these fields should
|
||||
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{size} field is the size of the file in bytes; for archive
|
||||
members that are symbolic or hard links to another file, this field
|
||||
is specified as zero.
|
||||
|
||||
The @code{mtime} field represents the data modification time of the file at
|
||||
the time it was archived. It represents the integer number of
|
||||
@@ -123,7 +127,7 @@ 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
|
||||
if it were all blanks.
|
||||
if it were filled with spaces (ASCII 32).
|
||||
|
||||
The @code{typeflag} field specifies the type of file archived. If a
|
||||
particular implementation does not recognize or permit the specified
|
||||
@@ -266,7 +270,7 @@ IEEE Std 1003.2-1992, pages 380-388 (section 4.48) and pages 936-940
|
||||
|
||||
@node Extensions
|
||||
@unnumberedsec @acronym{GNU} Extensions to the Archive Format
|
||||
@UNREVISED
|
||||
@UNREVISED{}
|
||||
|
||||
The @acronym{GNU} format uses additional file types to describe new types of
|
||||
files in an archive. These are listed below.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
;; Inc.
|
||||
;; Copyright 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Sergey Poznyakoff
|
||||
;; Maintainer: bug-tar@gnu.org
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the GNU tar manual.
|
||||
@c Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2017--2023 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.3 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright 1992, 1994-1997, 1999-2004, 2006, 2013-2014, 2016-2017 Free
|
||||
@c Software Foundation, Inc.
|
||||
@c Copyright 1992--2023 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,6 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2005, 2007, 2014, 2016-2017 Free Software Foundation,
|
||||
@c Inc.
|
||||
@c Copyright (C) 2005--2023 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.
|
||||
@@ -147,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-2017 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2023 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -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-2017 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2007--2023 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
|
||||
154
doc/tar.1
154
doc/tar.1
@@ -1,5 +1,5 @@
|
||||
.\" This file is part of GNU tar. -*- nroff -*-
|
||||
.\" Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
.\" Copyright 2013-2023 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 "November 16, 2017" "TAR" "GNU TAR Manual"
|
||||
.TH TAR 1 "July 11, 2022" "TAR" "GNU TAR Manual"
|
||||
.SH NAME
|
||||
tar \- an archiving utility
|
||||
.SH SYNOPSIS
|
||||
@@ -22,22 +22,22 @@ tar \- an archiving utility
|
||||
[\fBGnSkUWOmpsMBiajJzZhPlRvwo\fR] [\fIARG\fR...]
|
||||
.SS UNIX-style usage
|
||||
.sp
|
||||
\fBtar\fR \fB\-A\fR [\fIOPTIONS\fR] \fIARCHIVE\fR \fIARCHIVE\fR
|
||||
\fBtar\fR \fB\-A\fR [\fIOPTIONS\fR] \fB\-f\fR \fIARCHIVE\fR \fIARCHIVE\fR...
|
||||
.sp
|
||||
\fBtar\fR \fB\-c\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-d\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-t\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-r\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-t\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-u\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-x\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
.SS GNU-style usage
|
||||
.sp
|
||||
\fBtar\fR {\fB\-\-catenate\fR|\fB\-\-concatenate\fR} [\fIOPTIONS\fR] \fIARCHIVE\fR \fIARCHIVE\fR
|
||||
\fBtar\fR {\fB\-\-catenate\fR|\fB\-\-concatenate\fR} [\fIOPTIONS\fR] \fB\-\-file\fR \fIARCHIVE\fR \fIARCHIVE\fR...
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-create\fR [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
@@ -45,17 +45,15 @@ tar \- an archiving utility
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-delete\fR [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-append\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
\fBtar\fR \fB\-\-append\fR [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-list\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
\fBtar\fR \fB\-\-list\fR [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-test\-label\fR [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fILABEL\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-update\fR [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR \fB\-\-update\fR [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIFILE\fR...]
|
||||
.sp
|
||||
\fBtar\fR {\fB\-\-extract\fR|\fB\-\-get\fR} [\fB\-f\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
\fBtar\fR {\fB\-\-extract\fR|\fB\-\-get\fR} [\fB\-\-file\fR \fIARCHIVE\fR] [\fIOPTIONS\fR] [\fIMEMBER\fR...]
|
||||
.SH NOTE
|
||||
This manpage is a short description of GNU \fBtar\fR. For a detailed
|
||||
discussion, including examples and usage recommendations, refer to the
|
||||
@@ -74,7 +72,7 @@ You can also view the manual using the info mode in
|
||||
or find it in various formats online at
|
||||
.PP
|
||||
.RS +4
|
||||
.B http://www.gnu.org/software/tar/manual
|
||||
.B https://www.gnu.org/software/tar/manual
|
||||
.RE
|
||||
.PP
|
||||
If any discrepancies occur between this manpage and the
|
||||
@@ -97,8 +95,8 @@ In
|
||||
the first argument is a cluster of option letters and all subsequent
|
||||
arguments supply arguments to those options that require them. The
|
||||
arguments are read in the same order as the option letters. Any
|
||||
command line words that remain after all options has been processed
|
||||
are treated as non-optional arguments: file or archive member names.
|
||||
command line words that remain after all options have been processed
|
||||
are treated as non-option arguments: file or archive member names.
|
||||
.PP
|
||||
For example, the \fBc\fR option requires creating the archive, the
|
||||
\fBv\fR option requests the verbose operation, and the \fBf\fR option
|
||||
@@ -107,25 +105,25 @@ The following command, written in the traditional style, instructs tar
|
||||
to store all files from the directory
|
||||
.B /etc
|
||||
into the archive file
|
||||
.B etc.tar
|
||||
.BR etc.tar ,
|
||||
verbosely listing the files being archived:
|
||||
.PP
|
||||
.EX
|
||||
.B tar cfv a.tar /etc
|
||||
tar cfv etc.tar /etc
|
||||
.EE
|
||||
.PP
|
||||
In
|
||||
.BR "UNIX " or " short-option style" ,
|
||||
each option letter is prefixed with a single dash, as in other command
|
||||
line utilities. If an option takes argument, the argument follows it,
|
||||
line utilities. If an option takes an argument, the argument follows it,
|
||||
either as a separate command line word, or immediately following the
|
||||
option. However, if the option takes an \fBoptional\fR argument, the
|
||||
argument must follow the option letter without any intervening
|
||||
whitespace, as in \fB\-g/tmp/snar.db\fR.
|
||||
.PP
|
||||
Any number of options not taking arguments can be
|
||||
clustered together after a single dash, e.g. \fB\-vkp\fR. Options
|
||||
that take arguments (whether mandatory or optional), can appear at
|
||||
clustered together after a single dash, e.g. \fB\-vkp\fR. An option
|
||||
that takes an argument (whether mandatory or optional) can appear at
|
||||
the end of such a cluster, e.g. \fB\-vkpf a.tar\fR.
|
||||
.PP
|
||||
The example command above written in the
|
||||
@@ -133,9 +131,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 +152,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
|
||||
@@ -164,17 +164,17 @@ with old options is not encouraged.
|
||||
.SS Operation mode
|
||||
The options listed in the table below tell GNU \fBtar\fR what
|
||||
operation it is to perform. Exactly one of them must be given.
|
||||
Meaning of non-optional arguments depends on the operation mode
|
||||
The meaning of non-option arguments depends on the operation mode
|
||||
requested.
|
||||
.TP
|
||||
\fB\-A\fR, \fB\-\-catenate\fR, \fB\-\-concatenate\fR
|
||||
Append archive to the end of another archive. The arguments are
|
||||
Append archives to the end of another archive. The arguments are
|
||||
treated as the names of archives to append. All archives must be of
|
||||
the same format as the archive they are appended to, otherwise the
|
||||
resulting archive might be unusable with non-GNU implementations of
|
||||
\fBtar\fR. Notice also that when more than one archive is given, the
|
||||
members from archives other than the first one will be accessible in
|
||||
the resulting archive only if using the \fB\-i\fR
|
||||
the resulting archive only when using the \fB\-i\fR
|
||||
(\fB\-\-ignore\-zeros\fR) option.
|
||||
|
||||
Compressed archives cannot be concatenated.
|
||||
@@ -218,7 +218,7 @@ There is no short option equivalent for this option.
|
||||
.TP
|
||||
\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
|
||||
archive. Arguments have the same meaning as with the \fB\-c\fR and
|
||||
\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
|
||||
@@ -230,14 +230,13 @@ they specify names of the archive members to be extracted.
|
||||
.TP
|
||||
.TP
|
||||
\fB\-\-show\-defaults\fR
|
||||
Show built-in defaults for various \fBtar\fR options and exit. No
|
||||
arguments are allowed.
|
||||
Show built-in defaults for various \fBtar\fR options and exit.
|
||||
.TP
|
||||
\fB\-?\fR, \fB\-\-help
|
||||
Display a short option summary and exit. No arguments allowed.
|
||||
Display a short option summary and exit.
|
||||
.TP
|
||||
\fB\-\-usage\fR
|
||||
Display a list of available options and exit. No arguments allowed.
|
||||
Display a list of available options and exit.
|
||||
.TP
|
||||
\fB\-\-version\fR
|
||||
Print program version and copyright information and exit.
|
||||
@@ -249,16 +248,15 @@ Check device numbers when creating incremental archives (default).
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-listed\-incremental\fR=\fIFILE\fR
|
||||
Handle new GNU-format incremental backups. \fIFILE\fR is the name of
|
||||
a \fBsnapshot file\fR, where tar stores additional information which
|
||||
a \fBsnapshot file\fR, where \fBtar\fR stores additional information which
|
||||
is used to decide which files changed since the previous incremental
|
||||
dump and, consequently, must be dumped again. If \fIFILE\fR does not
|
||||
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.
|
||||
incremental archives of non-zero level \fBN\fR, you need a copy of the
|
||||
snapshot file created for level \fBN-1\fR, and use it as \fIFILE\fR.
|
||||
|
||||
When listing or extracting, the actual contents of \fIFILE\fR is not
|
||||
When listing or extracting, the actual content of \fIFILE\fR is not
|
||||
inspected, it is needed only due to syntactical requirements. It is
|
||||
therefore common practice to use \fB/dev/null\fR in its place.
|
||||
.TP
|
||||
@@ -275,7 +273,7 @@ Handle old GNU-format incremental backups.
|
||||
Do not exit with nonzero on unreadable files.
|
||||
.TP
|
||||
\fB\-\-level\fR=\fINUMBER\fR
|
||||
Set dump level for created listed-incremental archive. Currently only
|
||||
Set dump level for a created listed-incremental archive. Currently only
|
||||
\fB\-\-level=0\fR is meaningful: it instructs \fBtar\fR to truncate
|
||||
the snapshot file before dumping, thereby forcing a level 0 dump.
|
||||
.TP
|
||||
@@ -287,7 +285,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.
|
||||
@@ -307,7 +305,7 @@ either on the command line or via the \fB\-T\fR option. The default
|
||||
Disable the use of some potentially harmful options.
|
||||
.TP
|
||||
\fB\-\-sparse\-version\fR=\fIMAJOR\fR[.\fIMINOR\fR]
|
||||
Set version of the sparse format to use (implies \fB\-\-sparse\fR).
|
||||
Set which version of the sparse format to use.
|
||||
This option implies
|
||||
.BR \-\-sparse .
|
||||
Valid argument values are
|
||||
@@ -315,7 +313,7 @@ Valid argument values are
|
||||
.BR 0.1 ", and"
|
||||
.BR 1.0 .
|
||||
For a detailed discussion of sparse formats, refer to the \fBGNU Tar
|
||||
Manual\fR, appendix \fBD\fR, "\fBSparse Formats\fR". Using \fBinfo\fR
|
||||
Manual\fR, appendix \fBD\fR, "\fBSparse Formats\fR". Using the \fBinfo\fR
|
||||
reader, it can be accessed running the following command:
|
||||
.BR "info tar 'Sparse Formats'" .
|
||||
.TP
|
||||
@@ -370,7 +368,6 @@ Verify the archive after writing it.
|
||||
.SS Output stream selection
|
||||
.TP
|
||||
\fB\-\-ignore\-command\-error\fR
|
||||
.TP
|
||||
Ignore subprocess exit codes.
|
||||
.TP
|
||||
\fB\-\-no\-ignore\-command\-error\fR
|
||||
@@ -383,7 +380,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
|
||||
@@ -463,16 +460,17 @@ 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
|
||||
\fB\-\-atime\-preserve\fR[=\fIMETHOD\fR]
|
||||
Preserve access times on dumped files, either by restoring the times
|
||||
after reading (\fIMETHOD\fR=\fBreplace\fR, this is the default) or by
|
||||
not setting the times in the first place (\fIMETHOD\fR=\fBsystem\fR)
|
||||
not setting the times in the first place (\fIMETHOD\fR=\fBsystem\fR).
|
||||
.TP
|
||||
\fB\-\-delay\-directory\-restore\fR
|
||||
Delay setting modification times and permissions of extracted
|
||||
@@ -560,17 +558,16 @@ As a result, each input file owned by \fIOLDUSR\fR will be
|
||||
stored in archive with owner name \fINEWUSR\fR and UID \fINEWUID\fR.
|
||||
.TP
|
||||
\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.
|
||||
Set permissions of extracted files to those recorded in the archive
|
||||
(default for superuser).
|
||||
.TP
|
||||
\fB\-\-same\-owner\fR
|
||||
Try extracting files with the same ownership as exists in the archive
|
||||
(default for superuser).
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-preserve\-order\fR, \fB\-\-same\-order\fR
|
||||
Sort names to extract to match archive
|
||||
Tell \fBtar\fR that the list of file names to process is sorted in the
|
||||
same order as the files in the archive.
|
||||
.TP
|
||||
\fB\-\-sort=\fIORDER\fR
|
||||
When creating an archive, sort directory entries according to
|
||||
@@ -610,13 +607,13 @@ Enable extended attributes support.
|
||||
Disable extended attributes support.
|
||||
.TP
|
||||
.BI \-\-xattrs\-exclude= PATTERN
|
||||
Specify the exclude pattern for xattr keys. \fIPATTERN\fR is a POSIX
|
||||
regular expression, e.g. \fB\-\-xattrs\-exclude='^user\.'\fR, to exclude
|
||||
Specify the exclude pattern for xattr keys. \fIPATTERN\fR is a globbing
|
||||
pattern, e.g. \fB\-\-xattrs\-exclude='user.*'\fR to include only
|
||||
attributes from the user namespace.
|
||||
.TP
|
||||
.BI \-\-xattrs\-include= PATTERN
|
||||
Specify the include pattern for xattr keys. \fIPATTERN\fR is a POSIX
|
||||
regular expression.
|
||||
Specify the include pattern for xattr keys. \fIPATTERN\fR is a globbing
|
||||
pattern.
|
||||
.SS Device selection and switching
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-file\fR=\fIARCHIVE\fR
|
||||
@@ -694,7 +691,7 @@ executing.
|
||||
.B TAR_FD
|
||||
File descriptor which can be used to communicate the new volume name
|
||||
to
|
||||
.BR tar .
|
||||
.BR tar .
|
||||
.RE
|
||||
.RS
|
||||
|
||||
@@ -732,7 +729,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
|
||||
@@ -740,11 +737,11 @@ 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
|
||||
filled with zeroes mean EOF and tar stops reading after encountering
|
||||
filled with zeroes mean EOF and \fBtar\fR stops reading after encountering
|
||||
them. This option instructs it to read further and is useful when
|
||||
reading archives created with the \fB\-A\fR option.
|
||||
.TP
|
||||
@@ -783,7 +780,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.
|
||||
@@ -831,6 +829,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
|
||||
@@ -959,7 +961,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
|
||||
@@ -1008,7 +1010,7 @@ disables this behavior.
|
||||
|
||||
This option affects all \fB\-\-files\-from\fR options that occur after
|
||||
it in the command line. Its effect is reverted by the
|
||||
\fB\-\-no\-verbatim\-files\-from} option.
|
||||
\fB\-\-no\-verbatim\-files\-from\fR option.
|
||||
|
||||
This option is implied by the \fB\-\-null\fR option.
|
||||
|
||||
@@ -1058,7 +1060,8 @@ Display progress messages every \fIN\fRth record (default 10).
|
||||
Run \fIACTION\fR on each checkpoint.
|
||||
.TP
|
||||
\fB\-\-clamp\-mtime\fR
|
||||
Only set time when the file is more recent than what was given with \-\-mtime.
|
||||
Only set time when the file is more recent than what was given with
|
||||
\fB\-\-mtime\fR.
|
||||
.TP
|
||||
\fB\-\-full\-time\fR
|
||||
Print file time to its full resolution.
|
||||
@@ -1102,7 +1105,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"
|
||||
@@ -1113,14 +1116,18 @@ 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.2 "\fBThe '\-\-verbose' Option\fR".
|
||||
.TP
|
||||
\fB\-\-warning\fR=\fIKEYWORD\fR
|
||||
Enable or disable warning messages identified by \fIKEYWORD\fR. The
|
||||
messages are suppressed if \fIKEYWORD\fR is prefixed with \fBno\-\fR
|
||||
and enabled otherwise.
|
||||
|
||||
Multiple \fB\-\-warning\fR messages accumulate.
|
||||
Multiple \fB\-\-warning\fR options accumulate.
|
||||
|
||||
Keywords controlling general \fBtar\fR operation:
|
||||
.RS
|
||||
@@ -1159,7 +1166,7 @@ Keywords applicable for \fBtar --create\fR:
|
||||
"%s: file is unchanged; not dumped"
|
||||
.TP
|
||||
.B ignore-archive
|
||||
"%s: file is the archive; not dumped"
|
||||
"%s: archive cannot contain itself; not dumped"
|
||||
.TP
|
||||
.B file-removed
|
||||
"%s: File removed before we read it"
|
||||
@@ -1205,7 +1212,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
|
||||
@@ -1260,7 +1267,7 @@ as \fB\-\-no\-same\-owner\fR.
|
||||
.fi
|
||||
.PP
|
||||
.SH "RETURN VALUE"
|
||||
Tar exit code indicates whether it was able to successfully perform
|
||||
Tar's exit code indicates whether it was able to successfully perform
|
||||
the requested operation, and if not, what kind of error occurred.
|
||||
.TP
|
||||
.B 0
|
||||
@@ -1268,9 +1275,9 @@ Successful termination.
|
||||
.TP
|
||||
.B 1
|
||||
.I Some files differ.
|
||||
If tar was invoked with the \fB\-\-compare\fR (\fB\-\-diff\fR, \fB\-d\fR)
|
||||
If \fBtar\fR was invoked with the \fB\-\-compare\fR (\fB\-\-diff\fR, \fB\-d\fR)
|
||||
command line option, this means that some files in the archive differ
|
||||
from their disk counterparts. If tar was given one of the \fB\-\-create\fR,
|
||||
from their disk counterparts. If \fBtar\fR was given one of the \fB\-\-create\fR,
|
||||
\fB\-\-append\fR or \fB\-\-update\fR options, this exit code means
|
||||
that some files were changed while being archived and so the resulting
|
||||
archive does not contain the exact copy of the file set.
|
||||
@@ -1296,8 +1303,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
|
||||
@@ -1309,11 +1316,11 @@ Online copies of \fBGNU tar\fR documentation in various formats can be
|
||||
found at:
|
||||
.PP
|
||||
.in +4
|
||||
.B http://www.gnu.org/software/tar/manual
|
||||
.B https://www.gnu.org/software/tar/manual
|
||||
.SH "BUG REPORTS"
|
||||
Report bugs to <bug\-tar@gnu.org>.
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2013 Free Software Foundation, Inc.
|
||||
Copyright \(co 2023 Free Software Foundation, Inc.
|
||||
.br
|
||||
.na
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
||||
@@ -1328,4 +1335,3 @@ There is NO WARRANTY, to the extent permitted by law.
|
||||
.\" time-stamp-end: "\""
|
||||
.\" time-stamp-line-limit: 20
|
||||
.\" end:
|
||||
|
||||
|
||||
637
doc/tar.texi
637
doc/tar.texi
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,4 @@
|
||||
# Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2006-2023 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-2017 Free
|
||||
@c Software Foundation, Inc.
|
||||
@c Copyright 1992--2023 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
|
||||
2
gnulib
2
gnulib
Submodule gnulib updated: 91e834891d...46f9c21a08
@@ -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, 2017 Free Software Foundation, Inc.
|
||||
# Copyright 2005-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -23,10 +23,12 @@ areadlinkat-with-size
|
||||
argmatch
|
||||
argp
|
||||
argp-version-etc
|
||||
attribute
|
||||
backupfile
|
||||
closeout
|
||||
configmake
|
||||
dirname
|
||||
dup2
|
||||
error
|
||||
exclude
|
||||
extern-inline
|
||||
@@ -39,8 +41,10 @@ fdopendir
|
||||
fdutimensat
|
||||
file-has-acl
|
||||
fileblocks
|
||||
flexmember
|
||||
fnmatch-gnu
|
||||
fprintftime
|
||||
free-posix
|
||||
fseeko
|
||||
fstatat
|
||||
full-write
|
||||
@@ -48,11 +52,12 @@ futimens
|
||||
getline
|
||||
getopt-gnu
|
||||
getpagesize
|
||||
gettext
|
||||
gettext-h
|
||||
gettime
|
||||
gitlog-to-changelog
|
||||
hash
|
||||
human
|
||||
idx
|
||||
inttostr
|
||||
inttypes
|
||||
lchown
|
||||
@@ -74,7 +79,7 @@ readlinkat
|
||||
renameat
|
||||
root-uid
|
||||
rpmatch
|
||||
safe-read
|
||||
full-read
|
||||
savedir
|
||||
selinux-at
|
||||
setenv
|
||||
@@ -83,8 +88,10 @@ stat-time
|
||||
stdbool
|
||||
stdint
|
||||
stpcpy
|
||||
stdopen
|
||||
strdup-posix
|
||||
strerror
|
||||
strnlen
|
||||
strtoimax
|
||||
strtol
|
||||
strtoul
|
||||
@@ -102,3 +109,4 @@ xalloc-die
|
||||
xgetcwd
|
||||
xstrtoumax
|
||||
xvasprintf
|
||||
year2038-recommended
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Makefile for GNU tar library. -*- Makefile -*-
|
||||
|
||||
# Copyright 1994-1997, 1999-2001, 2003-2007, 2009-2010, 2013-2014,
|
||||
# 2016-2017 Free Software Foundation, Inc.
|
||||
# Copyright 1994-2023 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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2012-2023 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
|
||||
@@ -22,39 +22,39 @@
|
||||
#endif
|
||||
|
||||
/* setting */
|
||||
static inline int setxattr (const char *path, const char *name, const void
|
||||
*value, size_t size, int flags)
|
||||
static int setxattr (const char *path, const char *name, const void
|
||||
*value, size_t size, int flags)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline int lsetxattr (const char *path, const char *name, const void
|
||||
*value, size_t size, int flags)
|
||||
static int lsetxattr (const char *path, const char *name, const void
|
||||
*value, size_t size, int flags)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline int fsetxattr (int filedes, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
static int fsetxattr (int filedes, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
|
||||
/* getting */
|
||||
static inline ssize_t getxattr (const char *path, const char *name, void *value,
|
||||
size_t size)
|
||||
static ssize_t getxattr (const char *path, const char *name, void *value,
|
||||
size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline ssize_t lgetxattr (const char *path, const char *name, void
|
||||
*value, size_t size)
|
||||
static ssize_t lgetxattr (const char *path, const char *name, void
|
||||
*value, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline ssize_t fgetxattr (int filedes, const char *name, void *value,
|
||||
size_t size)
|
||||
static ssize_t fgetxattr (int filedes, const char *name, void *value,
|
||||
size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
|
||||
/* listing */
|
||||
static inline ssize_t listxattr (const char *path, char *list, size_t size)
|
||||
static ssize_t listxattr (const char *path, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline ssize_t llistxattr (const char *path, char *list, size_t size)
|
||||
static ssize_t llistxattr (const char *path, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline ssize_t flistxattr (int filedes, char *list, size_t size)
|
||||
static ssize_t flistxattr (int filedes, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/* stdopen.c - ensure that the three standard file descriptors are in use
|
||||
|
||||
Copyright 2005, 2007, 2013-2014, 2016-2017 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
|
||||
1726
lib/wordsplit.c
1726
lib/wordsplit.c
File diff suppressed because it is too large
Load Diff
213
lib/wordsplit.h
213
lib/wordsplit.h
@@ -1,5 +1,5 @@
|
||||
/* wordsplit - a word splitter
|
||||
Copyright (C) 2009-2014, 2016-2017 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,58 +12,114 @@
|
||||
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
|
||||
|
||||
#include <stddef.h>
|
||||
#include <attribute.h>
|
||||
|
||||
#if 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
|
||||
# define __WORDSPLIT_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
|
||||
#else
|
||||
# define __WORDSPLIT_ATTRIBUTE_FORMAT(spec) /* empty */
|
||||
#endif
|
||||
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 accommodate. */
|
||||
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;
|
||||
|
||||
const char *ws_input;
|
||||
size_t ws_len;
|
||||
size_t ws_endp;
|
||||
int ws_errno;
|
||||
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.
|
||||
|
||||
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 +127,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 +139,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 +167,97 @@ 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);
|
||||
|
||||
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2012-2023 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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2012-2023 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
|
||||
@@ -26,6 +26,7 @@
|
||||
# include <attr/xattr.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef ENOATTR
|
||||
# define ENOATTR ENODATA /* No such attribute */
|
||||
#endif
|
||||
@@ -62,7 +63,7 @@ ssize_t getxattrat (int dir_fd, const char *path, const char *name,
|
||||
ssize_t lgetxattrat (int dir_fd, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
|
||||
/* dir-fd-relative listxattr. Obtain the list of extended attrubtes names. For
|
||||
/* dir-fd-relative listxattr. Obtain the list of extended attributes names. For
|
||||
more info see the listxattr(2) manpage. */
|
||||
ssize_t listxattrat (int dir_fd, const char *path, char *list, size_t size);
|
||||
|
||||
|
||||
2
paxutils
2
paxutils
Submodule paxutils updated: d03eab65d3...481bae1105
23
po/.gitignore
vendored
23
po/.gitignore
vendored
@@ -1,24 +1,23 @@
|
||||
/Makevars.template~
|
||||
/Makefile.in.in~
|
||||
/Makefile.in.in
|
||||
/Makevars.template
|
||||
/Rules-quot
|
||||
/boldquot.sed
|
||||
/en@boldquot.header
|
||||
/en@quot.header
|
||||
/insert-header.sin
|
||||
/quot.sed
|
||||
/remove-potcdate.sed
|
||||
/remove-potcdate.sin
|
||||
*.gmo
|
||||
*.mo
|
||||
*.po
|
||||
*~
|
||||
.reference
|
||||
LINGUAS
|
||||
Makefile
|
||||
Makefile.in
|
||||
Makefile.in.in
|
||||
Makevars
|
||||
Makevars.template
|
||||
POTFILES
|
||||
Rules-quot
|
||||
boldquot.sed
|
||||
en@boldquot.header
|
||||
en@quot.header
|
||||
insert-header.sed
|
||||
insert-header.sin
|
||||
quot.sed
|
||||
remove-potcdate.sed
|
||||
remove-potcdate.sin
|
||||
stamp-po
|
||||
tar.pot
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# List of files which contain translatable strings.
|
||||
|
||||
# Copyright 1996, 1999-2000, 2003-2005, 2007, 2013-2014, 2016-2017 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1996-2023 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-2017 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ TAR=/bin/tar
|
||||
# (Optional) Path to rsh binary or its equivalent. You may wish to
|
||||
# set it to ssh as shown in the example below, to improve security.
|
||||
# In this case you will have to use public key authentication.
|
||||
RSH=/usr/local/bin/ssh
|
||||
RSH=/usr/bin/ssh
|
||||
|
||||
# (Optional) Path to rsh binary on remote mashines. This will be
|
||||
# (Optional) Path to rsh binary on remote machines. This will be
|
||||
# passed via --rsh-command option to the remote invocation of
|
||||
# tar
|
||||
RSH_COMMAND=/usr/local/bin/ssh
|
||||
RSH_COMMAND=/usr/bin/ssh
|
||||
|
||||
# Name of temporary file to hold volume numbers. This needs to be accessible
|
||||
# by all the machines which have filesystems to be dumped.
|
||||
@@ -43,7 +43,7 @@ BACKUP_DIRS='remote1:/etc remote1:/var/spool/crontab'
|
||||
# DIRLIST=/etc/my-backup/dirlist
|
||||
|
||||
# List of individual files to be dumped.
|
||||
# These should be accesible from the machine on which the dump is run.
|
||||
# These should be accessible from the machine on which the dump is run.
|
||||
BACKUP_FILES=''
|
||||
# This list may also be kept in file $SYSCONFDIR/backup/files, the
|
||||
# format of which is the same as described above. The location of
|
||||
@@ -82,8 +82,7 @@ SLEEP_MESSAGE="`awk '
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright 2004, 2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2023 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,7 +149,7 @@ 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.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -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-2017 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Restore backups.
|
||||
|
||||
# Copyright 2004, 2006, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -184,7 +183,7 @@ restore_files()
|
||||
done
|
||||
}
|
||||
|
||||
# Operation Overwiew:
|
||||
# Operation Overview:
|
||||
#
|
||||
# 1. Determine the time of the last backup
|
||||
# 2. Create list of incremental listings to process
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Display and edit the 'dev' field in tar's snapshots
|
||||
# Copyright 2007, 2011, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2007-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -409,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-2017 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright 2004-2023 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-2017 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright 2006-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -50,6 +49,7 @@ tar_SOURCES = \
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
|
||||
AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
|
||||
LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
|
||||
|
||||
tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
tar_LDADD = $(LIBS) ../lib/libtar.a ../gnu/libgnu.a\
|
||||
$(LIB_ACL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)\
|
||||
$(LIB_GETRANDOM) $(LIB_HARD_LOCALE) $(FILE_HAS_ACL_LIB) $(LIB_MBRTOWC)\
|
||||
$(LIB_SELINUX) $(LIB_SETLOCALE_NULL)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* Long integers, for GNU tar.
|
||||
Copyright 1999, 2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 1999-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
167
src/buffer.c
167
src/buffer.c
@@ -1,7 +1,6 @@
|
||||
/* Buffer management for tar.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2013-2014, 2016-2017
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -21,7 +20,6 @@
|
||||
Written by John Gilmore, on 1985-08-25. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@@ -29,10 +27,16 @@
|
||||
#include <fnmatch.h>
|
||||
#include <human.h>
|
||||
#include <quotearg.h>
|
||||
#include <verify.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <rmt.h>
|
||||
|
||||
/* Work around GCC bug 109856. */
|
||||
# if 13 <= __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wnull-dereference"
|
||||
# endif
|
||||
|
||||
/* Number of retries before giving up on read. */
|
||||
#define READ_ERROR_MAX 10
|
||||
|
||||
@@ -281,7 +285,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;
|
||||
@@ -308,8 +313,10 @@ static struct zip_magic const magic[] = {
|
||||
{ ct_bzip2, 3, "BZh" },
|
||||
{ ct_lzip, 4, "LZIP" },
|
||||
{ ct_lzma, 6, "\xFFLZMA" },
|
||||
{ ct_lzma, 3, "\x5d\x00\x00" },
|
||||
{ ct_lzop, 4, "\211LZO" },
|
||||
{ ct_xz, 6, "\xFD" "7zXZ" },
|
||||
{ ct_zstd, 4, "\x28\xB5\x2F\xFD" },
|
||||
};
|
||||
|
||||
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
|
||||
@@ -325,15 +332,16 @@ static struct zip_program zip_program[] = {
|
||||
{ ct_lzma, XZ_PROGRAM, "-J" },
|
||||
{ ct_lzop, LZOP_PROGRAM, "--lzop" },
|
||||
{ ct_xz, XZ_PROGRAM, "-J" },
|
||||
{ ct_none }
|
||||
{ ct_zstd, ZSTD_PROGRAM, "--zstd" },
|
||||
};
|
||||
enum { n_zip_programs = sizeof zip_program / sizeof *zip_program };
|
||||
|
||||
static struct zip_program const *
|
||||
find_zip_program (enum compress_type type, int *pstate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = *pstate; zip_program[i].type != ct_none; i++)
|
||||
for (i = *pstate; i < n_zip_programs; i++)
|
||||
{
|
||||
if (zip_program[i].type == type)
|
||||
{
|
||||
@@ -350,6 +358,8 @@ first_decompress_program (int *pstate)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
|
||||
*pstate = n_zip_programs;
|
||||
|
||||
if (use_compress_program_option)
|
||||
return use_compress_program_option;
|
||||
|
||||
@@ -366,8 +376,6 @@ next_decompress_program (int *pstate)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
|
||||
if (use_compress_program_option)
|
||||
return NULL;
|
||||
zp = find_zip_program (archive_compression_type, pstate);
|
||||
return zp ? zp->program : NULL;
|
||||
}
|
||||
@@ -418,37 +426,6 @@ check_compressed_archive (bool *pshort)
|
||||
return ct_none;
|
||||
}
|
||||
|
||||
/* Guess if the archive is seekable. */
|
||||
static void
|
||||
guess_seekable_archive (void)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (subcommand_option == DELETE_SUBCOMMAND)
|
||||
{
|
||||
/* The current code in delete.c is based on the assumption that
|
||||
skip_member() reads all data from the archive. So, we should
|
||||
make sure it won't use seeks. On the other hand, the same code
|
||||
depends on the ability to backspace a record in the archive,
|
||||
so setting seekable_archive to false is technically incorrect.
|
||||
However, it is tested only in skip_member(), so it's not a
|
||||
problem. */
|
||||
seekable_archive = false;
|
||||
}
|
||||
|
||||
if (seek_option != -1)
|
||||
{
|
||||
seekable_archive = !!seek_option;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!multi_volume_option && !use_compress_program_option
|
||||
&& fstat (archive, &st) == 0)
|
||||
seekable_archive = S_ISREG (st.st_mode);
|
||||
else
|
||||
seekable_archive = false;
|
||||
}
|
||||
|
||||
/* Open an archive named archive_name_array[0]. Detect if it is
|
||||
a compressed archive of known type and use corresponding decompression
|
||||
program if so */
|
||||
@@ -700,12 +677,41 @@ check_tty (enum access_mode mode)
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch the status of the archive, accessed via WANTED_STATUS. */
|
||||
|
||||
static void
|
||||
get_archive_status (enum access_mode wanted_access, bool backed_up_flag)
|
||||
{
|
||||
if (!sys_get_archive_stat ())
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
if (backed_up_flag)
|
||||
undo_last_backup ();
|
||||
errno = saved_errno;
|
||||
open_fatal (archive_name_array[0]);
|
||||
}
|
||||
|
||||
seekable_archive
|
||||
= (! (multi_volume_option || use_compress_program_option)
|
||||
&& (seek_option < 0
|
||||
? (_isrmt (archive)
|
||||
|| S_ISREG (archive_stat.st_mode)
|
||||
|| S_ISBLK (archive_stat.st_mode))
|
||||
: seek_option));
|
||||
|
||||
if (wanted_access != ACCESS_READ)
|
||||
sys_detect_dev_null_output ();
|
||||
|
||||
SET_BINARY_MODE (archive);
|
||||
}
|
||||
|
||||
/* Open an archive file. The argument specifies whether we are
|
||||
reading or writing, or both. */
|
||||
static void
|
||||
_open_archive (enum access_mode wanted_access)
|
||||
{
|
||||
int backed_up_flag = 0;
|
||||
bool backed_up_flag = false;
|
||||
|
||||
if (record_size == 0)
|
||||
FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
|
||||
@@ -794,15 +800,13 @@ _open_archive (enum access_mode wanted_access)
|
||||
{
|
||||
case ACCESS_READ:
|
||||
archive = open_compressed_archive ();
|
||||
if (archive >= 0)
|
||||
guess_seekable_archive ();
|
||||
break;
|
||||
|
||||
case ACCESS_WRITE:
|
||||
if (backup_option)
|
||||
{
|
||||
maybe_backup_file (archive_name_array[0], 1);
|
||||
backed_up_flag = 1;
|
||||
backed_up_flag = true;
|
||||
}
|
||||
if (verify_option)
|
||||
archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
|
||||
@@ -830,20 +834,7 @@ _open_archive (enum access_mode wanted_access)
|
||||
break;
|
||||
}
|
||||
|
||||
if (archive < 0
|
||||
|| (! _isrmt (archive) && !sys_get_archive_stat ()))
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
if (backed_up_flag)
|
||||
undo_last_backup ();
|
||||
errno = saved_errno;
|
||||
open_fatal (archive_name_array[0]);
|
||||
}
|
||||
|
||||
sys_detect_dev_null_output ();
|
||||
sys_save_archive_dev_ino ();
|
||||
SET_BINARY_MODE (archive);
|
||||
get_archive_status (wanted_access, backed_up_flag);
|
||||
|
||||
switch (wanted_access)
|
||||
{
|
||||
@@ -996,7 +987,8 @@ short_read (size_t status)
|
||||
}
|
||||
|
||||
record_end = record_start + (record_size - left) / BLOCKSIZE;
|
||||
records_read++;
|
||||
if (left == 0)
|
||||
records_read++;
|
||||
}
|
||||
|
||||
/* Flush the current buffer to/from the archive. */
|
||||
@@ -1046,18 +1038,8 @@ flush_archive (void)
|
||||
static void
|
||||
backspace_output (void)
|
||||
{
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop operation;
|
||||
|
||||
operation.mt_op = MTBSR;
|
||||
operation.mt_count = 1;
|
||||
if (rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
|
||||
return;
|
||||
if (errno == EIO && rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (mtioseek (false, -1))
|
||||
return;
|
||||
|
||||
{
|
||||
off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR);
|
||||
@@ -1323,8 +1305,8 @@ new_volume (enum access_mode mode)
|
||||
if (verify_option)
|
||||
verify_volume ();
|
||||
|
||||
assign_string (&volume_label, NULL);
|
||||
assign_string (&continued_file_name, NULL);
|
||||
assign_null (&volume_label);
|
||||
assign_null (&continued_file_name);
|
||||
continued_file_size = continued_file_offset = 0;
|
||||
current_block = record_start;
|
||||
|
||||
@@ -1370,7 +1352,6 @@ new_volume (enum access_mode mode)
|
||||
case ACCESS_READ:
|
||||
archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
|
||||
rsh_command_option);
|
||||
guess_seekable_archive ();
|
||||
break;
|
||||
|
||||
case ACCESS_WRITE:
|
||||
@@ -1395,7 +1376,7 @@ new_volume (enum access_mode mode)
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
SET_BINARY_MODE (archive);
|
||||
get_archive_status (mode, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1500,17 +1481,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)
|
||||
if (! (header && header->header.typeflag == GNUTYPE_MULTIVOL))
|
||||
break;
|
||||
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 =
|
||||
@@ -1653,15 +1634,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)
|
||||
{
|
||||
@@ -1694,11 +1667,11 @@ _write_volume_label (const char *str)
|
||||
{
|
||||
union block *label = find_next_block ();
|
||||
|
||||
assume (label);
|
||||
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);
|
||||
|
||||
@@ -1738,7 +1711,7 @@ 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;
|
||||
@@ -1768,15 +1741,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);
|
||||
@@ -1851,7 +1828,7 @@ simple_flush_read (void)
|
||||
|
||||
/* Simple flush write (no multi-volume or label extensions) */
|
||||
static void
|
||||
simple_flush_write (size_t level __attribute__((unused)))
|
||||
simple_flush_write (MAYBE_UNUSED size_t level)
|
||||
{
|
||||
ssize_t status;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Checkpoint management for tar.
|
||||
|
||||
Copyright 2007, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
Copyright 2007-2023 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)
|
||||
{
|
||||
@@ -71,7 +84,7 @@ copy_string_unquote (const char *str)
|
||||
char *output = xstrdup (str);
|
||||
size_t len = strlen (output);
|
||||
if ((*output == '"' || *output == '\'')
|
||||
&& output[len-1] == *output)
|
||||
&& len > 1 && output[len-1] == *output)
|
||||
{
|
||||
memmove (output, output+1, len-2);
|
||||
output[len-2] = 0;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
120
src/common.h
120
src/common.h
@@ -1,7 +1,6 @@
|
||||
/* Common declarations for the tar program.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2012-2017 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -44,24 +43,22 @@
|
||||
# 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
|
||||
|
||||
|
||||
#include "arith.h"
|
||||
#include <attribute.h>
|
||||
#include <backupfile.h>
|
||||
#include <exclude.h>
|
||||
#include <full-write.h>
|
||||
#include <idx.h>
|
||||
#include <inttostr.h>
|
||||
#include <modechange.h>
|
||||
#include <quote.h>
|
||||
#include <safe-read.h>
|
||||
#include <full-read.h>
|
||||
#include <stat-time.h>
|
||||
#include <timespec.h>
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
@@ -302,6 +299,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). */
|
||||
@@ -337,6 +338,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;
|
||||
|
||||
@@ -373,6 +377,7 @@ struct name
|
||||
char *name; /* File name or globbing pattern */
|
||||
size_t length; /* cached strlen (name) */
|
||||
int matching_flags; /* wildcard flags if name is a pattern */
|
||||
bool is_wildcard; /* true if this is a wildcard pattern */
|
||||
bool cmdline; /* true if this name was given in the
|
||||
command line */
|
||||
|
||||
@@ -391,9 +396,8 @@ struct name
|
||||
char *caname; /* canonical name */
|
||||
};
|
||||
|
||||
/* Obnoxious test to see if dimwit is trying to dump the archive. */
|
||||
GLOBAL dev_t ar_dev;
|
||||
GLOBAL ino_t ar_ino;
|
||||
/* Status of archive file, or all zeros if remote. */
|
||||
GLOBAL struct stat archive_stat;
|
||||
|
||||
/* Flags for reading, searching, and fstatatting files. */
|
||||
GLOBAL int open_read_flags;
|
||||
@@ -401,6 +405,9 @@ GLOBAL int open_searchdir_flags;
|
||||
GLOBAL int fstatat_flags;
|
||||
|
||||
GLOBAL int seek_option;
|
||||
|
||||
/* true if archive if lseek should be used on the archive, 0 if it
|
||||
should not be used. */
|
||||
GLOBAL bool seekable_archive;
|
||||
|
||||
GLOBAL dev_t root_device;
|
||||
@@ -463,7 +470,7 @@ void reset_eof (void);
|
||||
void set_next_block_after (union block *block);
|
||||
void clear_read_error_count (void);
|
||||
void xclose (int fd);
|
||||
void archive_write_error (ssize_t status) __attribute__ ((noreturn));
|
||||
_Noreturn void archive_write_error (ssize_t status);
|
||||
void archive_read_error (void);
|
||||
off_t seek_archive (off_t size);
|
||||
void set_start_time (void);
|
||||
@@ -498,7 +505,8 @@ enum dump_status
|
||||
void add_exclusion_tag (const char *name, enum exclusion_tag_type type,
|
||||
bool (*predicate) (int));
|
||||
bool cachedir_file_p (int fd);
|
||||
char *get_directory_entries (struct tar_stat_info *st);
|
||||
char *get_directory_entries (struct tar_stat_info *st)
|
||||
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
|
||||
|
||||
void create_archive (void);
|
||||
void pad_archive (off_t size_left);
|
||||
@@ -610,7 +618,7 @@ uintmax_t uintmax_from_header (const char *buf, size_t size);
|
||||
|
||||
void list_archive (void);
|
||||
void test_archive_label (void);
|
||||
void print_for_mkdir (char *dirname, int length, mode_t mode);
|
||||
void print_for_mkdir (char *dirname, mode_t mode);
|
||||
void print_header (struct tar_stat_info *st, union block *blk,
|
||||
off_t block_ordinal);
|
||||
void read_and (void (*do_something) (void));
|
||||
@@ -618,8 +626,9 @@ enum read_header read_header (union block **return_block,
|
||||
struct tar_stat_info *info,
|
||||
enum read_header_mode m);
|
||||
enum read_header tar_checksum (union block *header, bool silent);
|
||||
void skip_file (off_t size);
|
||||
void skim_file (off_t size, bool must_copy);
|
||||
void skip_member (void);
|
||||
void skim_member (bool must_copy);
|
||||
|
||||
/* Module misc.c. */
|
||||
|
||||
@@ -627,7 +636,12 @@ void skip_member (void);
|
||||
#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_or_null (char **dest, const char *src)
|
||||
ATTRIBUTE_NONNULL ((1));
|
||||
void assign_string (char **dest, const char *src) ATTRIBUTE_NONNULL ((1, 2));
|
||||
void assign_null (char **dest) ATTRIBUTE_NONNULL ((1));
|
||||
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);
|
||||
@@ -662,15 +676,18 @@ represent_uintmax (uintmax_t n)
|
||||
}
|
||||
}
|
||||
|
||||
#define STRINGIFY_BIGINT(i, b) umaxtostr (i, b)
|
||||
enum { UINTMAX_STRSIZE_BOUND = INT_BUFSIZE_BOUND (intmax_t) };
|
||||
enum { SYSINT_BUFSIZE =
|
||||
max (UINTMAX_STRSIZE_BOUND, INT_BUFSIZE_BOUND (intmax_t)) };
|
||||
char *sysinttostr (uintmax_t, intmax_t, uintmax_t, char buf[SYSINT_BUFSIZE]);
|
||||
intmax_t strtosysint (char const *, char **, intmax_t, uintmax_t);
|
||||
void code_ns_fraction (int ns, char *p);
|
||||
char const *code_timespec (struct timespec ts, char *sbuf);
|
||||
enum { BILLION = 1000000000, LOG10_BILLION = 9 };
|
||||
enum { TIMESPEC_STRSIZE_BOUND =
|
||||
UINTMAX_STRSIZE_BOUND + LOG10_BILLION + sizeof "-." - 1 };
|
||||
char const *code_timespec (struct timespec ts,
|
||||
char sbuf[TIMESPEC_STRSIZE_BOUND]);
|
||||
struct timespec decode_timespec (char const *, char **, bool);
|
||||
|
||||
/* Return true if T does not represent an out-of-range or invalid value. */
|
||||
@@ -721,9 +738,8 @@ void stat_diag (char const *name);
|
||||
void file_removed_diag (const char *name, bool top_level,
|
||||
void (*diagfn) (char const *name));
|
||||
void write_error_details (char const *name, size_t status, size_t size);
|
||||
void write_fatal (char const *name) __attribute__ ((noreturn));
|
||||
void write_fatal_details (char const *name, ssize_t status, size_t size)
|
||||
__attribute__ ((noreturn));
|
||||
_Noreturn void write_fatal (char const *name);
|
||||
_Noreturn void write_fatal_details (char const *name, ssize_t status, size_t size);
|
||||
|
||||
pid_t xfork (void);
|
||||
void xpipe (int fd[2]);
|
||||
@@ -734,7 +750,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 */
|
||||
COMMON_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);
|
||||
@@ -743,19 +773,19 @@ 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);
|
||||
void label_notfound (void);
|
||||
void collect_and_sort_names (void);
|
||||
struct name *name_scan (const char *name);
|
||||
struct name *name_scan (const char *name, bool exact);
|
||||
struct name const *name_from_list (void);
|
||||
void blank_name_list (void);
|
||||
char *make_file_name (const char *dir_name, const char *name);
|
||||
@@ -776,14 +806,14 @@ bool contains_dot_dot (char const *name);
|
||||
|
||||
/* Module tar.c. */
|
||||
|
||||
void usage (int);
|
||||
_Noreturn void usage (int);
|
||||
|
||||
int confirm (const char *message_action, const char *name);
|
||||
|
||||
void tar_stat_init (struct tar_stat_info *st);
|
||||
bool tar_stat_close (struct tar_stat_info *st);
|
||||
void tar_stat_destroy (struct tar_stat_info *st);
|
||||
void usage (int) __attribute__ ((noreturn));
|
||||
_Noreturn void usage (int);
|
||||
int tar_timespec_cmp (struct timespec a, struct timespec b);
|
||||
const char *archive_format_string (enum archive_format fmt);
|
||||
const char *subcommand_string (enum subcommand c);
|
||||
@@ -791,6 +821,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
|
||||
{
|
||||
@@ -809,6 +841,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. */
|
||||
@@ -829,6 +879,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);
|
||||
@@ -841,16 +892,19 @@ bool xheader_keyword_deleted_p (const char *kw);
|
||||
char *xheader_format_name (struct tar_stat_info *st, const char *fmt,
|
||||
size_t n);
|
||||
void xheader_xattr_init (struct tar_stat_info *st);
|
||||
void xheader_xattr_free (struct xattr_array *vals, size_t sz);
|
||||
void xheader_xattr_copy (const struct tar_stat_info *st,
|
||||
struct xattr_array **vals, size_t *sz);
|
||||
void xheader_xattr_add (struct tar_stat_info *st,
|
||||
const char *key, const char *val, size_t len);
|
||||
|
||||
void xattr_map_init (struct xattr_map *map);
|
||||
void xattr_map_copy (struct xattr_map *dst,
|
||||
const struct xattr_map *src);
|
||||
void xattr_map_add (struct xattr_map *map,
|
||||
const char *key, const char *val, size_t len);
|
||||
void xattr_map_free (struct xattr_map *xattr_map);
|
||||
|
||||
/* Module system.c */
|
||||
|
||||
void sys_detect_dev_null_output (void);
|
||||
void sys_save_archive_dev_ino (void);
|
||||
void sys_wait_for_child (pid_t, bool);
|
||||
void sys_spawn_shell (void);
|
||||
bool sys_compare_uid (struct stat *a, struct stat *b);
|
||||
@@ -868,10 +922,11 @@ int sys_exec_info_script (const char **archive_name, int volume_number);
|
||||
void sys_exec_checkpoint_script (const char *script_name,
|
||||
const char *archive_name,
|
||||
int checkpoint_number);
|
||||
bool mtioseek (bool count_files, off_t count);
|
||||
|
||||
/* Module compare.c */
|
||||
void report_difference (struct tar_stat_info *st, const char *message, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
ATTRIBUTE_FORMAT ((printf, 2, 3));
|
||||
|
||||
/* Module sparse.c */
|
||||
bool sparse_member_p (struct tar_stat_info *st);
|
||||
@@ -879,7 +934,7 @@ bool sparse_fixup_header (struct tar_stat_info *st);
|
||||
enum dump_status sparse_dump_file (int, struct tar_stat_info *st);
|
||||
enum dump_status sparse_extract_file (int fd, struct tar_stat_info *st,
|
||||
off_t *size);
|
||||
enum dump_status sparse_skip_file (struct tar_stat_info *st);
|
||||
enum dump_status sparse_skim_file (struct tar_stat_info *st, bool must_copy);
|
||||
bool sparse_diff_file (int, struct tar_stat_info *st);
|
||||
|
||||
/* Module utf8.c */
|
||||
@@ -934,12 +989,13 @@ void checkpoint_flush_actions (void);
|
||||
#define WARN_XATTR_WRITE 0x00200000
|
||||
#define WARN_RECORD_SIZE 0x00400000
|
||||
#define WARN_FAILED_READ 0x00800000
|
||||
#define WARN_MISSING_ZERO_BLOCKS 0x01000000
|
||||
|
||||
/* These warnings are enabled by default in verbose mode: */
|
||||
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY|\
|
||||
WARN_DECOMPRESS_PROGRAM|WARN_EXISTING_FILE|\
|
||||
WARN_RECORD_SIZE)
|
||||
#define WARN_ALL (~WARN_VERBOSE_WARNINGS)
|
||||
#define WARN_ALL 0xffffffff
|
||||
|
||||
void set_warning_option (const char *arg);
|
||||
|
||||
|
||||
@@ -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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -74,8 +73,7 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
|
||||
/* Take a buffer returned by read_and_process and do nothing with it. */
|
||||
static int
|
||||
process_noop (size_t size __attribute__ ((unused)),
|
||||
char *data __attribute__ ((unused)))
|
||||
process_noop (MAYBE_UNUSED size_t size, MAYBE_UNUSED char *data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -567,31 +565,12 @@ verify_volume (void)
|
||||
ioctl (archive, FDFLUSH);
|
||||
#endif
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop operation;
|
||||
int status;
|
||||
|
||||
operation.mt_op = MTBSF;
|
||||
operation.mt_count = 1;
|
||||
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation), status < 0)
|
||||
{
|
||||
if (errno != EIO
|
||||
|| (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
|
||||
status < 0))
|
||||
{
|
||||
#endif
|
||||
if (rmtlseek (archive, (off_t) 0, SEEK_SET) != 0)
|
||||
{
|
||||
/* Lseek failed. Try a different method. */
|
||||
seek_warn (archive_name_array[0]);
|
||||
return;
|
||||
}
|
||||
#ifdef MTIOCTOP
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!mtioseek (true, -1) && rmtlseek (archive, 0, SEEK_SET) != 0)
|
||||
{
|
||||
/* Lseek failed. Try a different method. */
|
||||
seek_warn (archive_name_array[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
access_mode = ACCESS_READ;
|
||||
now_verifying = 1;
|
||||
|
||||
173
src/create.c
173
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1985-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -23,6 +22,7 @@
|
||||
#include <system.h>
|
||||
|
||||
#include <areadlink.h>
|
||||
#include <flexmember.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -37,7 +37,7 @@ struct link
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
nlink_t nlink;
|
||||
char name[1];
|
||||
char name[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
struct exclusion_tag
|
||||
@@ -175,13 +175,13 @@ tar_name_copy_str (char *dst, const char *src, size_t len)
|
||||
}
|
||||
|
||||
/* Convert NEGATIVE VALUE to a base-256 representation suitable for
|
||||
tar headers. NEGATIVE is 1 if VALUE was negative before being cast
|
||||
to uintmax_t, 0 otherwise. Output to buffer WHERE with size SIZE.
|
||||
tar headers. NEGATIVE is true iff VALUE was negative before being
|
||||
cast to uintmax_t. Output to buffer WHERE with size SIZE.
|
||||
The result is undefined if SIZE is 0 or if VALUE is too large to
|
||||
fit. */
|
||||
|
||||
static void
|
||||
to_base256 (int negative, uintmax_t value, char *where, size_t size)
|
||||
to_base256 (bool negative, uintmax_t value, char *where, size_t size)
|
||||
{
|
||||
uintmax_t v = value;
|
||||
uintmax_t propagated_sign_bits =
|
||||
@@ -206,13 +206,13 @@ to_base256 (int negative, uintmax_t value, char *where, size_t size)
|
||||
#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,
|
||||
uintmax_t (*substitute) (int *),
|
||||
to_chars (bool negative, uintmax_t value, size_t valsize,
|
||||
uintmax_t (*substitute) (bool *),
|
||||
char *where, size_t size, const char *type);
|
||||
|
||||
static bool
|
||||
to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
|
||||
uintmax_t (*substitute) (int *),
|
||||
to_chars_subst (bool negative, bool gnu_format, uintmax_t value, size_t valsize,
|
||||
uintmax_t (*substitute) (bool *),
|
||||
char *where, size_t size, const char *type)
|
||||
{
|
||||
uintmax_t maxval = (gnu_format
|
||||
@@ -246,7 +246,7 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
|
||||
|
||||
if (substitute)
|
||||
{
|
||||
int negsub;
|
||||
bool negsub;
|
||||
uintmax_t sub = substitute (&negsub) & maxval;
|
||||
/* NOTE: This is one of the few places where GNU_FORMAT differs from
|
||||
OLDGNU_FORMAT. The actual differences are:
|
||||
@@ -273,25 +273,25 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
|
||||
|
||||
/* Convert NEGATIVE VALUE (which was originally of size VALSIZE) to
|
||||
external form, using SUBSTITUTE (...) if VALUE won't fit. Output
|
||||
to buffer WHERE with size SIZE. NEGATIVE is 1 iff VALUE was
|
||||
to buffer WHERE with size SIZE. NEGATIVE is true iff VALUE was
|
||||
negative before being cast to uintmax_t; its original bitpattern
|
||||
can be deduced from VALSIZE, its original size before casting.
|
||||
TYPE is the kind of value being output (useful for diagnostics).
|
||||
Prefer the POSIX format of SIZE - 1 octal digits (with leading zero
|
||||
digits), followed by '\0'. If this won't work, and if GNU or
|
||||
OLDGNU format is allowed, use '\200' followed by base-256, or (if
|
||||
NEGATIVE is nonzero) '\377' followed by two's complement base-256.
|
||||
NEGATIVE) '\377' followed by two's complement base-256.
|
||||
If neither format works, use SUBSTITUTE (...) instead. Pass to
|
||||
SUBSTITUTE the address of an 0-or-1 flag recording whether the
|
||||
substitute value is negative. */
|
||||
|
||||
static bool
|
||||
to_chars (int negative, uintmax_t value, size_t valsize,
|
||||
uintmax_t (*substitute) (int *),
|
||||
to_chars (bool negative, uintmax_t value, size_t valsize,
|
||||
uintmax_t (*substitute) (bool *),
|
||||
char *where, size_t size, const char *type)
|
||||
{
|
||||
int gnu_format = (archive_format == GNU_FORMAT
|
||||
|| archive_format == OLDGNU_FORMAT);
|
||||
bool gnu_format = (archive_format == GNU_FORMAT
|
||||
|| archive_format == OLDGNU_FORMAT);
|
||||
|
||||
/* Generate the POSIX octal representation if the number fits. */
|
||||
if (! negative && value <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
|
||||
@@ -309,7 +309,7 @@ to_chars (int negative, uintmax_t value, size_t valsize,
|
||||
if (((negative ? -1 - value : value)
|
||||
<= MAX_VAL_WITH_DIGITS (size - 1, LG_256)))
|
||||
{
|
||||
where[0] = negative ? -1 : 1 << (LG_256 - 1);
|
||||
where[0] = (char) (negative ? -1 : 1 << (LG_256 - 1));
|
||||
to_base256 (negative, value, where + 1, size - 1);
|
||||
return true;
|
||||
}
|
||||
@@ -322,10 +322,10 @@ to_chars (int negative, uintmax_t value, size_t valsize,
|
||||
But this is the traditional behavior. */
|
||||
else if (negative && valsize * CHAR_BIT <= (size - 1) * LG_8)
|
||||
{
|
||||
static int warned_once;
|
||||
static bool warned_once;
|
||||
if (! warned_once)
|
||||
{
|
||||
warned_once = 1;
|
||||
warned_once = true;
|
||||
WARN ((0, 0, _("Generating negative octal headers")));
|
||||
}
|
||||
where[size - 1] = '\0';
|
||||
@@ -343,7 +343,7 @@ to_chars (int negative, uintmax_t value, size_t valsize,
|
||||
}
|
||||
|
||||
static uintmax_t
|
||||
gid_substitute (int *negative)
|
||||
gid_substitute (bool *negative)
|
||||
{
|
||||
gid_t r;
|
||||
#ifdef GID_NOBODY
|
||||
@@ -384,7 +384,7 @@ mode_to_chars (mode_t v, char *p, size_t s)
|
||||
propagate all unknown bits to the external mode.
|
||||
This matches historical practice.
|
||||
Otherwise, just copy the bits we know about. */
|
||||
int negative;
|
||||
bool negative;
|
||||
uintmax_t u;
|
||||
if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
|
||||
&& S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
|
||||
@@ -399,7 +399,7 @@ mode_to_chars (mode_t v, char *p, size_t s)
|
||||
}
|
||||
else
|
||||
{
|
||||
negative = 0;
|
||||
negative = false;
|
||||
u = ((v & S_ISUID ? TSUID : 0)
|
||||
| (v & S_ISGID ? TSGID : 0)
|
||||
| (v & S_ISVTX ? TSVTX : 0)
|
||||
@@ -429,7 +429,7 @@ time_to_chars (time_t v, char *p, size_t s)
|
||||
}
|
||||
|
||||
static uintmax_t
|
||||
uid_substitute (int *negative)
|
||||
uid_substitute (bool *negative)
|
||||
{
|
||||
uid_t r;
|
||||
#ifdef UID_NOBODY
|
||||
@@ -453,7 +453,7 @@ uid_to_chars (uid_t v, char *p, size_t s)
|
||||
static bool
|
||||
uintmax_to_chars (uintmax_t v, char *p, size_t s)
|
||||
{
|
||||
return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
|
||||
return to_chars (false, v, sizeof v, 0, p, s, "uintmax_t");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -518,8 +518,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;
|
||||
}
|
||||
|
||||
@@ -882,12 +882,6 @@ start_header (struct tar_stat_info *st)
|
||||
if (!MINOR_TO_CHARS (devminor, header->header.devminor))
|
||||
return NULL;
|
||||
}
|
||||
else if (archive_format != GNU_FORMAT && archive_format != OLDGNU_FORMAT)
|
||||
{
|
||||
if (!(MAJOR_TO_CHARS (0, header->header.devmajor)
|
||||
&& MINOR_TO_CHARS (0, header->header.devminor)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
@@ -917,8 +911,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:
|
||||
@@ -967,14 +961,9 @@ start_header (struct tar_stat_info *st)
|
||||
xheader_store ("RHT.security.selinux", st, NULL);
|
||||
if (xattrs_option > 0)
|
||||
{
|
||||
size_t scan_xattr = 0;
|
||||
struct xattr_array *xattr_map = st->xattr_map;
|
||||
|
||||
while (scan_xattr < st->xattr_map_size)
|
||||
{
|
||||
xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
|
||||
++scan_xattr;
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < st->xattr_map.xm_size; i++)
|
||||
xheader_store (st->xattr_map.xm_map[i].xkey, st, &i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1349,15 +1338,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 ();
|
||||
@@ -1372,12 +1361,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;
|
||||
@@ -1408,12 +1393,8 @@ create_archive (void)
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -1538,8 +1519,7 @@ file_count_links (struct tar_stat_info *st)
|
||||
absolute_names_option));
|
||||
transform_name (&linkname, XFORM_LINK);
|
||||
|
||||
lp = xmalloc (offsetof (struct link, name)
|
||||
+ strlen (linkname) + 1);
|
||||
lp = xmalloc (FLEXNSIZEOF (struct link, name, strlen (linkname) + 1));
|
||||
lp->ino = st->stat.st_ino;
|
||||
lp->dev = st->stat.st_dev;
|
||||
lp->nlink = st->stat.st_nlink;
|
||||
@@ -1659,8 +1639,6 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
{
|
||||
union block *header;
|
||||
char type;
|
||||
off_t original_size;
|
||||
struct timespec original_ctime;
|
||||
off_t block_ordinal = -1;
|
||||
int fd = 0;
|
||||
bool is_dir;
|
||||
@@ -1703,10 +1681,11 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
return;
|
||||
}
|
||||
|
||||
st->archive_file_size = original_size = st->stat.st_size;
|
||||
struct stat st1 = st->stat;
|
||||
st->archive_file_size = st->stat.st_size;
|
||||
st->atime = get_stat_atime (&st->stat);
|
||||
st->mtime = get_stat_mtime (&st->stat);
|
||||
st->ctime = original_ctime = get_stat_ctime (&st->stat);
|
||||
st->ctime = get_stat_ctime (&st->stat);
|
||||
|
||||
#ifdef S_ISHIDDEN
|
||||
if (S_ISHIDDEN (st->stat.st_mode))
|
||||
@@ -1743,7 +1722,7 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
if (sys_file_is_archive (st))
|
||||
{
|
||||
WARNOPT (WARN_IGNORE_ARCHIVE,
|
||||
(0, 0, _("%s: file is the archive; not dumped"),
|
||||
(0, 0, _("%s: archive cannot contain itself; not dumped"),
|
||||
quotearg_colon (p)));
|
||||
return;
|
||||
}
|
||||
@@ -1756,9 +1735,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
if (is_dir || S_ISREG (st->stat.st_mode) || S_ISCTG (st->stat.st_mode))
|
||||
{
|
||||
bool ok;
|
||||
struct stat final_stat;
|
||||
struct stat st2;
|
||||
|
||||
xattrs_acls_get (parentfd, name, st, 0, !is_dir);
|
||||
xattrs_acls_get (parentfd, name, st, !is_dir);
|
||||
xattrs_selinux_get (parentfd, name, st, fd);
|
||||
xattrs_xattrs_get (parentfd, name, st, fd);
|
||||
|
||||
@@ -1824,31 +1803,54 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
errno = - parentfd;
|
||||
ok = false;
|
||||
}
|
||||
else
|
||||
ok = fstatat (parentfd, name, &final_stat, fstatat_flags) == 0;
|
||||
}
|
||||
else
|
||||
ok = fstat (fd, &final_stat) == 0;
|
||||
ok = fstat (fd, &st2) == 0;
|
||||
|
||||
if (! ok)
|
||||
file_removed_diag (p, top_level, stat_diag);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
if (ok && fd)
|
||||
{
|
||||
if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
|
||||
/* Original ctime will change if the file is a directory and
|
||||
--remove-files is given */
|
||||
&& !(remove_files_option && is_dir))
|
||||
|| original_size < final_stat.st_size)
|
||||
/* Heuristically check whether the file is the same in all
|
||||
attributes that tar cares about and can easily check.
|
||||
Although the check is not perfect since it does not
|
||||
consult file contents, it is typically good enough.
|
||||
Do not check atime which is saved only to replace it later.
|
||||
Do not check ctime where changes might be benign (e.g.,
|
||||
another process creates a hard link to the file). */
|
||||
|
||||
/* If the file's user ID, group ID or mode changed, tar may
|
||||
have output the wrong info for the file. */
|
||||
ok &= st1.st_uid == st2.st_uid;
|
||||
ok &= st1.st_gid == st2.st_gid;
|
||||
ok &= st1.st_mode == st2.st_mode;
|
||||
|
||||
/* Likewise for the file's mtime, but skip this check if it
|
||||
is a directory possibly updated by --remove-files. */
|
||||
if (! (is_dir && remove_files_option))
|
||||
ok &= ! timespec_cmp (get_stat_mtime (&st1),
|
||||
get_stat_mtime (&st2));
|
||||
|
||||
/* Likewise for the file's size, but skip this check if it
|
||||
is a directory as tar does not output directory sizes.
|
||||
Although dump_regular_file caught regular file shrinkage,
|
||||
it shouldn't hurt to check for shrinkage again now;
|
||||
plus, the file may have grown. */
|
||||
if (!is_dir)
|
||||
ok &= st1.st_size == st2.st_size;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
WARNOPT (WARN_FILE_CHANGED,
|
||||
(0, 0, _("%s: file changed as we read it"),
|
||||
quotearg_colon (p)));
|
||||
set_exit_status (TAREXIT_DIFFERS);
|
||||
if (! ignore_failed_read_option)
|
||||
set_exit_status (TAREXIT_DIFFERS);
|
||||
}
|
||||
else if (atime_preserve_option == replace_atime_preserve
|
||||
&& fd && (is_dir || original_size != 0)
|
||||
&& timespec_cmp (st->atime, get_stat_atime (&st2)) != 0
|
||||
&& set_file_atime (fd, parentfd, name, st->atime) != 0)
|
||||
utime_error (p);
|
||||
}
|
||||
@@ -1898,21 +1900,21 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
else if (S_ISCHR (st->stat.st_mode))
|
||||
{
|
||||
type = CHRTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, 0, true);
|
||||
xattrs_acls_get (parentfd, name, st, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
}
|
||||
else if (S_ISBLK (st->stat.st_mode))
|
||||
{
|
||||
type = BLKTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, 0, true);
|
||||
xattrs_acls_get (parentfd, name, st, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
}
|
||||
else if (S_ISFIFO (st->stat.st_mode))
|
||||
{
|
||||
type = FIFOTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, 0, true);
|
||||
xattrs_acls_get (parentfd, name, st, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
}
|
||||
@@ -1946,15 +1948,6 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
if (!header)
|
||||
return;
|
||||
header->header.typeflag = type;
|
||||
|
||||
if (type != FIFOTYPE)
|
||||
{
|
||||
MAJOR_TO_CHARS (major (st->stat.st_rdev),
|
||||
header->header.devmajor);
|
||||
MINOR_TO_CHARS (minor (st->stat.st_rdev),
|
||||
header->header.devminor);
|
||||
}
|
||||
|
||||
finish_header (st, header, block_ordinal);
|
||||
if (remove_files_option)
|
||||
queue_deferred_unlink (p, false);
|
||||
|
||||
276
src/delete.c
276
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -19,7 +18,6 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <rmt.h>
|
||||
@@ -51,41 +49,31 @@ move_archive (off_t count)
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop operation;
|
||||
|
||||
if (count < 0
|
||||
? (operation.mt_op = MTBSR,
|
||||
operation.mt_count = -count,
|
||||
operation.mt_count == -count)
|
||||
: (operation.mt_op = MTFSR,
|
||||
operation.mt_count = count,
|
||||
operation.mt_count == count))
|
||||
{
|
||||
if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
|
||||
return;
|
||||
|
||||
if (errno == EIO
|
||||
&& 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* MTIOCTOP */
|
||||
|
||||
{
|
||||
off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
|
||||
off_t increment = record_size * (off_t) count;
|
||||
off_t position = position0 + increment;
|
||||
|
||||
if (increment / count != record_size
|
||||
|| (position < position0) != (increment < 0)
|
||||
|| (position = position < 0 ? 0 : position,
|
||||
rmtlseek (archive, position, SEEK_SET) != position))
|
||||
seek_error_details (archive_name_array[0], position);
|
||||
|
||||
if (mtioseek (false, count))
|
||||
return;
|
||||
}
|
||||
|
||||
off_t position0 = rmtlseek (archive, 0, SEEK_CUR), position = 0;
|
||||
if (0 <= position0)
|
||||
{
|
||||
/* Pretend the starting position is at the first record
|
||||
boundary after POSITION0. This is useful at EOF after
|
||||
a short read. */
|
||||
idx_t short_size = position0 % record_size;
|
||||
idx_t start_offset = short_size ? record_size - short_size : 0;
|
||||
off_t increment, move_start;
|
||||
if (INT_MULTIPLY_WRAPV (record_size, count, &increment)
|
||||
|| INT_ADD_WRAPV (position0, start_offset, &move_start)
|
||||
|| INT_ADD_WRAPV (move_start, increment, &position)
|
||||
|| position < 0)
|
||||
{
|
||||
ERROR ((0, EOVERFLOW, "lseek: %s", archive_name_array[0]));
|
||||
return;
|
||||
}
|
||||
else if (rmtlseek (archive, position, SEEK_SET) == position)
|
||||
return;
|
||||
}
|
||||
if (!_isrmt (archive))
|
||||
seek_error_details (archive_name_array[0], position);
|
||||
}
|
||||
|
||||
/* Write out the record which has been filled. If MOVE_BACK_FLAG,
|
||||
@@ -148,6 +136,26 @@ write_recent_bytes (char *data, size_t bytes)
|
||||
write_record (1);
|
||||
}
|
||||
|
||||
static 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 ();
|
||||
if (record_end == current_block)
|
||||
/* Hit EOF */
|
||||
break;
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
}
|
||||
|
||||
void
|
||||
delete_archive_members (void)
|
||||
{
|
||||
@@ -156,7 +164,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 +171,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)
|
||||
{
|
||||
@@ -176,15 +184,15 @@ delete_archive_members (void)
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
if ((name = name_scan (current_stat_info.file_name)) == NULL)
|
||||
if ((name = name_scan (current_stat_info.file_name, false)) == NULL)
|
||||
{
|
||||
skip_member ();
|
||||
skim_member (acting_as_filter);
|
||||
break;
|
||||
}
|
||||
name->found_count++;
|
||||
if (!ISFOUND(name))
|
||||
if (!ISFOUND (name))
|
||||
{
|
||||
skip_member ();
|
||||
skim_member (acting_as_filter);
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
@@ -244,15 +252,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;
|
||||
|
||||
@@ -260,105 +265,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, false)) != 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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2014-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
#include <flexmember.h>
|
||||
#include <fnmatch.h>
|
||||
#include <wordsplit.h>
|
||||
#include "common.h"
|
||||
@@ -40,7 +41,7 @@ struct excfile
|
||||
{
|
||||
struct excfile *next;
|
||||
int flags;
|
||||
char name[1];
|
||||
char name[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
static struct excfile *excfile_head, *excfile_tail;
|
||||
@@ -48,7 +49,8 @@ static struct excfile *excfile_head, *excfile_tail;
|
||||
void
|
||||
excfile_add (const char *name, int flags)
|
||||
{
|
||||
struct excfile *p = xmalloc (sizeof (*p) + strlen (name));
|
||||
struct excfile *p = xmalloc (FLEXNSIZEOF (struct excfile, name,
|
||||
strlen (name) + 1));
|
||||
p->next = NULL;
|
||||
p->flags = flags;
|
||||
strcpy (p->name, name);
|
||||
@@ -104,7 +106,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;
|
||||
@@ -197,11 +200,13 @@ excluded_name (char const *name, struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
static void
|
||||
cvs_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
cvs_addfn (struct exclude *ex, char const *pattern, int options,
|
||||
MAYBE_UNUSED void *data)
|
||||
{
|
||||
struct wordsplit ws;
|
||||
size_t i;
|
||||
|
||||
options |= EXCLUDE_ALLOC;
|
||||
if (wordsplit (pattern, &ws,
|
||||
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS))
|
||||
return;
|
||||
@@ -211,7 +216,8 @@ cvs_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
}
|
||||
|
||||
static void
|
||||
git_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
git_addfn (struct exclude *ex, char const *pattern, int options,
|
||||
MAYBE_UNUSED void *data)
|
||||
{
|
||||
while (isspace (*pattern))
|
||||
++pattern;
|
||||
@@ -223,7 +229,8 @@ git_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
}
|
||||
|
||||
static void
|
||||
bzr_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
bzr_addfn (struct exclude *ex, char const *pattern, int options,
|
||||
MAYBE_UNUSED void *data)
|
||||
{
|
||||
while (isspace (*pattern))
|
||||
++pattern;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Exit from GNU tar.
|
||||
|
||||
Copyright 2009, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
Copyright 2009-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
863
src/extract.c
863
src/extract.c
File diff suppressed because it is too large
Load Diff
109
src/incremen.c
109
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 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;
|
||||
for (p = dir; p && p->orig; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *temp_name;
|
||||
|
||||
/* 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);
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
obstack_code_rename (stk, dir->name, "");
|
||||
|
||||
DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
|
||||
for (p = dir; p != prev; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->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);
|
||||
}
|
||||
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)
|
||||
@@ -990,17 +993,17 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = strdup (initbuf);
|
||||
buf = xstrdup (initbuf);
|
||||
bufsize = strlen (buf) + 1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
97
src/list.c
97
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-2017 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1988-2023 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 */
|
||||
@@ -257,6 +256,13 @@ read_and (void (*do_something) (void))
|
||||
continue;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
if (!ignore_zeros_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
WARNOPT (WARN_MISSING_ZERO_BLOCKS,
|
||||
(0, 0, _("Terminating zero blocks missing at %s"),
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
|
||||
}
|
||||
if (block_number_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
@@ -409,26 +415,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. */
|
||||
|
||||
@@ -438,7 +445,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
|
||||
@@ -448,10 +458,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;
|
||||
@@ -518,7 +532,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! */
|
||||
@@ -537,6 +554,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
|
||||
{
|
||||
@@ -568,6 +586,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
|
||||
{
|
||||
@@ -579,9 +598,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')
|
||||
@@ -631,10 +653,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);
|
||||
|
||||
@@ -857,8 +881,9 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
where++;
|
||||
}
|
||||
}
|
||||
else if (*where == '\200' /* positive base-256 */
|
||||
|| *where == '\377' /* negative base-256 */)
|
||||
else if (where <= lim - 2
|
||||
&& (*where == '\200' /* positive base-256 */
|
||||
|| *where == '\377' /* negative base-256 */))
|
||||
{
|
||||
/* Parse base-256 output. A nonnegative number N is
|
||||
represented as (256**DIGS)/2 + N; a negative number -N is
|
||||
@@ -1049,15 +1074,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;
|
||||
}
|
||||
|
||||
@@ -1355,7 +1376,7 @@ print_header (struct tar_stat_info *st, union block *blk,
|
||||
|
||||
/* Print a similar line when we make a directory automatically. */
|
||||
void
|
||||
print_for_mkdir (char *dirname, int length, mode_t mode)
|
||||
print_for_mkdir (char *dirname, mode_t mode)
|
||||
{
|
||||
char modes[11];
|
||||
|
||||
@@ -1378,15 +1399,17 @@ print_for_mkdir (char *dirname, int length, mode_t mode)
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip over SIZE bytes of data in blocks in the archive. */
|
||||
/* Skip over SIZE bytes of data in blocks in the archive.
|
||||
This may involve copying the data.
|
||||
If MUST_COPY, always copy instead of skipping. */
|
||||
void
|
||||
skip_file (off_t size)
|
||||
skim_file (off_t size, bool must_copy)
|
||||
{
|
||||
union block *x;
|
||||
|
||||
/* FIXME: Make sure mv_begin_read is always called before it */
|
||||
|
||||
if (seekable_archive)
|
||||
if (seekable_archive && !must_copy)
|
||||
{
|
||||
off_t nblk = seek_archive (size);
|
||||
if (nblk >= 0)
|
||||
@@ -1413,6 +1436,14 @@ skip_file (off_t size)
|
||||
NOTE: Current header must be decoded before calling this function. */
|
||||
void
|
||||
skip_member (void)
|
||||
{
|
||||
skim_member (false);
|
||||
}
|
||||
|
||||
/* Skip the current member in the archive.
|
||||
If MUST_COPY, always copy instead of skipping. */
|
||||
void
|
||||
skim_member (bool must_copy)
|
||||
{
|
||||
if (!current_stat_info.skipped)
|
||||
{
|
||||
@@ -1422,9 +1453,9 @@ skip_member (void)
|
||||
mv_begin_read (¤t_stat_info);
|
||||
|
||||
if (current_stat_info.is_sparse)
|
||||
sparse_skip_file (¤t_stat_info);
|
||||
sparse_skim_file (¤t_stat_info, must_copy);
|
||||
else if (save_typeflag != DIRTYPE)
|
||||
skip_file (current_stat_info.stat.st_size);
|
||||
skim_file (current_stat_info.stat.st_size, must_copy);
|
||||
|
||||
mv_end ();
|
||||
}
|
||||
@@ -1443,7 +1474,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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2015-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
118
src/misc.c
118
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 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
|
||||
@@ -43,11 +42,44 @@ quote_n_colon (int n, char const *arg)
|
||||
|
||||
/* Assign STRING to a copy of VALUE if not zero, or to zero. If
|
||||
STRING was nonzero, it is freed first. */
|
||||
void
|
||||
assign_string_or_null (char **string, const char *value)
|
||||
{
|
||||
if (value)
|
||||
assign_string (string, value);
|
||||
else
|
||||
assign_null (string);
|
||||
}
|
||||
|
||||
void
|
||||
assign_string (char **string, const char *value)
|
||||
{
|
||||
free (*string);
|
||||
*string = value ? xstrdup (value) : 0;
|
||||
*string = xstrdup (value);
|
||||
}
|
||||
|
||||
void
|
||||
assign_null (char **string)
|
||||
{
|
||||
char *old = *string;
|
||||
*string = NULL;
|
||||
free (old);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
*string = NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -301,8 +333,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]));
|
||||
@@ -665,13 +695,11 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
char *file_name_buffer = make_file_name (file_name, entry);
|
||||
int r = remove_any_file (file_name_buffer,
|
||||
RECURSIVE_REMOVE_OPTION);
|
||||
int e = errno;
|
||||
free (file_name_buffer);
|
||||
|
||||
if (! r)
|
||||
{
|
||||
free (directory);
|
||||
errno = e;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -704,7 +732,7 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
possible, real problems are unlikely. Doing any better would require a
|
||||
convention, GNU-wide, for all programs doing backups. */
|
||||
|
||||
assign_string (&after_backup_name, 0);
|
||||
assign_null (&after_backup_name);
|
||||
|
||||
/* Check if we really need to backup the file. */
|
||||
|
||||
@@ -727,7 +755,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 ();
|
||||
|
||||
@@ -747,7 +775,7 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
ERROR ((0, e, _("%s: Cannot rename to %s"),
|
||||
quotearg_colon (before_backup_name),
|
||||
quote_n (1, after_backup_name)));
|
||||
assign_string (&after_backup_name, 0);
|
||||
assign_null (&after_backup_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -771,7 +799,7 @@ undo_last_backup (void)
|
||||
fprintf (stdlis, _("Renaming %s back to %s\n"),
|
||||
quote_n (0, after_backup_name),
|
||||
quote_n (1, before_backup_name));
|
||||
assign_string (&after_backup_name, 0);
|
||||
assign_null (&after_backup_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,7 +821,7 @@ deref_stat (char const *name, struct stat *buf)
|
||||
size_t
|
||||
blocking_read (int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t bytes = safe_read (fd, buf, count);
|
||||
size_t bytes = full_read (fd, buf, count);
|
||||
|
||||
#if defined F_SETFL && O_NONBLOCK
|
||||
if (bytes == SAFE_READ_ERROR && errno == EAGAIN)
|
||||
@@ -801,10 +829,12 @@ blocking_read (int fd, void *buf, size_t count)
|
||||
int flags = fcntl (fd, F_GETFL);
|
||||
if (0 <= flags && flags & O_NONBLOCK
|
||||
&& fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1)
|
||||
bytes = safe_read (fd, buf, count);
|
||||
bytes = full_read (fd, buf, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bytes == 0 && errno != 0)
|
||||
bytes = SAFE_READ_ERROR;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -897,8 +927,6 @@ chdir_count (void)
|
||||
int
|
||||
chdir_arg (char const *dir)
|
||||
{
|
||||
char *absdir;
|
||||
|
||||
if (wd_count == wd_alloc)
|
||||
{
|
||||
if (wd_alloc == 0)
|
||||
@@ -908,7 +936,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++;
|
||||
}
|
||||
@@ -925,22 +953,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++;
|
||||
}
|
||||
@@ -1034,9 +1048,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;
|
||||
}
|
||||
|
||||
@@ -1162,7 +1214,7 @@ xpipe (int fd[2])
|
||||
PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable
|
||||
locations. */
|
||||
|
||||
static inline void *
|
||||
static void *
|
||||
ptr_align (void *ptr, size_t alignment)
|
||||
{
|
||||
char *p0 = ptr;
|
||||
|
||||
280
src/names.c
280
src/names.c
@@ -1,7 +1,6 @@
|
||||
/* Various processing of names.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996-2001, 2003-2007, 2009, 2013-2017
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 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
|
||||
@@ -63,89 +62,93 @@ enum
|
||||
WILDCARDS_OPTION
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GRH_LOCAL,
|
||||
GRID_LOCAL,
|
||||
GRH_MATCH,
|
||||
GRID_MATCH,
|
||||
};
|
||||
|
||||
static struct argp_option names_options[] = {
|
||||
#define GRID 100
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("Local file name selection:"), GRID },
|
||||
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+1 },
|
||||
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 escape or 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}
|
||||
};
|
||||
@@ -197,11 +200,24 @@ names_parse_opt (int key, char *arg, struct argp_state *state)
|
||||
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;
|
||||
}
|
||||
@@ -332,7 +348,7 @@ handle_file_selection_option (int key, const char *arg)
|
||||
break;
|
||||
|
||||
case EXCLUDE_VCS_OPTION:
|
||||
add_exclude_array (vcs_file_table, 0);
|
||||
add_exclude_array (vcs_file_table, FNM_LEADING_DIR);
|
||||
break;
|
||||
|
||||
case EXCLUDE_VCS_IGNORES_OPTION:
|
||||
@@ -379,7 +395,7 @@ handle_file_selection_option (int key, const char *arg)
|
||||
break;
|
||||
|
||||
case NO_ANCHORED_OPTION:
|
||||
include_anchored = 0; /* Clear the default for comman line args */
|
||||
include_anchored = 0; /* Clear the default for command line args */
|
||||
matching_flags &= ~ EXCLUDE_ANCHORED;
|
||||
break;
|
||||
|
||||
@@ -420,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,
|
||||
@@ -430,10 +446,6 @@ static struct argp names_argp = {
|
||||
NULL
|
||||
};
|
||||
|
||||
struct argp_child names_argp_children[] = {
|
||||
{ &names_argp, 0, "", 0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* User and group names. */
|
||||
|
||||
@@ -652,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 file 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)
|
||||
@@ -730,7 +744,7 @@ unconsumed_option_report (void)
|
||||
{
|
||||
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.")));
|
||||
ERROR ((0, 0, _("The following options were used after non-option arguments. These options are positional and affect only arguments that follow them. Please, rearrange them properly.")));
|
||||
|
||||
elt = unconsumed_option_tail;
|
||||
while (elt->prev)
|
||||
@@ -785,13 +799,6 @@ name_list_advance (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if there are names or options in the list */
|
||||
bool
|
||||
name_more_files (void)
|
||||
{
|
||||
return name_count > 0;
|
||||
}
|
||||
|
||||
/* Add to name_array the file NAME with fnmatch options MATFLAGS */
|
||||
void
|
||||
name_add_name (const char *name)
|
||||
@@ -800,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
|
||||
@@ -830,7 +850,10 @@ name_add_file (const char *name)
|
||||
ep->v.file.name = name;
|
||||
ep->v.file.line = 0;
|
||||
ep->v.file.fp = NULL;
|
||||
name_count++;
|
||||
|
||||
/* We don't know beforehand how many files are listed.
|
||||
Assume more than one. */
|
||||
filename_args = FILES_MANY;
|
||||
}
|
||||
|
||||
/* Names from external name file. */
|
||||
@@ -957,7 +980,6 @@ read_name_from_file (struct name_elt *ent)
|
||||
if (counter == name_buffer_length)
|
||||
name_buffer = x2realloc (name_buffer, &name_buffer_length);
|
||||
name_buffer[counter] = 0;
|
||||
chopslash (name_buffer);
|
||||
return (counter == 0 && c == EOF) ? file_list_end : file_list_success;
|
||||
}
|
||||
|
||||
@@ -1006,8 +1028,10 @@ read_next_name (struct name_elt *ent, struct name_elt *ret)
|
||||
name_list_advance ();
|
||||
return 1;
|
||||
}
|
||||
if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) == NULL)
|
||||
FILE *fp = fopen (ent->v.file.name, "r");
|
||||
if (!fp)
|
||||
open_fatal (ent->v.file.name);
|
||||
ent->v.file.fp = fp;
|
||||
}
|
||||
ent->v.file.term = filename_terminator;
|
||||
ent->v.file.verbatim = verbatim_files_from_option;
|
||||
@@ -1037,6 +1061,7 @@ read_next_name (struct name_elt *ent, struct name_elt *ret)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
chopslash (name_buffer);
|
||||
ret->type = NELT_NAME;
|
||||
ret->v.name = name_buffer;
|
||||
return 0;
|
||||
@@ -1059,19 +1084,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);
|
||||
}
|
||||
@@ -1139,6 +1153,13 @@ name_next (int change_dirs)
|
||||
return nelt ? nelt->v.name : NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
name_is_wildcard (struct name const *name)
|
||||
{
|
||||
return (name->matching_flags & EXCLUDE_WILDCARDS) &&
|
||||
fnmatch_pattern_has_wildcards (name->name, name->matching_flags);
|
||||
}
|
||||
|
||||
/* Gather names in a list for scanning. Could hash them later if we
|
||||
really care.
|
||||
|
||||
@@ -1175,6 +1196,7 @@ name_gather (void)
|
||||
buffer->directory = NULL;
|
||||
buffer->parent = NULL;
|
||||
buffer->cmdline = true;
|
||||
buffer->is_wildcard = name_is_wildcard (buffer);
|
||||
|
||||
namelist = nametail = buffer;
|
||||
}
|
||||
@@ -1218,6 +1240,7 @@ addname (char const *string, int change_dir, bool cmdline, struct name *parent)
|
||||
name->directory = NULL;
|
||||
name->parent = parent;
|
||||
name->cmdline = cmdline;
|
||||
name->is_wildcard = name_is_wildcard (name);
|
||||
|
||||
if (nametail)
|
||||
nametail->next = name;
|
||||
@@ -1227,16 +1250,46 @@ addname (char const *string, int change_dir, bool cmdline, struct name *parent)
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
|
||||
list. */
|
||||
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;
|
||||
name->is_wildcard = name_is_wildcard (name);
|
||||
|
||||
starting_file_option = true;
|
||||
}
|
||||
|
||||
/* Find a match for FILE_NAME in the name list. If EXACT is true,
|
||||
look for exact match (no wildcards). */
|
||||
static struct name *
|
||||
namelist_match (char const *file_name, size_t length)
|
||||
namelist_match (char const *file_name, bool exact)
|
||||
{
|
||||
struct name *p;
|
||||
|
||||
for (p = namelist; p; p = p->next)
|
||||
{
|
||||
if (p->name[0]
|
||||
&& (exact ? !p->is_wildcard : true)
|
||||
&& exclude_fnmatch (p->name, file_name, p->matching_flags))
|
||||
return p;
|
||||
}
|
||||
@@ -1265,8 +1318,6 @@ remname (struct name *name)
|
||||
bool
|
||||
name_match (const char *file_name)
|
||||
{
|
||||
size_t length = strlen (file_name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct name *cursor = namelist;
|
||||
@@ -1282,20 +1333,23 @@ name_match (const char *file_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor = namelist_match (file_name, length);
|
||||
cursor = namelist_match (file_name, false);
|
||||
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);
|
||||
}
|
||||
@@ -1561,9 +1615,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;
|
||||
@@ -1584,18 +1637,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)
|
||||
@@ -1767,6 +1812,11 @@ collect_and_sort_names (void)
|
||||
name->found_count++;
|
||||
add_hierarchy_to_namelist (&st, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
open_diag (name->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1791,7 +1841,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);
|
||||
@@ -1821,7 +1871,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);
|
||||
@@ -1832,15 +1882,14 @@ collect_and_sort_names (void)
|
||||
1. It returns a pointer to the name it matched, and doesn't set FOUND
|
||||
in structure. The caller will have to do that if it wants to.
|
||||
2. If the namelist is empty, it returns null, unlike name_match, which
|
||||
returns TRUE. */
|
||||
returns TRUE.
|
||||
3. If EXACT is true, it looks for exact matches only (no wildcards). */
|
||||
struct name *
|
||||
name_scan (const char *file_name)
|
||||
name_scan (const char *file_name, bool exact)
|
||||
{
|
||||
size_t length = strlen (file_name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct name *cursor = namelist_match (file_name, length);
|
||||
struct name *cursor = namelist_match (file_name, exact);
|
||||
if (cursor)
|
||||
return cursor;
|
||||
|
||||
@@ -1860,9 +1909,10 @@ name_scan (const char *file_name)
|
||||
}
|
||||
}
|
||||
|
||||
/* This returns a name from the namelist which doesn't have ->found
|
||||
set. It sets ->found before returning, so successive calls will
|
||||
find and return all the non-found names in the namelist. */
|
||||
/* This returns a name from the namelist which is an exact match (i.e.
|
||||
not a pattern) and doesn't have ->found set. It sets ->found before
|
||||
returning, so successive calls will find and return all the non-found
|
||||
names in the namelist. */
|
||||
struct name *gnu_list_name;
|
||||
|
||||
struct name const *
|
||||
@@ -1871,11 +1921,13 @@ name_from_list (void)
|
||||
if (!gnu_list_name)
|
||||
gnu_list_name = namelist;
|
||||
while (gnu_list_name
|
||||
&& (gnu_list_name->found_count || gnu_list_name->name[0] == 0))
|
||||
&& (gnu_list_name->is_wildcard ||
|
||||
gnu_list_name->found_count || gnu_list_name->name[0] == 0))
|
||||
gnu_list_name = gnu_list_name->next;
|
||||
if (gnu_list_name)
|
||||
{
|
||||
gnu_list_name->found_count++;
|
||||
if (!gnu_list_name->is_wildcard)
|
||||
gnu_list_name->found_count++;
|
||||
chdir_do (gnu_list_name->change_dir);
|
||||
return gnu_list_name;
|
||||
}
|
||||
|
||||
109
src/sparse.c
109
src/sparse.c
@@ -1,6 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright 2003-2007, 2010, 2013-2017 Free Software Foundation, Inc.
|
||||
Copyright 2003-2023 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
|
||||
@@ -335,8 +335,6 @@ sparse_scan_file_seek (struct tar_sparse_file *file)
|
||||
st->archive_file_size += sp.numbytes;
|
||||
offset = hole_offset;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -417,7 +415,7 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
size_t bytes_read;
|
||||
|
||||
blk = find_next_block ();
|
||||
bytes_read = safe_read (file->fd, blk->buffer, bufsize);
|
||||
bytes_read = full_read (file->fd, blk->buffer, bufsize);
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
@@ -427,6 +425,42 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
bufsize);
|
||||
return false;
|
||||
}
|
||||
else if (bytes_read == 0)
|
||||
{
|
||||
if (errno != 0)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
(file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].numbytes
|
||||
- bytes_left),
|
||||
bufsize);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
@@ -464,9 +498,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)
|
||||
@@ -546,7 +580,10 @@ sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
|
||||
size_t i;
|
||||
|
||||
if (!tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
{
|
||||
*size = st->stat.st_size;
|
||||
return dump_status_not_implemented;
|
||||
}
|
||||
|
||||
file.stat_info = st;
|
||||
file.fd = fd;
|
||||
@@ -561,7 +598,7 @@ sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
|
||||
}
|
||||
|
||||
enum dump_status
|
||||
sparse_skip_file (struct tar_stat_info *st)
|
||||
sparse_skim_file (struct tar_stat_info *st, bool must_copy)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
@@ -573,7 +610,7 @@ sparse_skip_file (struct tar_stat_info *st)
|
||||
file.fd = -1;
|
||||
|
||||
rc = tar_sparse_decode_header (&file);
|
||||
skip_file (file.stat_info->archive_file_size - file.dumped_size);
|
||||
skim_file (file.stat_info->archive_file_size - file.dumped_size, must_copy);
|
||||
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
|
||||
}
|
||||
|
||||
@@ -590,7 +627,7 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
size_t rdsize = BLOCKSIZE < end - beg ? BLOCKSIZE : end - beg;
|
||||
char diff_buffer[BLOCKSIZE];
|
||||
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
bytes_read = full_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
@@ -598,6 +635,17 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
rdsize);
|
||||
return false;
|
||||
}
|
||||
else if (bytes_read == 0)
|
||||
{
|
||||
if (errno != 0)
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
beg,
|
||||
rdsize);
|
||||
else
|
||||
report_difference (file->stat_info, _("Size differs"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!zero_block_p (diff_buffer, bytes_read))
|
||||
{
|
||||
char begbuf[INT_BUFSIZE_BOUND (off_t)];
|
||||
@@ -609,6 +657,7 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
|
||||
beg += bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -635,7 +684,8 @@ check_data_region (struct tar_sparse_file *file, size_t i)
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
file->dumped_size += BLOCKSIZE;
|
||||
bytes_read = full_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
@@ -645,10 +695,21 @@ check_data_region (struct tar_sparse_file *file, size_t i)
|
||||
rdsize);
|
||||
return false;
|
||||
}
|
||||
file->dumped_size += bytes_read;
|
||||
else if (bytes_read == 0)
|
||||
{
|
||||
if (errno != 0)
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
(file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].numbytes
|
||||
- size_left),
|
||||
rdsize);
|
||||
else
|
||||
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;
|
||||
@@ -666,7 +727,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;
|
||||
@@ -684,7 +745,7 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
skip_file (file.stat_info->archive_file_size - file.dumped_size);
|
||||
skim_file (file.stat_info->archive_file_size - file.dumped_size, false);
|
||||
mv_end ();
|
||||
|
||||
tar_sparse_done (&file);
|
||||
@@ -718,7 +779,7 @@ enum oldgnu_add_status
|
||||
};
|
||||
|
||||
static bool
|
||||
oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
|
||||
oldgnu_sparse_member_p (MAYBE_UNUSED struct tar_sparse_file *file)
|
||||
{
|
||||
return current_header->header.typeflag == GNUTYPE_SPARSE;
|
||||
}
|
||||
@@ -862,7 +923,7 @@ static struct tar_sparse_optab const oldgnu_optab = {
|
||||
/* Star */
|
||||
|
||||
static bool
|
||||
star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
|
||||
star_sparse_member_p (MAYBE_UNUSED struct tar_sparse_file *file)
|
||||
{
|
||||
return current_header->header.typeflag == GNUTYPE_SPARSE;
|
||||
}
|
||||
@@ -982,7 +1043,7 @@ static struct tar_sparse_optab const star_optab = {
|
||||
* 1.0
|
||||
|
||||
Starting from this version, the exact sparse format version is specified
|
||||
explicitely in the header using the following variables:
|
||||
explicitly in the header using the following variables:
|
||||
|
||||
GNU.sparse.major Major version
|
||||
GNU.sparse.minor Minor version
|
||||
@@ -1213,6 +1274,7 @@ 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 \
|
||||
{ \
|
||||
@@ -1229,8 +1291,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; \
|
||||
} \
|
||||
@@ -1240,9 +1303,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)))
|
||||
@@ -1268,7 +1333,9 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
}
|
||||
sp.offset = u;
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t))
|
||||
|| INT_ADD_OVERFLOW (sp.offset, u)
|
||||
|| file->stat_info->stat.st_size < sp.offset + u)
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
@@ -1278,6 +1345,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;
|
||||
|
||||
16
src/suffix.c
16
src/suffix.c
@@ -1,6 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2007, 2009, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2007-2023 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff.
|
||||
|
||||
@@ -46,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__
|
||||
@@ -60,7 +61,7 @@ find_compression_suffix (const char *name, size_t *ret_len)
|
||||
{
|
||||
size_t len;
|
||||
struct compression_suffix *p;
|
||||
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
@@ -99,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;
|
||||
@@ -112,4 +117,3 @@ strip_compression_suffix (const char *name)
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
111
src/system.c
111
src/system.c
@@ -1,7 +1,6 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright 2003-2008, 2010, 2013-2014, 2016-2017 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright 2003-2023 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
|
||||
@@ -17,6 +16,7 @@
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <priv-set.h>
|
||||
@@ -38,6 +38,35 @@ xexec (const char *cmd)
|
||||
exec_fatal (cmd);
|
||||
}
|
||||
|
||||
/* True if the archive is seekable via ioctl and MTIOCTOP,
|
||||
or if it is not known whether it is seekable.
|
||||
False if it is known to be not seekable. */
|
||||
static bool mtioseekable_archive;
|
||||
|
||||
bool
|
||||
mtioseek (bool count_files, off_t count)
|
||||
{
|
||||
if (mtioseekable_archive)
|
||||
{
|
||||
#ifdef MTIOCTOP
|
||||
struct mtop operation;
|
||||
operation.mt_op = (count_files
|
||||
? (count < 0 ? MTBSF : MTFSF)
|
||||
: (count < 0 ? MTBSR : MTFSR));
|
||||
if (! (count < 0
|
||||
? INT_SUBTRACT_WRAPV (0, count, &operation.mt_count)
|
||||
: INT_ADD_WRAPV (count, 0, &operation.mt_count))
|
||||
&& (0 <= rmtioctl (archive, MTIOCTOP, &operation)
|
||||
|| (errno == EIO
|
||||
&& 0 <= rmtioctl (archive, MTIOCTOP, &operation))))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
mtioseekable_archive = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if MSDOS
|
||||
|
||||
bool
|
||||
@@ -52,11 +81,6 @@ sys_file_is_archive (struct tar_stat_info *p)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
sys_save_archive_dev_ino (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_detect_dev_null_output (void)
|
||||
{
|
||||
@@ -129,31 +153,34 @@ sys_child_open_for_uncompress (void)
|
||||
|
||||
extern union block *record_start; /* FIXME */
|
||||
|
||||
static struct stat archive_stat; /* stat block for archive file */
|
||||
|
||||
bool
|
||||
sys_get_archive_stat (void)
|
||||
{
|
||||
return fstat (archive, &archive_stat) == 0;
|
||||
bool remote = _isrmt (archive);
|
||||
mtioseekable_archive = true;
|
||||
if (!remote && 0 <= archive && fstat (archive, &archive_stat) == 0)
|
||||
{
|
||||
if (!S_ISCHR (archive_stat.st_mode))
|
||||
mtioseekable_archive = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: This memset should not be needed. It is present only
|
||||
because other parts of tar may incorrectly access
|
||||
archive_stat even if it's not the archive status. */
|
||||
memset (&archive_stat, 0, sizeof archive_stat);
|
||||
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
sys_file_is_archive (struct tar_stat_info *p)
|
||||
{
|
||||
return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
|
||||
}
|
||||
|
||||
/* Save archive file inode and device numbers */
|
||||
void
|
||||
sys_save_archive_dev_ino (void)
|
||||
{
|
||||
if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
|
||||
{
|
||||
ar_dev = archive_stat.st_dev;
|
||||
ar_ino = archive_stat.st_ino;
|
||||
}
|
||||
else
|
||||
ar_dev = 0;
|
||||
return (!dev_null_output && !_isrmt (archive)
|
||||
&& p->stat.st_dev == archive_stat.st_dev
|
||||
&& p->stat.st_ino == archive_stat.st_ino);
|
||||
}
|
||||
|
||||
/* Detect if outputting to "/dev/null". */
|
||||
@@ -161,14 +188,15 @@ void
|
||||
sys_detect_dev_null_output (void)
|
||||
{
|
||||
static char const dev_null[] = "/dev/null";
|
||||
struct stat dev_null_stat;
|
||||
static struct stat dev_null_stat;
|
||||
|
||||
dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
|
||||
|| (! _isrmt (archive)
|
||||
&& S_ISCHR (archive_stat.st_mode)
|
||||
&& stat (dev_null, &dev_null_stat) == 0
|
||||
&& archive_stat.st_dev == dev_null_stat.st_dev
|
||||
&& archive_stat.st_ino == dev_null_stat.st_ino));
|
||||
&& (dev_null_stat.st_ino != 0
|
||||
|| stat (dev_null, &dev_null_stat) == 0)
|
||||
&& archive_stat.st_ino == dev_null_stat.st_ino
|
||||
&& archive_stat.st_dev == dev_null_stat.st_dev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -271,6 +299,11 @@ sys_write_archive_buffer (void)
|
||||
#define PREAD 0 /* read file descriptor from pipe() */
|
||||
#define PWRITE 1 /* write file descriptor from pipe() */
|
||||
|
||||
/* Work around GCC bug 109839. */
|
||||
#if 13 <= __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wanalyzer-fd-leak"
|
||||
#endif
|
||||
|
||||
/* Duplicate file descriptor FROM into becoming INTO.
|
||||
INTO is closed first and has to be the next available slot. */
|
||||
static void
|
||||
@@ -278,31 +311,17 @@ xdup2 (int from, int into)
|
||||
{
|
||||
if (from != into)
|
||||
{
|
||||
int status = close (into);
|
||||
|
||||
if (status != 0 && errno != EBADF)
|
||||
if (dup2 (from, into) < 0)
|
||||
{
|
||||
int e = errno;
|
||||
FATAL_ERROR ((0, e, _("Cannot close")));
|
||||
}
|
||||
status = dup (from);
|
||||
if (status != into)
|
||||
{
|
||||
if (status < 0)
|
||||
{
|
||||
int e = errno;
|
||||
FATAL_ERROR ((0, e, _("Cannot dup")));
|
||||
}
|
||||
abort ();
|
||||
FATAL_ERROR ((0, e, _("Cannot dup2")));
|
||||
}
|
||||
xclose (from);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
|
||||
|
||||
/* Propagate any failure of the grandchild back to the parent. */
|
||||
static void
|
||||
static _Noreturn void
|
||||
wait_for_grandchild (pid_t pid)
|
||||
{
|
||||
int wait_status;
|
||||
@@ -541,7 +560,7 @@ sys_child_open_for_uncompress (void)
|
||||
&& !_remdev (archive_name_array[0])
|
||||
&& is_regular_file (archive_name_array[0]))
|
||||
{
|
||||
/* We don't need a grandchild tar. Open the archive and lauch the
|
||||
/* We don't need a grandchild tar. Open the archive and launch the
|
||||
uncompressor. */
|
||||
|
||||
archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
|
||||
|
||||
13
src/tar.h
13
src/tar.h
@@ -1,7 +1,6 @@
|
||||
/* GNU tar Archive Format description.
|
||||
|
||||
Copyright 1988-1989, 1991-1997, 2000-2001, 2003-2007, 2012-2014,
|
||||
2016-2017 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -285,6 +284,13 @@ struct xattr_array
|
||||
size_t xval_len;
|
||||
};
|
||||
|
||||
struct xattr_map
|
||||
{
|
||||
struct xattr_array *xm_map;
|
||||
size_t xm_size; /* Size of the xattr map */
|
||||
size_t xm_max; /* Max. number of entries in xattr_map */
|
||||
};
|
||||
|
||||
struct tar_stat_info
|
||||
{
|
||||
char *orig_file_name; /* name of file read from the archive header */
|
||||
@@ -335,8 +341,7 @@ struct tar_stat_info
|
||||
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;
|
||||
struct xattr_map xattr_map;
|
||||
|
||||
/* Extended headers */
|
||||
struct xheader xhdr;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2006-2008, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2006-2023 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
|
||||
@@ -101,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)
|
||||
@@ -209,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++)
|
||||
@@ -273,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);
|
||||
@@ -403,6 +404,7 @@ parse_transform_expr (const char *expr)
|
||||
cur++;
|
||||
}
|
||||
add_literal_segment (tf, beg, cur);
|
||||
free(str);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -491,9 +493,6 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
|
||||
disp = rmp[0].rm_eo;
|
||||
|
||||
if (rmp[0].rm_so)
|
||||
obstack_grow (&stk, input, rmp[0].rm_so);
|
||||
|
||||
nmatches++;
|
||||
if (tf->match_number && nmatches < tf->match_number)
|
||||
{
|
||||
@@ -502,6 +501,9 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rmp[0].rm_so)
|
||||
obstack_grow (&stk, input, rmp[0].rm_so);
|
||||
|
||||
for (segm = tf->repl_head; segm; segm = segm->next)
|
||||
{
|
||||
switch (segm->type)
|
||||
@@ -550,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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2009-2023 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;
|
||||
|
||||
93
src/update.c
93
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-2017 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -43,13 +42,14 @@ bool time_to_start_writing;
|
||||
first part of the record. */
|
||||
char *output_start;
|
||||
|
||||
static bool acting_as_filter;
|
||||
|
||||
/* Catenate file FILE_NAME to the archive without creating a header for it.
|
||||
It had better be a tar file or the archive is screwed. */
|
||||
static void
|
||||
append_file (char *file_name)
|
||||
{
|
||||
int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY);
|
||||
struct stat stat_data;
|
||||
|
||||
if (handle < 0)
|
||||
{
|
||||
@@ -57,49 +57,48 @@ append_file (char *file_name)
|
||||
return;
|
||||
}
|
||||
|
||||
if (fstat (handle, &stat_data) != 0)
|
||||
stat_error (file_name);
|
||||
else
|
||||
while (true)
|
||||
{
|
||||
off_t bytes_left = stat_data.st_size;
|
||||
|
||||
while (bytes_left > 0)
|
||||
union block *start = find_next_block ();
|
||||
size_t status = full_read (handle, start->buffer,
|
||||
available_space_after (start));
|
||||
if (status == 0)
|
||||
{
|
||||
union block *start = find_next_block ();
|
||||
size_t buffer_size = available_space_after (start);
|
||||
size_t status;
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
if (bytes_left < buffer_size)
|
||||
{
|
||||
buffer_size = bytes_left;
|
||||
status = buffer_size % BLOCKSIZE;
|
||||
if (status)
|
||||
memset (start->buffer + bytes_left, 0, BLOCKSIZE - status);
|
||||
}
|
||||
|
||||
status = safe_read (handle, start->buffer, buffer_size);
|
||||
if (status == SAFE_READ_ERROR)
|
||||
read_fatal_details (file_name, stat_data.st_size - bytes_left,
|
||||
buffer_size);
|
||||
if (status == 0)
|
||||
FATAL_ERROR ((0, 0,
|
||||
ngettext ("%s: File shrank by %s byte",
|
||||
"%s: File shrank by %s bytes",
|
||||
bytes_left),
|
||||
quotearg_colon (file_name),
|
||||
STRINGIFY_BIGINT (bytes_left, buf)));
|
||||
|
||||
bytes_left -= status;
|
||||
|
||||
set_next_block_after (start + (status - 1) / BLOCKSIZE);
|
||||
if (errno == 0)
|
||||
break;
|
||||
read_fatal (file_name);
|
||||
}
|
||||
if (status == SAFE_READ_ERROR)
|
||||
read_fatal (file_name);
|
||||
if (status % BLOCKSIZE)
|
||||
memset (start->buffer + status - status % BLOCKSIZE, 0,
|
||||
BLOCKSIZE - status % BLOCKSIZE);
|
||||
set_next_block_after (start + (status - 1) / BLOCKSIZE);
|
||||
}
|
||||
|
||||
if (close (handle) != 0)
|
||||
close_error (file_name);
|
||||
}
|
||||
|
||||
/* If NAME is not a pattern, remove it from the namelist. Otherwise,
|
||||
remove the FILE_NAME that matched it. Take care to look for exact
|
||||
match when removing it. */
|
||||
static void
|
||||
remove_exact_name (struct name *name, char const *file_name)
|
||||
{
|
||||
if (name->is_wildcard)
|
||||
{
|
||||
struct name *match = name_scan (file_name, true);
|
||||
name->found_count++;
|
||||
if (match)
|
||||
name = match;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
remname (name);
|
||||
}
|
||||
|
||||
/* Implement the 'r' (add files to end of archive), and 'u' (add files
|
||||
to end of archive if they aren't there, or are more up to date than
|
||||
the version in the archive) commands. */
|
||||
@@ -111,7 +110,8 @@ update_archive (void)
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
buffer_write_global_xheader ();
|
||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||
xheader_forbid_global ();
|
||||
|
||||
while (!found_end)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ update_archive (void)
|
||||
archive_format = current_format;
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
&& (name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
&& (name = name_scan (current_stat_info.file_name, false)) != NULL)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
@@ -145,10 +145,10 @@ update_archive (void)
|
||||
{
|
||||
if (S_ISDIR (s.st_mode))
|
||||
{
|
||||
char *p, *dirp = tar_savedir (name->name, 1);
|
||||
char *p, *dirp = tar_savedir (current_stat_info.file_name, 1);
|
||||
if (dirp)
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (name->name);
|
||||
namebuf_t nbuf = namebuf_create (current_stat_info.file_name);
|
||||
|
||||
for (p = dirp; *p; p += strlen (p) + 1)
|
||||
addname (namebuf_name (nbuf, p),
|
||||
@@ -157,17 +157,22 @@ update_archive (void)
|
||||
namebuf_free (nbuf);
|
||||
free (dirp);
|
||||
|
||||
remname (name);
|
||||
remove_exact_name (name, current_stat_info.file_name);
|
||||
}
|
||||
}
|
||||
else if (tar_timespec_cmp (get_stat_mtime (&s),
|
||||
current_stat_info.mtime)
|
||||
<= 0)
|
||||
remname (name);
|
||||
{
|
||||
remove_exact_name (name, current_stat_info.file_name);
|
||||
}
|
||||
else if (name->is_wildcard)
|
||||
addname (current_stat_info.file_name,
|
||||
name->change_dir, false, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
skip_member ();
|
||||
skim_member (acting_as_filter);
|
||||
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-2017 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright 2004-2023 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-2017 Free Software Foundation, Inc.
|
||||
Copyright 2009-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -48,6 +48,8 @@ static char const *const warning_args[] = {
|
||||
"xattr-write",
|
||||
"record-size",
|
||||
"failed-read",
|
||||
"missing-zero-blocks",
|
||||
"verbose",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -76,12 +78,14 @@ static int warning_types[] = {
|
||||
WARN_EXISTING_FILE,
|
||||
WARN_XATTR_WRITE,
|
||||
WARN_RECORD_SIZE,
|
||||
WARN_FAILED_READ
|
||||
WARN_FAILED_READ,
|
||||
WARN_MISSING_ZERO_BLOCKS,
|
||||
WARN_VERBOSE_WARNINGS,
|
||||
};
|
||||
|
||||
ARGMATCH_VERIFY (warning_args, warning_types);
|
||||
|
||||
int warning_option = WARN_ALL;
|
||||
int warning_option = WARN_ALL & ~(WARN_VERBOSE_WARNINGS|WARN_MISSING_ZERO_BLOCKS);
|
||||
|
||||
void
|
||||
set_warning_option (const char *arg)
|
||||
|
||||
221
src/xattrs.c
221
src/xattrs.c
@@ -1,6 +1,6 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -30,6 +30,83 @@
|
||||
#include "xattr-at.h"
|
||||
#include "selinux-at.h"
|
||||
|
||||
#define XATTRS_PREFIX "SCHILY.xattr."
|
||||
#define XATTRS_PREFIX_LEN (sizeof XATTRS_PREFIX - 1)
|
||||
|
||||
void
|
||||
xheader_xattr_init (struct tar_stat_info *st)
|
||||
{
|
||||
xattr_map_init (&st->xattr_map);
|
||||
|
||||
st->acls_a_ptr = NULL;
|
||||
st->acls_a_len = 0;
|
||||
st->acls_d_ptr = NULL;
|
||||
st->acls_d_len = 0;
|
||||
st->cntx_name = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_init (struct xattr_map *map)
|
||||
{
|
||||
memset (map, 0, sizeof *map);
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_free (struct xattr_map *xattr_map)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < xattr_map->xm_size; i++)
|
||||
{
|
||||
free (xattr_map->xm_map[i].xkey);
|
||||
free (xattr_map->xm_map[i].xval_ptr);
|
||||
}
|
||||
free (xattr_map->xm_map);
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_add (struct xattr_map *map,
|
||||
const char *key, const char *val, size_t len)
|
||||
{
|
||||
struct xattr_array *p;
|
||||
|
||||
if (map->xm_size == map->xm_max)
|
||||
map->xm_map = x2nrealloc (map->xm_map, &map->xm_max,
|
||||
sizeof (map->xm_map[0]));
|
||||
p = &map->xm_map[map->xm_size];
|
||||
p->xkey = xstrdup (key);
|
||||
p->xval_ptr = xmemdup (val, len + 1);
|
||||
p->xval_len = len;
|
||||
map->xm_size++;
|
||||
}
|
||||
|
||||
void
|
||||
xheader_xattr_add (struct tar_stat_info *st,
|
||||
const char *key, const char *val, size_t len)
|
||||
{
|
||||
size_t klen = strlen (key);
|
||||
char *xkey = xmalloc (XATTRS_PREFIX_LEN + klen + 1);
|
||||
char *tmp = xkey;
|
||||
|
||||
tmp = stpcpy (tmp, XATTRS_PREFIX);
|
||||
stpcpy (tmp, key);
|
||||
|
||||
xattr_map_add (&st->xattr_map, xkey, val, len);
|
||||
|
||||
free (xkey);
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_copy (struct xattr_map *dst, const struct xattr_map *src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < src->xm_size; i++)
|
||||
xattr_map_add (dst, src->xm_map[i].xkey,
|
||||
src->xm_map[i].xval_ptr,
|
||||
src->xm_map[i].xval_len);
|
||||
}
|
||||
|
||||
struct xattrs_mask_map
|
||||
{
|
||||
const char **masks;
|
||||
@@ -53,6 +130,10 @@ static struct
|
||||
#ifdef HAVE_POSIX_ACLS
|
||||
# include "acl.h"
|
||||
# include <sys/acl.h>
|
||||
# ifdef HAVE_ACL_LIBACL_H
|
||||
# /* needed for numeric-owner support */
|
||||
# include <acl/libacl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACLS
|
||||
@@ -204,13 +285,12 @@ fixup_extra_acl_fields (char *ptr)
|
||||
static void
|
||||
xattrs__acls_set (struct tar_stat_info const *st,
|
||||
char const *file_name, int type,
|
||||
char *ptr, size_t len, bool def)
|
||||
char *ptr, bool def)
|
||||
{
|
||||
acl_t acl;
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
/* assert (strlen (ptr) == len); */
|
||||
ptr = fixup_extra_acl_fields (ptr);
|
||||
acl = acl_from_text (ptr);
|
||||
}
|
||||
@@ -246,23 +326,60 @@ 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_get_a (int parentfd, const char *file_name,
|
||||
struct tar_stat_info *st,
|
||||
char **ret_ptr, size_t * ret_len)
|
||||
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
|
||||
acls_get_text (int parentfd, const char *file_name, acl_type_t type,
|
||||
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)))
|
||||
if (!(acl = acl_get_file_at (parentfd, file_name, type)))
|
||||
{
|
||||
if (errno != ENOTSUP)
|
||||
call_arg_warn ("acl_get_file_at", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
val = acl_to_text (acl, &len);
|
||||
if (numeric_owner_option)
|
||||
{
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
val = acl_to_any_text (acl, NULL, '\n',
|
||||
TEXT_SOME_EFFECTIVE | TEXT_NUMERIC_IDS);
|
||||
#else
|
||||
static int warned;
|
||||
if (!warned)
|
||||
{
|
||||
WARN ((0, 0, _("--numeric-owner is ignored for ACLs: libacl is not available")));
|
||||
warned = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
val = acl_to_text (acl, NULL);
|
||||
acl_free (acl);
|
||||
|
||||
if (!val)
|
||||
@@ -272,41 +389,23 @@ 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);
|
||||
}
|
||||
|
||||
static void
|
||||
xattrs__acls_get_a (int parentfd, const char *file_name,
|
||||
char **ret_ptr, size_t *ret_len)
|
||||
{
|
||||
acls_get_text (parentfd, file_name, ACL_TYPE_ACCESS, ret_ptr, ret_len);
|
||||
}
|
||||
|
||||
/* "system.posix_acl_default" */
|
||||
static void
|
||||
xattrs__acls_get_d (int parentfd, char const *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_DEFAULT)))
|
||||
{
|
||||
if (errno != ENOTSUP)
|
||||
call_arg_warn ("acl_get_file_at", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
val = acl_to_text (acl, &len);
|
||||
acl_free (acl);
|
||||
|
||||
if (!val)
|
||||
{
|
||||
call_arg_warn ("acl_to_text", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
*ret_ptr = xstrdup (val);
|
||||
*ret_len = len;
|
||||
|
||||
acl_free (val);
|
||||
acls_get_text (parentfd, file_name, ACL_TYPE_DEFAULT, ret_ptr, ret_len);
|
||||
}
|
||||
#endif /* HAVE_POSIX_ACLS */
|
||||
|
||||
@@ -336,6 +435,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;
|
||||
}
|
||||
|
||||
@@ -348,7 +448,7 @@ acls_one_line (const char *prefix, char delim,
|
||||
|
||||
void
|
||||
xattrs_acls_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd, int xisfile)
|
||||
struct tar_stat_info *st, int xisfile)
|
||||
{
|
||||
if (acls_option > 0)
|
||||
{
|
||||
@@ -367,10 +467,10 @@ xattrs_acls_get (int parentfd, char const *file_name,
|
||||
return;
|
||||
}
|
||||
|
||||
xattrs__acls_get_a (parentfd, file_name, st,
|
||||
xattrs__acls_get_a (parentfd, file_name,
|
||||
&st->acls_a_ptr, &st->acls_a_len);
|
||||
if (!xisfile)
|
||||
xattrs__acls_get_d (parentfd, file_name, st,
|
||||
xattrs__acls_get_d (parentfd, file_name,
|
||||
&st->acls_d_ptr, &st->acls_d_len);
|
||||
#endif
|
||||
}
|
||||
@@ -389,10 +489,10 @@ xattrs_acls_set (struct tar_stat_info const *st,
|
||||
done = 1;
|
||||
#else
|
||||
xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
|
||||
st->acls_a_ptr, st->acls_a_len, false);
|
||||
st->acls_a_ptr, false);
|
||||
if (typeflag == DIRTYPE || typeflag == GNUTYPE_DUMPDIR)
|
||||
xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
|
||||
st->acls_d_ptr, st->acls_d_len, true);
|
||||
st->acls_d_ptr, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -512,8 +612,7 @@ xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
static void
|
||||
xattrs__fd_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag,
|
||||
xattrs__fd_set (char const *file_name, char typeflag,
|
||||
const char *attr, const char *ptr, size_t len)
|
||||
{
|
||||
if (ptr)
|
||||
@@ -629,7 +728,7 @@ xattrs_kw_included (const char *kw, bool archiving)
|
||||
}
|
||||
|
||||
static bool
|
||||
xattrs_kw_excluded (const char *kw, bool archiving)
|
||||
xattrs_kw_excluded (const char *kw)
|
||||
{
|
||||
return xattrs_setup.excl.size ?
|
||||
xattrs_matches_mask (kw, &xattrs_setup.excl) : false;
|
||||
@@ -641,8 +740,7 @@ xattrs_kw_excluded (const char *kw, bool archiving)
|
||||
static bool
|
||||
xattrs_masked_out (const char *kw, bool archiving)
|
||||
{
|
||||
return xattrs_kw_included (kw, archiving) ?
|
||||
xattrs_kw_excluded (kw, archiving) : true;
|
||||
return xattrs_kw_included (kw, archiving) ? xattrs_kw_excluded (kw) : true;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -657,15 +755,14 @@ xattrs_xattrs_set (struct tar_stat_info const *st,
|
||||
WARN ((0, 0, _("XATTR support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
size_t scan = 0;
|
||||
size_t i;
|
||||
|
||||
if (!st->xattr_map_size)
|
||||
if (!st->xattr_map.xm_size)
|
||||
return;
|
||||
|
||||
for (; scan < st->xattr_map_size; ++scan)
|
||||
for (i = 0; i < st->xattr_map.xm_size; i++)
|
||||
{
|
||||
char *keyword = st->xattr_map[scan].xkey;
|
||||
keyword += strlen ("SCHILY.xattr.");
|
||||
char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
|
||||
|
||||
/* TODO: this 'later_run' workaround is temporary solution -> once
|
||||
capabilities should become fully supported by it's API and there
|
||||
@@ -681,9 +778,9 @@ xattrs_xattrs_set (struct tar_stat_info const *st,
|
||||
/* we don't want to restore this keyword */
|
||||
continue;
|
||||
|
||||
xattrs__fd_set (st, file_name, typeflag, keyword,
|
||||
st->xattr_map[scan].xval_ptr,
|
||||
st->xattr_map[scan].xval_len);
|
||||
xattrs__fd_set (file_name, typeflag, keyword,
|
||||
st->xattr_map.xm_map[i].xval_ptr,
|
||||
st->xattr_map.xm_map[i].xval_len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -707,10 +804,10 @@ xattrs_print_char (struct tar_stat_info const *st, char *output)
|
||||
output[1] = 0;
|
||||
}
|
||||
|
||||
if (xattrs_option > 0 && st->xattr_map_size)
|
||||
for (i = 0; i < st->xattr_map_size; ++i)
|
||||
if (xattrs_option > 0 && st->xattr_map.xm_size)
|
||||
for (i = 0; i < st->xattr_map.xm_size; ++i)
|
||||
{
|
||||
char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr.");
|
||||
char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
|
||||
if (!xattrs_masked_out (keyword, false /* like extracting */ ))
|
||||
{
|
||||
*output = '*';
|
||||
@@ -740,21 +837,23 @@ 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");
|
||||
}
|
||||
|
||||
/* xattrs */
|
||||
if (xattrs_option > 0 && st->xattr_map_size)
|
||||
if (xattrs_option > 0 && st->xattr_map.xm_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < st->xattr_map_size; ++i)
|
||||
for (i = 0; i < st->xattr_map.xm_size; ++i)
|
||||
{
|
||||
char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr.");
|
||||
char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
|
||||
if (!xattrs_masked_out (keyword, false /* like extracting */ ))
|
||||
fprintf (stdlis, " x: %lu %s\n",
|
||||
(unsigned long) st->xattr_map[i].xval_len, keyword);
|
||||
(unsigned long) st->xattr_map.xm_map[i].xval_len, keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -30,7 +30,7 @@ extern void xattrs_mask_add (const char *mask, bool incl);
|
||||
extern void xattrs_clear_setup (void);
|
||||
|
||||
extern void xattrs_acls_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd, int xisfile);
|
||||
struct tar_stat_info *st, int xisfile);
|
||||
extern void xattrs_selinux_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd);
|
||||
extern void xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
|
||||
369
src/xheader.c
369
src/xheader.c
@@ -1,7 +1,6 @@
|
||||
/* POSIX extended headers for tar.
|
||||
|
||||
Copyright (C) 2003-2007, 2009-2010, 2012-2014, 2016-2017 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright (C) 2003-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -30,7 +29,6 @@
|
||||
static void xheader_init (struct xheader *xhdr);
|
||||
static bool xheader_protected_pattern_p (char const *pattern);
|
||||
static bool xheader_protected_keyword_p (char const *keyword);
|
||||
static void xheader_set_single_keyword (char *) __attribute__ ((noreturn));
|
||||
|
||||
/* Used by xheader_finish() */
|
||||
static void code_string (char const *string, char const *keyword,
|
||||
@@ -159,7 +157,7 @@ xheader_list_destroy (struct keyword_list **root)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static _Noreturn void
|
||||
xheader_set_single_keyword (char *kw)
|
||||
{
|
||||
USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet implemented"), kw));
|
||||
@@ -185,6 +183,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 +256,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 +267,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 +368,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,46 +484,12 @@ xheader_write_global (struct xheader *xhdr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Forbid modifications of the global extended header */
|
||||
void
|
||||
xheader_xattr_init (struct tar_stat_info *st)
|
||||
xheader_forbid_global (void)
|
||||
{
|
||||
st->xattr_map = NULL;
|
||||
st->xattr_map_size = 0;
|
||||
|
||||
st->acls_a_ptr = NULL;
|
||||
st->acls_a_len = 0;
|
||||
st->acls_d_ptr = NULL;
|
||||
st->acls_d_len = 0;
|
||||
st->cntx_name = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size)
|
||||
{
|
||||
size_t scan = 0;
|
||||
|
||||
while (scan < xattr_map_size)
|
||||
{
|
||||
free (xattr_map[scan].xkey);
|
||||
free (xattr_map[scan].xval_ptr);
|
||||
|
||||
++scan;
|
||||
}
|
||||
free (xattr_map);
|
||||
}
|
||||
|
||||
static void
|
||||
xheader_xattr__add (struct xattr_array **xattr_map,
|
||||
size_t *xattr_map_size,
|
||||
const char *key, const char *val, size_t len)
|
||||
{
|
||||
size_t pos = (*xattr_map_size)++;
|
||||
|
||||
*xattr_map = xrealloc (*xattr_map,
|
||||
*xattr_map_size * sizeof(struct xattr_array));
|
||||
(*xattr_map)[pos].xkey = xstrdup (key);
|
||||
(*xattr_map)[pos].xval_ptr = xmemdup (val, len + 1);
|
||||
(*xattr_map)[pos].xval_len = len;
|
||||
if (keyword_global_override_list)
|
||||
USAGE_ERROR ((0, 0, _("can't update global extended header record")));
|
||||
}
|
||||
|
||||
/* This is reversal function for xattr_encode_keyword. See comment for
|
||||
@@ -537,44 +529,6 @@ xattr_decode_keyword (char *keyword)
|
||||
kpl++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xheader_xattr_add (struct tar_stat_info *st,
|
||||
const char *key, const char *val, size_t len)
|
||||
{
|
||||
size_t klen = strlen (key);
|
||||
char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1);
|
||||
char *tmp = xkey;
|
||||
|
||||
tmp = stpcpy (tmp, "SCHILY.xattr.");
|
||||
stpcpy (tmp, key);
|
||||
|
||||
xheader_xattr__add (&st->xattr_map, &st->xattr_map_size, xkey, val, len);
|
||||
|
||||
free (xkey);
|
||||
}
|
||||
|
||||
void
|
||||
xheader_xattr_copy (const struct tar_stat_info *st,
|
||||
struct xattr_array **xattr_map, size_t *xattr_map_size)
|
||||
{
|
||||
size_t scan = 0;
|
||||
|
||||
*xattr_map = NULL;
|
||||
*xattr_map_size = 0;
|
||||
|
||||
while (scan < st->xattr_map_size)
|
||||
{
|
||||
char *key = st->xattr_map[scan].xkey;
|
||||
char *val = st->xattr_map[scan].xval_ptr;
|
||||
size_t len = st->xattr_map[scan].xval_len;
|
||||
|
||||
xheader_xattr__add(xattr_map, xattr_map_size, key, val, len);
|
||||
|
||||
++scan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* General Interface */
|
||||
|
||||
@@ -603,11 +557,11 @@ static struct xhdr_tab const *
|
||||
locate_handler (char const *keyword)
|
||||
{
|
||||
struct xhdr_tab const *p;
|
||||
|
||||
for (p = xhdr_tab; p->keyword; p++)
|
||||
if (p->prefix)
|
||||
{
|
||||
if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0)
|
||||
size_t kwlen = strlen (p->keyword);
|
||||
if (strncmp (p->keyword, keyword, kwlen) == 0 && keyword[kwlen] == '.')
|
||||
return p;
|
||||
}
|
||||
else
|
||||
@@ -674,7 +628,7 @@ decode_record (struct xheader *xhdr,
|
||||
if (len_max < len)
|
||||
{
|
||||
int len_len = len_lim - p;
|
||||
ERROR ((0, 0, _("Extended header length %*s is out of range"),
|
||||
ERROR ((0, 0, _("Extended header length %.*s is out of range"),
|
||||
len_len, p));
|
||||
return false;
|
||||
}
|
||||
@@ -769,7 +723,7 @@ xheader_decode (struct tar_stat_info *st)
|
||||
|
||||
static void
|
||||
decg (void *data, char const *keyword, char const *value,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
struct keyword_list **kwl = data;
|
||||
struct xhdr_tab const *tab = locate_handler (keyword);
|
||||
@@ -885,7 +839,7 @@ xattr_encode_keyword(const char *keyword)
|
||||
{
|
||||
char c = *keyword;
|
||||
|
||||
if (bp + 2 /* enough for URL encoding also.. */ >= encode_buffer_size)
|
||||
if (bp + 3 /* enough for URL encoding also.. */ >= encode_buffer_size)
|
||||
{
|
||||
encode_buffer = x2realloc (encode_buffer, &encode_buffer_size);
|
||||
}
|
||||
@@ -1105,6 +1059,12 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
keyword, arg));
|
||||
return false;
|
||||
}
|
||||
if (*arg_lim)
|
||||
{
|
||||
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
|
||||
keyword, arg));
|
||||
return false;
|
||||
}
|
||||
|
||||
*ts = t;
|
||||
return true;
|
||||
@@ -1161,24 +1121,24 @@ decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
|
||||
char const *keyword __attribute__ ((unused)),
|
||||
struct xheader *xhdr __attribute__ ((unused)),
|
||||
void const *data __attribute__ ((unused)))
|
||||
dummy_coder (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
MAYBE_UNUSED struct xheader *xhdr,
|
||||
MAYBE_UNUSED void const *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)),
|
||||
char const *keyword __attribute__ ((unused)),
|
||||
char const *arg __attribute__ ((unused)),
|
||||
size_t size __attribute__((unused)))
|
||||
dummy_decoder (MAYBE_UNUSED struct tar_stat_info *st,
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
MAYBE_UNUSED char const *arg,
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
atime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_time (st->atime, keyword, xhdr);
|
||||
}
|
||||
@@ -1187,7 +1147,7 @@ static void
|
||||
atime_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, keyword))
|
||||
@@ -1196,7 +1156,7 @@ atime_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
gid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_signed_num (st->stat.st_gid, keyword,
|
||||
TYPE_MINIMUM (gid_t), TYPE_MAXIMUM (gid_t), xhdr);
|
||||
@@ -1206,7 +1166,7 @@ static void
|
||||
gid_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
intmax_t u;
|
||||
if (decode_signed_num (&u, arg, TYPE_MINIMUM (gid_t),
|
||||
@@ -1216,39 +1176,39 @@ gid_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
gname_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_string (st->gname, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
gname_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
decode_string (&st->gname, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
linkpath_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_string (st->link_name, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
linkpath_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
decode_string (&st->link_name, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
ctime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_time (st->ctime, keyword, xhdr);
|
||||
}
|
||||
@@ -1257,7 +1217,7 @@ static void
|
||||
ctime_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, keyword))
|
||||
@@ -1276,7 +1236,7 @@ static void
|
||||
mtime_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, keyword))
|
||||
@@ -1285,7 +1245,7 @@ mtime_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
path_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_string (st->file_name, keyword, xhdr);
|
||||
}
|
||||
@@ -1293,17 +1253,20 @@ path_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
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);
|
||||
if (*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)),
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
if (! st->sparse_name_done)
|
||||
raw_path_decoder (st, arg);
|
||||
@@ -1311,9 +1274,9 @@ path_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
sparse_path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
st->sparse_name_done = true;
|
||||
raw_path_decoder (st, arg);
|
||||
@@ -1321,7 +1284,7 @@ sparse_path_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_num (st->stat.st_size, keyword, xhdr);
|
||||
}
|
||||
@@ -1330,7 +1293,7 @@ static void
|
||||
size_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
@@ -1339,7 +1302,7 @@ size_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
uid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_signed_num (st->stat.st_uid, keyword,
|
||||
TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t), xhdr);
|
||||
@@ -1349,7 +1312,7 @@ static void
|
||||
uid_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
intmax_t u;
|
||||
if (decode_signed_num (&u, arg, TYPE_MINIMUM (uid_t),
|
||||
@@ -1359,16 +1322,16 @@ uid_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
uname_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_string (st->uname, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
uname_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
decode_string (&st->uname, arg);
|
||||
}
|
||||
@@ -1384,7 +1347,7 @@ static void
|
||||
sparse_size_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
@@ -1397,7 +1360,7 @@ sparse_size_decoder (struct tar_stat_info *st,
|
||||
static void
|
||||
sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr,
|
||||
void const *data __attribute__ ((unused)))
|
||||
MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_num (st->sparse_map_avail, keyword, xhdr);
|
||||
}
|
||||
@@ -1406,7 +1369,7 @@ static void
|
||||
sparse_numblocks_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, SIZE_MAX, keyword))
|
||||
@@ -1429,7 +1392,7 @@ static void
|
||||
sparse_offset_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
@@ -1454,7 +1417,7 @@ static void
|
||||
sparse_numbytes_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
@@ -1471,7 +1434,7 @@ static void
|
||||
sparse_map_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
int offset = 1;
|
||||
struct sp_array e;
|
||||
@@ -1545,7 +1508,7 @@ sparse_map_decoder (struct tar_stat_info *st,
|
||||
}
|
||||
|
||||
static void
|
||||
dumpdir_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
dumpdir_coder (MAYBE_UNUSED struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
xheader_print_n (xhdr, keyword, data, dumpdir_size (data));
|
||||
@@ -1553,7 +1516,7 @@ dumpdir_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
|
||||
static void
|
||||
dumpdir_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size)
|
||||
{
|
||||
@@ -1562,23 +1525,25 @@ dumpdir_decoder (struct tar_stat_info *st,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_label_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
volume_label_coder (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
code_string (data, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
volume_label_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
volume_label_decoder (MAYBE_UNUSED struct tar_stat_info *st,
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
decode_string (&volume_label, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
volume_size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
volume_size_coder (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
off_t const *v = data;
|
||||
@@ -1586,9 +1551,9 @@ volume_size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_size_decoder (struct tar_stat_info *st,
|
||||
volume_size_decoder (MAYBE_UNUSED struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg, size_t size)
|
||||
char const *arg, MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
|
||||
@@ -1597,7 +1562,8 @@ volume_size_decoder (struct tar_stat_info *st,
|
||||
|
||||
/* FIXME: Merge with volume_size_coder */
|
||||
static void
|
||||
volume_offset_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
volume_offset_coder (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
off_t const *v = data;
|
||||
@@ -1605,9 +1571,9 @@ volume_offset_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_offset_decoder (struct tar_stat_info *st,
|
||||
volume_offset_decoder (MAYBE_UNUSED struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg, size_t size)
|
||||
char const *arg, MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
|
||||
@@ -1615,38 +1581,40 @@ volume_offset_decoder (struct tar_stat_info *st,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_filename_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
volume_filename_decoder (MAYBE_UNUSED struct tar_stat_info *st,
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
decode_string (&continued_file_name, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_string (st->cntx_name, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_selinux_decoder (struct tar_stat_info *st,
|
||||
char const *keyword, char const *arg, size_t size)
|
||||
MAYBE_UNUSED char const *keyword, char const *arg,
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
decode_string (&st->cntx_name, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_acls_a_decoder (struct tar_stat_info *st,
|
||||
char const *keyword, char const *arg, size_t size)
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg, size_t size)
|
||||
{
|
||||
st->acls_a_ptr = xmemdup (arg, size + 1);
|
||||
st->acls_a_len = size;
|
||||
@@ -1654,14 +1622,15 @@ xattr_acls_a_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_acls_d_decoder (struct tar_stat_info *st,
|
||||
char const *keyword, char const *arg, size_t size)
|
||||
MAYBE_UNUSED char const *keyword, char const *arg,
|
||||
size_t size)
|
||||
{
|
||||
st->acls_d_ptr = xmemdup (arg, size + 1);
|
||||
st->acls_d_len = size;
|
||||
@@ -1671,35 +1640,31 @@ static void
|
||||
xattr_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
struct xattr_array *xattr_map = st->xattr_map;
|
||||
const size_t *off = data;
|
||||
size_t n = *(size_t *)data;
|
||||
xheader_print_n (xhdr, keyword,
|
||||
xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
|
||||
st->xattr_map.xm_map[n].xval_ptr,
|
||||
st->xattr_map.xm_map[n].xval_len);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_decoder (struct tar_stat_info *st,
|
||||
char const *keyword, char const *arg, size_t size)
|
||||
{
|
||||
char *xstr, *xkey;
|
||||
char *xkey;
|
||||
|
||||
/* copy keyword */
|
||||
size_t klen_raw = strlen (keyword);
|
||||
xkey = alloca (klen_raw + 1);
|
||||
memcpy (xkey, keyword, klen_raw + 1) /* including null-terminating */;
|
||||
|
||||
/* copy value */
|
||||
xstr = alloca (size + 1);
|
||||
memcpy (xstr, arg, size + 1); /* separator included, for GNU tar '\n' */;
|
||||
xkey = xstrdup (keyword);
|
||||
|
||||
xattr_decode_keyword (xkey);
|
||||
|
||||
xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size);
|
||||
xattr_map_add (&st->xattr_map, xkey, arg, size);
|
||||
|
||||
free (xkey);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_num (st->sparse_major, keyword, xhdr);
|
||||
}
|
||||
@@ -1708,7 +1673,7 @@ static void
|
||||
sparse_major_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size)
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
|
||||
@@ -1717,7 +1682,7 @@ sparse_major_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
sparse_minor_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
struct xheader *xhdr, MAYBE_UNUSED void const *data)
|
||||
{
|
||||
code_num (st->sparse_minor, keyword, xhdr);
|
||||
}
|
||||
@@ -1726,7 +1691,7 @@ static void
|
||||
sparse_minor_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size)
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
|
||||
|
||||
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-2023 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. ##
|
||||
@@ -43,6 +47,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
|
||||
TESTSUITE_AT = \
|
||||
testsuite.at\
|
||||
compress.m4\
|
||||
T-cd.at\
|
||||
T-dir00.at\
|
||||
T-dir01.at\
|
||||
@@ -66,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\
|
||||
delete06.at\
|
||||
difflink.at\
|
||||
exclude.at\
|
||||
exclude01.at\
|
||||
@@ -110,6 +121,10 @@ TESTSUITE_AT = \
|
||||
extrac19.at\
|
||||
extrac20.at\
|
||||
extrac21.at\
|
||||
extrac22.at\
|
||||
extrac23.at\
|
||||
extrac24.at\
|
||||
extrac25.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
dirrem01.at\
|
||||
@@ -188,6 +203,7 @@ TESTSUITE_AT = \
|
||||
rename03.at\
|
||||
rename04.at\
|
||||
rename05.at\
|
||||
rename06.at\
|
||||
remfiles01.at\
|
||||
remfiles02.at\
|
||||
remfiles03.at\
|
||||
@@ -228,6 +244,9 @@ TESTSUITE_AT = \
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
sptrcreat.at\
|
||||
sptrdiff00.at\
|
||||
sptrdiff01.at\
|
||||
time01.at\
|
||||
time02.at\
|
||||
truncate.at\
|
||||
@@ -235,6 +254,7 @@ TESTSUITE_AT = \
|
||||
update01.at\
|
||||
update02.at\
|
||||
update03.at\
|
||||
update04.at\
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
@@ -257,6 +277,7 @@ TESTSUITE_AT = \
|
||||
xattr05.at\
|
||||
xattr06.at\
|
||||
xattr07.at\
|
||||
xattr08.at\
|
||||
acls01.at\
|
||||
acls02.at\
|
||||
acls03.at\
|
||||
@@ -310,4 +331,7 @@ AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/lib\
|
||||
-DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
LDADD = ../gnu/libgnu.a $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
|
||||
LDADD = ../gnu/libgnu.a\
|
||||
$(LIB_ACL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)\
|
||||
$(LIB_GETRANDOM) $(LIB_HARD_LOCALE) $(FILE_HAS_ACL_LIB) $(LIB_MBRTOWC)\
|
||||
$(LIB_SELINUX) $(LIB_SETLOCALE_NULL)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2014-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2014-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2006-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 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,8 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 2006-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2015-2023 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2015-2023 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-2017 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 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