Compare commits
335 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 | ||
|
|
f8459cf838 | ||
|
|
22b5645879 | ||
|
|
d44d592013 | ||
|
|
0c8e7bad3e | ||
|
|
37d7ce16c5 | ||
|
|
9ed0a6ba35 | ||
|
|
35008b75e4 | ||
|
|
9855bc011e | ||
|
|
22093ad2b6 | ||
|
|
ee0508f01c | ||
|
|
32e51de2af | ||
|
|
560f67c9f0 | ||
|
|
3ae075a51a | ||
|
|
1bf590ab2d | ||
|
|
dee7e3f16e | ||
|
|
13edc746f6 | ||
|
|
1e6d2c0488 | ||
|
|
228d83ed24 | ||
|
|
ede0d1b42d | ||
|
|
1e8b786e65 | ||
|
|
8b9026f3ae | ||
|
|
795877532e | ||
|
|
da8d0659a6 | ||
|
|
d06126f814 | ||
|
|
2be02a7c9a | ||
|
|
30fe67226a | ||
|
|
2bfacfe3d0 | ||
|
|
76dad6d1fb | ||
|
|
a2fd82f622 | ||
|
|
3a283cfe9f | ||
|
|
ca9399d4ee | ||
|
|
597b0ae509 | ||
|
|
21c1c29592 | ||
|
|
00f928642f | ||
|
|
c81a0853bb | ||
|
|
bb6ddd8e04 | ||
|
|
7340f67b98 | ||
|
|
1d2674bacc | ||
|
|
e1b7e40ff0 | ||
|
|
c2886473a8 | ||
|
|
ac065c57fd | ||
|
|
9a33077a7b | ||
|
|
20b55f0679 | ||
|
|
35b292ac4b | ||
|
|
61cd3fd268 | ||
|
|
3010818f36 | ||
|
|
733e2741b1 | ||
|
|
195a25316c | ||
|
|
74e3b497c4 | ||
|
|
29f652871e | ||
|
|
13d04fe6ae | ||
|
|
8d31493c99 | ||
|
|
752b447f3e | ||
|
|
a3aa7003ea | ||
|
|
143dc63ffa | ||
|
|
c0fb0740fa | ||
|
|
6ac0dd1d73 | ||
|
|
160fb9abd2 | ||
|
|
f6ad0e4af2 | ||
|
|
e4b246c14a | ||
|
|
2a7c84b4a9 | ||
|
|
da7845c656 | ||
|
|
8980ecd62d | ||
|
|
63f2e969dd | ||
|
|
445293654d | ||
|
|
b5f581e637 | ||
|
|
0f26331b17 | ||
|
|
196fef9b40 | ||
|
|
68dd249987 | ||
|
|
4cf2af4500 | ||
|
|
cadc43ace5 | ||
|
|
239441b5df | ||
|
|
0a93c16c62 | ||
|
|
5dd490e7f1 | ||
|
|
68e9ab4966 | ||
|
|
b684326e69 | ||
|
|
589ba77faf | ||
|
|
6ea9e62bb3 | ||
|
|
d02c81df15 | ||
|
|
e426787454 | ||
|
|
e6fcc73efa | ||
|
|
6167c23e22 | ||
|
|
5e2a1d5b38 | ||
|
|
4aebc943bb | ||
|
|
1a615a41f5 | ||
|
|
cdf41c383f | ||
|
|
a65086c71c | ||
|
|
ae23a57d70 | ||
|
|
c440a92627 | ||
|
|
aa9676dcad | ||
|
|
6cb94e37a9 | ||
|
|
232a7258c3 | ||
|
|
429bd311b7 | ||
|
|
eb621c67cf | ||
|
|
21f86195b7 | ||
|
|
fe3b106cb3 | ||
|
|
3828942550 | ||
|
|
d95457e007 | ||
|
|
da06935f6e | ||
|
|
15c02c2b9d | ||
|
|
0c4aa85e6c | ||
|
|
731b7b07de | ||
|
|
4eb1484dce | ||
|
|
1847ec67ce | ||
|
|
9c2b57232e | ||
|
|
55fb2fc38f | ||
|
|
5a9ac8312e | ||
|
|
7bf812579c | ||
|
|
1209e0ebff | ||
|
|
e7b6f8e3ae | ||
|
|
586a6263e9 | ||
|
|
ec94fbdf45 | ||
|
|
c48f4e8f6c | ||
|
|
e7c99a4dd1 | ||
|
|
e9ddc08da0 | ||
|
|
163e96a0e6 | ||
|
|
0e0a852e91 |
51
.gitignore
vendored
51
.gitignore
vendored
@@ -1,35 +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/*.h
|
||||
gnu/*/
|
||||
gnu/.gitignore
|
||||
gnu/charset.alias
|
||||
gnulib
|
||||
libtool
|
||||
m4
|
||||
paxutils
|
||||
rmt
|
||||
stamp-h1
|
||||
TAGS
|
||||
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "gnulib"]
|
||||
path = gnulib
|
||||
url = git://git.sv.gnu.org/gnulib.git
|
||||
[submodule "paxutils"]
|
||||
path = paxutils
|
||||
url = git://git.sv.gnu.org/paxutils.git
|
||||
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.
|
||||
|
||||
@@ -3186,7 +3186,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
Reported by Jeffrey Goldberg.
|
||||
|
||||
* rmt.h (_remdev): A filename is not remote if the colon is
|
||||
preceeded by a slash, to take care of `/:/' which is a shorthand
|
||||
preceded by a slash, to take care of `/:/' which is a shorthand
|
||||
for `/.../<CELL-NAME>/fs' on OSF's Distributing Computing
|
||||
Environment (DCE) and Distributed File System (DFS).
|
||||
Reported by Travis L. Priest.
|
||||
|
||||
@@ -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 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -26,7 +25,7 @@ dist-hook:
|
||||
$(MAKE) changelog_dir=$(distdir) ChangeLog
|
||||
-rm -f $(distdir).cpio
|
||||
find $(distdir) | cpio -Hcrc -o | \
|
||||
GZIP=$(GZIP_ENV) gzip -c > $(distdir).cpio.gz
|
||||
eval GZIP= gzip $(GZIP_ENV) -c > $(distdir).cpio.gz
|
||||
|
||||
distclean-local:
|
||||
-rm -f $(distdir).cpio.gz
|
||||
|
||||
299
NEWS
299
NEWS
@@ -1,5 +1,286 @@
|
||||
GNU tar NEWS - User visible changes. 2014-07-27
|
||||
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
|
||||
|
||||
* Member names containing '..' components are now skipped when extracting.
|
||||
|
||||
This fixes tar's behavior to match its documentation, and is a bit
|
||||
safer when extracting untrusted archives over old files (an unsafe
|
||||
practice that the tar manual has long recommended against).
|
||||
|
||||
* Report erroneous use of position-sensitive options.
|
||||
|
||||
During archive creation or update, tar keeps track of positional
|
||||
options (see the manual, subsection 3.4.4 "Position-Sensitive
|
||||
Options"), and reports those that had no effect. For example, when
|
||||
invoked as
|
||||
|
||||
tar -cf a.tar . --exclude '*.o'
|
||||
|
||||
tar will create the archive, but will exit with status 2, having
|
||||
issued the following error message
|
||||
|
||||
tar: The following options were used after non-optional
|
||||
arguments in archive create or update mode. These options are
|
||||
positional and affect only arguments that follow them. Please,
|
||||
rearrange them properly.
|
||||
tar: --exclude '*.o' has no effect
|
||||
tar: Exiting with failure status due to previous errors
|
||||
|
||||
* --numeric-owner now affects private headers too.
|
||||
|
||||
This helps the output of 'tar' to be more deterministic.
|
||||
|
||||
* Fixed the --delay-directory-restore option
|
||||
|
||||
In some cases tar would restore the directory permissions too early,
|
||||
causing subsequent link extractions in that directory to fail.
|
||||
|
||||
* The --warnings=failed-read option
|
||||
|
||||
This new warning control option suppresses warning messages about
|
||||
unreadable files and directories. It has effect only if used together
|
||||
with the --ignore-failed-read option.
|
||||
|
||||
* The --warnings=none option now suppresses all warnings
|
||||
|
||||
This includes warnings about unreadable files produced when
|
||||
--ignore-failed-read is in effect. To output these, use
|
||||
--warnings=none --warnings=no-failed-read.
|
||||
|
||||
* Fix reporting of hardlink mismatches during compare
|
||||
|
||||
Tar reported incorrect target file name in the 'Not linked to'
|
||||
diagnostic message.
|
||||
|
||||
|
||||
version 1.29 - Sergey Poznyakoff, 2016-05-16
|
||||
|
||||
* New options: --verbatim-files-from, --no-verbatim-files-from
|
||||
|
||||
The --verbatim-files-from option instructs tar to treat each line read
|
||||
from a file list as a file name, even if it starts with a dash.
|
||||
|
||||
File lists are supplied with the --files-from (-T) option. By
|
||||
default, each line read from a file list is first stripped off the
|
||||
leading and trailing whitespace and, if the result begins with a dash,
|
||||
it is treated as tar command line option.
|
||||
|
||||
Use the --verbatim-files-from option to disable this special handling.
|
||||
This facilitates the use of tar with file lists created automatically
|
||||
(e.g. by find(1) command).
|
||||
|
||||
This option affects all --files-from options that occur after it in
|
||||
the command line. Its effect is reverted by the
|
||||
--no-verbatim-files-from option.
|
||||
|
||||
* --null option reads file names verbatim
|
||||
|
||||
The --null option implies --verbatim-files-from. I.e. each line
|
||||
read from null-delimited file lists is treated as a file name.
|
||||
|
||||
This restores the documented behavior, which was broken in version
|
||||
1.27.
|
||||
|
||||
* New options: --owner-map=FILE and --group-map=FILE
|
||||
|
||||
These two options provide fine-grained control over what user/group
|
||||
names (or IDs) should be mapped when adding files to archive.
|
||||
|
||||
For both options, FILE is a plain text file with user or group
|
||||
mappings. Empty lines are ignored. Comments are introduced with
|
||||
# sign (unless quoted) and extend to the end of the corresponding
|
||||
line. Each non-empty line defines translation for a single UID (GID).
|
||||
It must consist of two fields, delimited by any amount of whitespace:
|
||||
|
||||
OLDNAME NEWNAME[:NEWID]
|
||||
|
||||
OLDNAME is either a valid user (group) name or a ID prefixed with +. Unless
|
||||
NEWID is supplied, NEWNAME must also be either a valid name or a
|
||||
+ID. Otherwise, both NEWNAME and NEWID need not be listed in the
|
||||
system user database.
|
||||
|
||||
* New option --clamp-mtime
|
||||
|
||||
The new --clamp-mtime option changes the behavior of --mtime to only
|
||||
use the time specified if the file mtime is newer than the given time.
|
||||
The --clamp-mtime option can only be used together with --mtime.
|
||||
|
||||
Typical use case is to make builds reproducible: to loose less
|
||||
information, it's better to keep the original date of an archive,
|
||||
except for files modified during the build process. In that case, using
|
||||
reference (and thus reproducible) timestamps for the latter is good
|
||||
enough.
|
||||
|
||||
See <https://wiki.debian.org/ReproducibleBuilds> for more information.
|
||||
|
||||
* Deprecated --preserve option removed
|
||||
|
||||
* Sparse file detection
|
||||
|
||||
Tar now uses SEEK_DATA/SEEK_HOLE on systems that support it. This
|
||||
allows for considerable speed-up in sparse-file detection.
|
||||
|
||||
New option --hole-detection is provided, that allows the user to
|
||||
select the algorithm used for hole detection. Available arguments
|
||||
are:
|
||||
|
||||
--hole-detection=seek
|
||||
Use lseek(2) SEEK_DATA and SEEK_HOLE "whence" parameters.
|
||||
|
||||
--hole-detection=raw
|
||||
Scan entire file before storing it to determine where holes
|
||||
are located.
|
||||
|
||||
The default is to use "seek" whenever possible, and fall back to
|
||||
"raw" otherwise.
|
||||
|
||||
|
||||
version 1.28, 2014-07-28
|
||||
@@ -21,7 +302,7 @@ sign and the specifier letter.
|
||||
deleted, correspondingly.
|
||||
%{FMT}t - Current local time using FMT as strftime(3) format.
|
||||
If {FMT} is omitted, use %c.
|
||||
%{N}* - Pad output with spaces to the Nth column, or to the
|
||||
%{N}* - Pad output with spaces to the Nth column, or to the
|
||||
current screen width, if {N} is not given.
|
||||
%c - A shortcut for "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r"
|
||||
|
||||
@@ -60,7 +341,7 @@ speed up archivation.
|
||||
--exclude-vcs-ignores Read exclude tags from VCS ignore files,
|
||||
where such files exist. Supported VCS's
|
||||
are: CVS, Git, Bazaar, Mercurial.
|
||||
|
||||
|
||||
|
||||
* Tar refuses to read input from and write output to a tty device.
|
||||
|
||||
@@ -69,7 +350,7 @@ speed up archivation.
|
||||
This release includes official tar(1) and rmt(8) manpages.
|
||||
Distribution maintainers are kindly asked to use these instead of the
|
||||
home-made pages they have been providing so far.
|
||||
|
||||
|
||||
|
||||
version 1.27.1 - Sergey Poznyakoff, 2013-11-17
|
||||
|
||||
@@ -162,7 +443,7 @@ tar discovers that the corresponding file name already exists and is a
|
||||
symbolic link, it first unlinks the entry, and then extracts the directory.
|
||||
|
||||
This option disables this behavior and instructs tar to follow
|
||||
symlinks to directories when extracting from the archive.
|
||||
symlinks to directories when extracting from the archive.
|
||||
|
||||
It is mainly intended to provide compatibility with the Slackware
|
||||
installation scripts.
|
||||
@@ -369,7 +650,7 @@ Modification times in ustar header blocks of extended headers
|
||||
are set to mtimes of the corresponding archive members. This
|
||||
can be overridden by the
|
||||
|
||||
--pax-opion='exthdr.mtime=STRING'
|
||||
--pax-option='exthdr.mtime=STRING'
|
||||
|
||||
command line option. The STRING is either number of seconds since
|
||||
the Epoch or a "Time reference" (see below).
|
||||
@@ -379,7 +660,7 @@ headers are set to the time when tar was invoked.
|
||||
|
||||
This can be overridden by the
|
||||
|
||||
--pax-opion='globexthdr.mtime=STRING'
|
||||
--pax-option='globexthdr.mtime=STRING'
|
||||
|
||||
command line option. The STRING is either number of seconds since
|
||||
the Epoch or a "Time reference" (see below).
|
||||
@@ -1505,7 +1786,7 @@ Versions 1.07 back to 1.00 by Jay Fenlason.
|
||||
|
||||
|
||||
|
||||
Copyright 1994-2001, 2003-2010, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -1525,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"
|
||||
|
||||
4
README
4
README
@@ -23,7 +23,6 @@ GNU 'tar' is derived from John Gilmore's public domain 'tar'.
|
||||
See file 'ABOUT-NLS' for how to customize this program to your language.
|
||||
See file 'COPYING' for copying conditions.
|
||||
See file 'INSTALL' for compilation and installation instructions.
|
||||
See file 'PORTS' for various ports of GNU tar to non-Unix systems.
|
||||
See file 'NEWS' for a list of major changes in the current release.
|
||||
See file 'THANKS' for a list of contributors.
|
||||
|
||||
@@ -222,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 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1990-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
60
README-alpha
60
README-alpha
@@ -3,67 +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 obtains various
|
||||
additional files from the CVS repository and the Translation Project
|
||||
site and prepares the source directory for building.
|
||||
|
||||
When run without arguments, bootstrap will try to obtain gnulib and
|
||||
paxutils files from their corresponding CVS repositories on Savannah
|
||||
using anonymous SSH access. Then, it will fetch the po files from tar
|
||||
page at Translation Project, and, finally, it will start autoconfiguration
|
||||
process. Simply running it without arguments should do in most cases.
|
||||
Several options allow to control the behavior of bootstrap:
|
||||
|
||||
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
|
||||
sources reside. Use this if you already
|
||||
have gnulib sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
|
||||
--paxutils-srcdir=DIRNAME Specify the local directory where paxutils
|
||||
sources reside. Use this if you already
|
||||
have paxutils sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
|
||||
--cvs-auth=METHOD Set the CVS access method used for downloading
|
||||
gnulib files. METHOD is one of the keywords
|
||||
accepted by cvs -d option (see info cvs
|
||||
repository).
|
||||
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
|
||||
--no-po Do not download po files.
|
||||
|
||||
Notice also that when using CVS authentication method "ext", bootstrap
|
||||
will set the variable CVS_RSH to "ssh", unless it is already set to
|
||||
some other value.
|
||||
|
||||
|
||||
|
||||
Copyright 2001, 2003-2005, 2007, 2013-2014 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 2001-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -8,12 +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>
|
||||
- Gnulib <http://www.gnu.org/software/gnulib>
|
||||
- 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
|
||||
|
||||
@@ -33,23 +43,28 @@ Once done, proceed as described in the file README (section
|
||||
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. In
|
||||
this case, you will probably want to save some time and bandwidth by
|
||||
avoiding downloading the same files again. If so, create in GNU tar
|
||||
root directory the file named '.bootstrap' with the following
|
||||
contents:
|
||||
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.
|
||||
|
||||
--gnulib-srcdir=$HOME/gnulib
|
||||
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.
|
||||
|
||||
Replace '$HOME/gnulib' with the actual directory where the Gnulib
|
||||
sources reside.
|
||||
The file bootstrap.conf contains bootstrapping configuration.
|
||||
Several options are provided that modify its behavior.
|
||||
Run './bootstrap --help' for a list.
|
||||
|
||||
For more information about 'bootstrap', run 'bootstrap --help'.
|
||||
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-2014 Free Software Foundation, Inc.
|
||||
Copyright 2007-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
10
THANKS
10
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
|
||||
@@ -78,6 +79,7 @@ Cesar Romani romani@ifm.uni-hamburg.de
|
||||
Chad Hurwitz churritz@cts.com
|
||||
Chance Reschke creschke@usra.edu
|
||||
Charles Fu ccwf@klab.caltech.edu
|
||||
Charles McGarvey chazmcgarvey@brokenzipper.com
|
||||
Charles Lopes Charles.Lopes@infm.ulst.ac.uk
|
||||
Charles M. Hannum mycroft@gnu.org
|
||||
Chip Salzenberg tct!chip
|
||||
@@ -93,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
|
||||
@@ -107,6 +110,7 @@ Conrad Hughes chughes@maths.tcd.ie
|
||||
Constantin Belous const@cris.net
|
||||
Coranth Gryphon gryphon@bur.visidyne.com
|
||||
Cyril Strejc strejc@unicontrols.cz
|
||||
Dagobert Michelsen dam@opencsw.org
|
||||
Dale R. Worley worley@world.std.com
|
||||
Dale Wiles wiles@geordi.calspan.com
|
||||
Dan Bloch dan@transarc.com
|
||||
@@ -114,6 +118,7 @@ Dan Drake dan@dandrake.org
|
||||
Dan Reish dreish@izzy.net
|
||||
Daniel Hagerty hag@gnu.org
|
||||
Daniel Quinlan quinlan@pathname.com
|
||||
Daniel Kahn Gillmor dkg@fifthhorseman.net
|
||||
Daniel R. Guilderson d.guilderson@ma30.bull.com
|
||||
Daniel S. Barclay daniel@compass-da.com
|
||||
Daniel Trinkle trinkle@cs.purdue.edu
|
||||
@@ -135,11 +140,13 @@ David Nugent davidn@blaze.net.au
|
||||
David Shaw david.shaw@alcatel.com.au
|
||||
David Steiner dsteiner@ispa.uni-osnabrueck.de
|
||||
David Taylor taylor@think.com
|
||||
Dawid dpc@dpc.pw
|
||||
Dean Gaudet dgaudet@watdragon.uwaterloo.ca
|
||||
Demizu Noritoshi nori-d@is.aist-nara.ac.jp
|
||||
Denis Excoffier denis.excoffier@free.fr
|
||||
Denis Fortin fortin@acm.org
|
||||
Dennis Pixton dennis@math.binghamton.edu
|
||||
Derek Terveer dt@hawkmoon.mn.org
|
||||
Dick Streefland dicks@tasking.nl
|
||||
Dietmar Braun dietmar@highway.bertelsmann.de
|
||||
Dimitri Bougoulias opus@hol.gr
|
||||
@@ -172,6 +179,7 @@ Erik D. Frederick edf@deckard.mc.duke.edu
|
||||
Esa Karell karell@cs.helsinki.fi
|
||||
Ezra Peisach epeisach@mit.edu
|
||||
Fabio d'Alessi cars@civ.bio.unipd.it
|
||||
Flavio Poletti polettix@gmail.com
|
||||
Frank Heckenbach frank@g-n-u.de
|
||||
Frank Koenen koenfr@lidp.com
|
||||
Franz-Werner Gergen gergen@edvulx.mpi-stuttgart.mpg.de
|
||||
@@ -202,6 +210,7 @@ Helmut Waitzmann Helmut.Waitzmann@web.de
|
||||
Henrik Bakman hb@csd.uu.se
|
||||
Hernan Prieto Schmidt hernan@pea.usp.br
|
||||
Hiroyuki Bessho bsh@grotto.iijnet.or.jp
|
||||
Holger Levsen holger@layer-acht.org
|
||||
Holger Teutsch holger@hotbso.rhein-main.de
|
||||
Hugh Secker-Walker hugh@ear.mit.edu
|
||||
Hunyue Yau hunyue.yau@picksys.com
|
||||
@@ -240,6 +249,7 @@ Jeffrey Goldberg J.Goldberg@cranfield.ac.uk
|
||||
Jeffrey Mark Siskind Qobi@emba.uvm.edu
|
||||
Jeffrey W. Parker jwpkr@mcs.com
|
||||
Jens Henrik Jensen recjhl@mediator.uni-c.dk
|
||||
Jérémy Bobbio lunar@debian.org
|
||||
Jim Blandy jimb@totoro.cs.oberlin.edu
|
||||
Jim Clausing jac@postbox.acs.ohio-state.edu
|
||||
Jim Farrell jwf@platinum.com
|
||||
|
||||
2
TODO
2
TODO
@@ -45,7 +45,7 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright 2003-2004, 2007, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2003-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
46
acinclude.m4
46
acinclude.m4
@@ -1,6 +1,6 @@
|
||||
dnl Special Autoconf macros for GNU tar -*- autoconf -*-
|
||||
|
||||
dnl Copyright 2009, 2013-2014 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)])
|
||||
@@ -40,37 +40,23 @@ AC_DEFUN([TAR_HEADERS_ATTR_XATTR_H],
|
||||
# First check for <sys/xattr.h>
|
||||
AC_CHECK_HEADERS([sys/xattr.h])
|
||||
AM_CONDITIONAL([TAR_COND_XATTR_H],[test "$ac_cv_header_sys_xattr_h" = yes])
|
||||
AM_CONDITIONAL([TAR_LIB_ATTR],[false])
|
||||
if test "$ac_cv_header_sys_xattr_h" = yes; then
|
||||
AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \
|
||||
setxattr fsetxattr lsetxattr \
|
||||
listxattr flistxattr llistxattr,
|
||||
# only when functions are present
|
||||
AC_DEFINE([HAVE_SYS_XATTR_H], [1],
|
||||
[define to 1 if we have <sys/xattr.h> header])
|
||||
if test "$with_xattrs" != no; then
|
||||
AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.])
|
||||
fi
|
||||
)
|
||||
fi
|
||||
|
||||
# If <sys/xattr.h> is not found, then check for <attr/xattr.h>
|
||||
if test "$ac_cv_header_sys_xattr_h" != yes; then
|
||||
AC_CHECK_HEADERS([attr/xattr.h])
|
||||
AM_CONDITIONAL([TAR_COND_XATTR_H],[test "$ac_cv_header_attr_xattr_h" = yes])
|
||||
AC_CHECK_LIB([attr],[fgetxattr])
|
||||
AM_CONDITIONAL([TAR_LIB_ATTR],[test "$ac_cv_lib_attr_fgetxattr" = yes])
|
||||
if test "$ac_cv_header_attr_xattr_h" = yes; then
|
||||
AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \
|
||||
setxattr fsetxattr lsetxattr \
|
||||
listxattr flistxattr llistxattr,
|
||||
# only when functions are present
|
||||
AC_DEFINE([HAVE_ATTR_XATTR_H], [1],
|
||||
[define to 1 if we have <attr/xattr.h> header])
|
||||
if test "$with_xattrs" != no; then
|
||||
AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.])
|
||||
fi
|
||||
)
|
||||
fi
|
||||
|
||||
if test "$with_xattrs" != no; then
|
||||
for i in getxattr fgetxattr lgetxattr \
|
||||
setxattr fsetxattr lsetxattr \
|
||||
listxattr flistxattr llistxattr
|
||||
do
|
||||
AC_SEARCH_LIBS($i, attr)
|
||||
eval found=\$ac_cv_search_$i
|
||||
test "$found" = "no" && break
|
||||
done
|
||||
|
||||
if test "$found" != no; then
|
||||
AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bootstrap configuration for GNU tar.
|
||||
|
||||
# Copyright 2006-2009, 2013-2014 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -26,10 +26,6 @@ avoided_gnulib_modules='
|
||||
--avoid=lock
|
||||
'
|
||||
|
||||
# gnulib modules used by this package.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep '^[^#]' gnulib.modules`
|
||||
"
|
||||
|
||||
# Additional xgettext options to use. Use "\\\newline" to break lines.
|
||||
XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
|
||||
@@ -64,10 +60,68 @@ 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
|
||||
PAXUTILS=paxutils
|
||||
|
||||
# gnulib modules used by this package.
|
||||
# getopt-gnu is for paxutils.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep -h '^[^#]' gnulib.modules`
|
||||
getopt-gnu
|
||||
"
|
||||
|
||||
# copy_files srcdir dstdir
|
||||
copy_files() {
|
||||
for file in `cat $1/DISTFILES`
|
||||
do
|
||||
case $file in
|
||||
"#*") continue;;
|
||||
esac
|
||||
dst=`echo $file | sed 's^.*/^^'`
|
||||
if [ $# -eq 3 ]; then
|
||||
case $dst in
|
||||
${3}*) ;;
|
||||
*) dst=${3}$dst;;
|
||||
esac
|
||||
fi
|
||||
if [ "$2" = '.' ]; then
|
||||
ln -sf $1/$file $2
|
||||
else
|
||||
symlink_to_dir "$1" "$file" "$2/$dst" || exit
|
||||
fi
|
||||
# FIXME ignorefile $2 $dst
|
||||
done
|
||||
}
|
||||
|
||||
bootstrap_post_import_hook() {
|
||||
|
||||
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
|
||||
|
||||
# Import from paxutils
|
||||
copy_files ${PAXUTILS} .
|
||||
copy_files ${PAXUTILS}/am m4
|
||||
|
||||
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
|
||||
|
||||
mkdir -p rmt
|
||||
|
||||
for dir in doc rmt lib tests; do
|
||||
copy_files ${PAXUTILS}/$dir $dir
|
||||
done
|
||||
|
||||
copy_files ${PAXUTILS}/paxlib lib pax
|
||||
}
|
||||
|
||||
68
configure.ac
68
configure.ac
@@ -1,6 +1,6 @@
|
||||
# Configure template for GNU tar. -*- autoconf -*-
|
||||
|
||||
# Copyright 1991, 1994-2010, 2013-2014 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.28], [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,8 @@ 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])
|
||||
gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw])
|
||||
@@ -158,12 +189,12 @@ 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])
|
||||
|
||||
AC_DEFINE([lint], [1], [Define to 1 if the compiler is checking for lint.])
|
||||
@@ -204,8 +235,7 @@ fi
|
||||
|
||||
TAR_HEADERS_ATTR_XATTR_H
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink grantpt])
|
||||
AM_CONDITIONAL([TAR_COND_GRANTPT], [test $ac_cv_func_grantpt = yes])
|
||||
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
|
||||
|
||||
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
|
||||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||||
@@ -249,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)
|
||||
|
||||
@@ -342,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)
|
||||
@@ -352,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)'
|
||||
@@ -367,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\
|
||||
@@ -375,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
|
||||
|
||||
3
doc/.gitignore
vendored
3
doc/.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
genfile.texi
|
||||
header.texi
|
||||
manual
|
||||
parse-datetime.texi
|
||||
stamp-vti
|
||||
tar.aux
|
||||
tar.cp
|
||||
@@ -24,3 +23,5 @@ tar.toc
|
||||
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 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -23,11 +22,11 @@ tar_TEXINFOS = \
|
||||
dumpdir.texi\
|
||||
tar-snapshot-edit.texi\
|
||||
fdl.texi\
|
||||
freemanuals.texi\
|
||||
genfile.texi\
|
||||
header.texi\
|
||||
intern.texi\
|
||||
parse-datetime.texi\
|
||||
recipes.texi\
|
||||
rendition.texi\
|
||||
snapshot.texi\
|
||||
sparse.texi\
|
||||
@@ -139,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:
|
||||
@@ -149,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,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006-2007, 2014 Free Software Foundation, 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.
|
||||
|
||||
11
doc/fdl.texi
11
doc/fdl.texi
@@ -5,9 +5,9 @@
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000-2002, 2007-2008, 2014 Free Software
|
||||
Copyright @copyright{} 2000--2002, 2007--2008, 2022 Free Software
|
||||
Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
@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 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 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
|
||||
@@ -87,6 +90,8 @@ The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and
|
||||
@code{gname} are null-terminated character strings. All other fields
|
||||
are zero-filled octal numbers in ASCII. Each numeric field of width
|
||||
@var{w} contains @var{w} minus 1 digits, and a null.
|
||||
(In the extended @acronym{GNU} format, the numeric fields can take
|
||||
other forms.)
|
||||
|
||||
The @code{name} field is the file name of the file, with directory names
|
||||
(if any) preceding the file name, separated by slashes.
|
||||
@@ -109,21 +114,20 @@ 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 is the data modification time of the file at
|
||||
the time it was archived. It is the ASCII representation of the octal
|
||||
value of the last time the file's contents were modified, represented
|
||||
as an integer number of
|
||||
The @code{mtime} field represents the data modification time of the file at
|
||||
the time it was archived. It represents the integer number of
|
||||
seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
||||
|
||||
The @code{chksum} field is the ASCII representation of the octal value
|
||||
of the simple sum of all bytes in the header block. Each 8-bit
|
||||
The @code{chksum} field represents
|
||||
the simple sum of all bytes in the header block. Each 8-bit
|
||||
byte in the header is added to an unsigned integer, initialized to
|
||||
zero, the precision of which shall be no less than seventeen bits.
|
||||
When calculating the checksum, the @code{chksum} field is treated as
|
||||
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.
|
||||
@@ -310,6 +314,18 @@ of an archive should have this type.
|
||||
|
||||
@end table
|
||||
|
||||
For fields containing numbers or timestamps that are out of range for
|
||||
the basic format, the @acronym{GNU} format uses a base-256
|
||||
representation instead of an ASCII octal number. If the leading byte
|
||||
is 0xff (255), all the bytes of the field (including the leading byte)
|
||||
are concatenated in big-endian order, with the result being a negative
|
||||
number expressed in two's complement form. If the leading byte is
|
||||
0x80 (128), the non-leading bytes of the field are concatenated in
|
||||
big-endian order, with the result being a positive number expressed in
|
||||
binary form. Leading bytes other than 0xff, 0x80 and ASCII octal
|
||||
digits are reserved for future use, as are base-256 representations of
|
||||
values that would be in range for the basic format.
|
||||
|
||||
You may have trouble reading a @acronym{GNU} format archive on a
|
||||
non-@acronym{GNU} system if the options @option{--incremental} (@option{-G}),
|
||||
@option{--multi-volume} (@option{-M}), @option{--sparse} (@option{-S}), or @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) were
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright 2006-2007, 2013-2014 Free Software Foundation, Inc.
|
||||
;; Copyright 2006-2023 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Sergey Poznyakoff
|
||||
;; Maintainer: bug-tar@gnu.org
|
||||
|
||||
134
doc/recipes.texi
Normal file
134
doc/recipes.texi
Normal file
@@ -0,0 +1,134 @@
|
||||
@c This is part of the GNU tar manual.
|
||||
@c Copyright (C) 2017--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.
|
||||
|
||||
This appendix provides several recipes for performing common tasks
|
||||
using @GNUTAR{}.
|
||||
|
||||
@menu
|
||||
* copy directory hierarchy::
|
||||
* intermediate directories::
|
||||
@end menu
|
||||
|
||||
@node copy directory hierarchy
|
||||
@appendixsec Copying directory hierarchies
|
||||
|
||||
This is a traditional way to copy a directory hierarchy preserving
|
||||
the dates, modes, owners and link-structure of all the files therein.
|
||||
It was used back when the @command{cp} command lacked the @option{-a}
|
||||
option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{(cd sourcedir; tar -cf - .) | (cd targetdir; tar -xf -)}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
You can avoid subshells by using @option{-C} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar -C sourcedir -cf - . | tar -C targetdir -xf -}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
The same command using long option forms:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{(cd sourcedir; tar --create --file=- . ) \
|
||||
| (cd targetdir; tar --extract --file=-)}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
or
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{tar --directory sourcedir --create --file=- . \
|
||||
| tar --directory targetdir --extract --file=-}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@node intermediate directories
|
||||
@appendixsec Restoring Intermediate Directories
|
||||
|
||||
A common concern is how to extract permissions and ownerships of
|
||||
intermediate directories when extracting only selected members from
|
||||
the archive. To illustrate this, consider the following archive:
|
||||
|
||||
@example
|
||||
@group
|
||||
# tar tvf A.tar
|
||||
drwxr-xr-x root/root 0 2017-11-16 14:39 foo/
|
||||
dr-xr-x--- gray/user 0 2017-11-16 14:39 foo/bar/
|
||||
-rw-r--r-- gray/user 10 2017-11-16 14:40 foo/bar/file
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Suppose you extract only the file @file{foo/bar/file}, while being
|
||||
@samp{root}:
|
||||
|
||||
@example
|
||||
# @kbd{tar xvf A.tar foo/bar/file}
|
||||
foo/bar/file
|
||||
@end example
|
||||
|
||||
Now, let's inspect the content of the created directories:
|
||||
|
||||
@example
|
||||
@group
|
||||
# find foo -ls
|
||||
427257 0 drwxr-xr-x 3 root root 16 Nov 17 16:10 foo
|
||||
427258 0 drwxr-xr-x 2 root root 17 Nov 17 16:10 foo/bar
|
||||
427259 0 -rw-r--r-- 1 gray user 10 Nov 6 14:40 foo/bar/file
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The requested file is restored, including its ownership and
|
||||
permissions. The intermediate directories, however, are created with
|
||||
the default permissions, current timestamp and owned by the current
|
||||
user. This is because by the time @command{tar} has reached the requested file,
|
||||
it had already skipped the entries for its parent directories, so it
|
||||
has no iformation about their ownership and modes.
|
||||
|
||||
To restore meta information about the intermediate directories,
|
||||
you'll need to specify them explicitly in the command line and use the
|
||||
@option{--no-recursive} option (@pxref{recurse}) to avoid extracting
|
||||
their content.
|
||||
|
||||
To automate this process, @cite{Neal P. Murphy} proposed the following
|
||||
shell script@footnote{The original version of the script can be
|
||||
seen at @uref{http://lists.gnu.org/archive/html/bug-tar/2016-11/msg00024.html}}:
|
||||
|
||||
@example
|
||||
@group
|
||||
#! /bin/sh
|
||||
(while read path
|
||||
do
|
||||
path=`dirname $path`
|
||||
while [ -n "$path" -a "$path" != "." ]
|
||||
do
|
||||
echo $path
|
||||
path=`dirname $path`
|
||||
done
|
||||
done < $2 | sort | uniq) |
|
||||
tar -x --no-recursion -v -f $1 -T - -T $2
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The script takes two arguments: the name of the archive file, and the
|
||||
name of the file list file.
|
||||
|
||||
To complete our example, the file list will contain single line:
|
||||
|
||||
@example
|
||||
foo/bar/file
|
||||
@end example
|
||||
|
||||
Supposing its name is @file{file.list} and the script is named
|
||||
@file{restore.sh}, you can invoke it as follows:
|
||||
|
||||
@example
|
||||
# @kbd{sh restore.sh A.tar file.list}
|
||||
@end example
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright 1992, 1994-1997, 1999-2004, 2006, 2013-2014 Free Software
|
||||
@c 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,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2005, 2007, 2014 Free Software Foundation, 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.
|
||||
@@ -116,7 +116,7 @@ epoch. These are followed by arbitrary number of directory records.
|
||||
particular directory. Parts of a directory record are delimited with
|
||||
@acronym{ASCII} 0 characters. The following table describes each
|
||||
part. The @dfn{Number} type in this table stands for a decimal integer
|
||||
in @acronym{ASCII} notation. (Negative values are preceeded with a "-"
|
||||
in @acronym{ASCII} notation. (Negative values are preceded with a "-"
|
||||
character, while positive values have no leading punctuation.)
|
||||
|
||||
@multitable @columnfractions 0.25 0.15 0.6
|
||||
@@ -146,7 +146,7 @@ is compiled. To see the specific ranges allowed for a particular
|
||||
@option{--show-snapshot-field-ranges} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --show-shapshot-field-ranges}
|
||||
$ @kbd{tar --show-snapshot-field-ranges}
|
||||
This tar's snapshot file field ranges are
|
||||
(field name => [ min, max ]):
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2014 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.
|
||||
|
||||
@@ -143,7 +143,7 @@ format, it will also extract a file containing extension header
|
||||
attributes. This file can be used to expand the file to its original
|
||||
state. However, posix-aware @command{tar}s will usually ignore the
|
||||
unknown variables, which makes restoring the file more
|
||||
difficult. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
difficult. @xref{extracting sparse v0x, Extraction of sparse
|
||||
members in v.0.0 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
@end enumerate
|
||||
@@ -175,7 +175,7 @@ The real name of the sparse file is stored in the variable
|
||||
@code{GNU.sparse.name}. Thus, those @command{tar} implementations
|
||||
that are not aware of GNU extensions will at least extract the files
|
||||
into separate directories, giving the user a possibility to expand it
|
||||
afterwards. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
afterwards. @xref{extracting sparse v0x, Extraction of sparse
|
||||
members in v.0.1 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
|
||||
@@ -218,12 +218,12 @@ The real name of the sparse file is stored in the variable
|
||||
variable @code{GNU.sparse.realsize}.
|
||||
|
||||
The sparse map itself is stored in the file data block, preceding the actual
|
||||
file data. It consists of a series of octal numbers of arbitrary length, delimited
|
||||
file data. It consists of a series of decimal numbers delimited
|
||||
by newlines. The map is padded with nulls to the nearest block boundary.
|
||||
|
||||
The first number gives the number of entries in the map. Following are map entries,
|
||||
each one consisting of two numbers giving the offset and size of the
|
||||
data block it describes.
|
||||
The first number gives the number of entries in the map. Following are
|
||||
map entries, each one consisting of two numbers giving the offset and
|
||||
size of the data block it describes.
|
||||
|
||||
The format is designed in such a way that non-posix aware @command{tar}s and @command{tar}s not
|
||||
supporting @code{GNU.sparse.*} keywords will extract each sparse file
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2007, 2014 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.
|
||||
|
||||
|
||||
335
doc/tar.1
335
doc/tar.1
@@ -1,5 +1,5 @@
|
||||
.\" This file is part of GNU tar. -*- nroff -*-
|
||||
.\" Copyright 2013-2014 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 "February 22, 2014" "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} [\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,18 +164,18 @@ 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
|
||||
(\fB\-\-ignore\-zeros) option.
|
||||
the resulting archive only when using the \fB\-i\fR
|
||||
(\fB\-\-ignore\-zeros\fR) option.
|
||||
|
||||
Compressed archives cannot be concatenated.
|
||||
.TP
|
||||
@@ -198,7 +198,7 @@ short option equivalent.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-append\fR
|
||||
Append files to the end of an archive. Arguments have the same
|
||||
meaning as for \fB\-c\fR (\fB\-\-create).
|
||||
meaning as for \fB\-c\fR (\fB\-\-create\fR).
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-list\fR
|
||||
List the contents of an archive. Arguments are optional. When given,
|
||||
@@ -218,8 +218,11 @@ 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
|
||||
\fB\-r\fR options.
|
||||
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
|
||||
same name, corresponding to various versions of the same file.
|
||||
.TP
|
||||
\fB\-x\fR, \fB\-\-extract\fR, \fB\-\-get\fR
|
||||
Extract files from an archive. Arguments are optional. When given,
|
||||
@@ -227,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.
|
||||
@@ -246,19 +248,24 @@ 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
|
||||
\fB\-\-hole\-detection\fR=\fIMETHOD\fR
|
||||
Use \fIMETHOD\fR to detect holes in sparse files. This option implies
|
||||
\fB\-\-sparse\fR. Valid values for \fIMETHOD\fR are \fBseek\fR and
|
||||
\fBraw\fR. Default is \fBseek\fR with fallback to \fBraw\fR when not
|
||||
applicable.
|
||||
.TP
|
||||
\fB\-G\fR, \fB\-\-incremental\fR
|
||||
Handle old GNU-format incremental backups.
|
||||
.TP
|
||||
@@ -266,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
|
||||
@@ -278,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.
|
||||
@@ -291,14 +298,14 @@ Process only the \fIN\fRth occurrence of each file in the
|
||||
archive. This option is valid only when used with one of the
|
||||
following subcommands: \fB\-\-delete\fR, \fB\-\-diff\fR,
|
||||
\fB\-\-extract\fR or \fB\-\-list\fR and when a list of files is given
|
||||
either on the command line or via the \fB\-\fRT option. The default
|
||||
either on the command line or via the \fB\-T\fR option. The default
|
||||
\fIN\fR is \fB1\fR.
|
||||
.TP
|
||||
\fB\-\-restrict\fR
|
||||
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
|
||||
@@ -306,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
|
||||
@@ -327,6 +334,9 @@ Don't replace existing files when extracting.
|
||||
\fB\-\-keep\-newer\-files\fR
|
||||
Don't replace existing files that are newer than their archive copies.
|
||||
.TP
|
||||
\fB\-\-keep\-directory\-symlink\fR
|
||||
Don't replace existing symlinks to directories when extracting.
|
||||
.TP
|
||||
\fB\-\-no\-overwrite\-dir\fR
|
||||
Preserve metadata of existing directories.
|
||||
.TP
|
||||
@@ -347,6 +357,9 @@ Recursively remove all files in the directory prior to extracting it.
|
||||
\fB\-\-remove\-files\fR
|
||||
Remove files from disk after adding them to the archive.
|
||||
.TP
|
||||
\fB\-\-skip\-old\-files
|
||||
Don't replace existing files when extracting, silently skip over them.
|
||||
.TP
|
||||
\fB\-U\fR, \fB\-\-unlink\-first\fR
|
||||
Remove each file prior to extracting over it.
|
||||
.TP
|
||||
@@ -355,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
|
||||
@@ -368,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
|
||||
@@ -448,31 +460,57 @@ 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
|
||||
directories until the end of extraction. Use this option when
|
||||
extracting from an archive which has unusual member ordering.
|
||||
.TP
|
||||
\fB\-\-group\fR=\fINAME\fR
|
||||
Force \fINAME\fR as group for added files.
|
||||
\fB\-\-group\fR=\fINAME\fR[:\fIGID\fR]
|
||||
Force \fINAME\fR as group for added files. If \fIGID\fR is not
|
||||
supplied, \fINAME\fR can be either a user name or numeric GID. In
|
||||
this case the missing part (GID or name) will be inferred from the
|
||||
current host's group database.
|
||||
|
||||
When used with \fB\-\-group\-map\fR=\fIFILE\fR, affects only those
|
||||
files whose owner group is not listed in \fIFILE\fR.
|
||||
.TP
|
||||
\fB\-\-group\-map\fR=\fIFILE\fR
|
||||
Read group translation map from \fIFILE\fR. Empty lines are ignored.
|
||||
Comments are introduced with \fB#\fR sign and extend to the end of line.
|
||||
Each non-empty line in \fIFILE\fR defines translation for a single
|
||||
group. It must consist of two fields, delimited by any amount of whitespace:
|
||||
|
||||
.EX
|
||||
\fIOLDGRP\fR \fINEWGRP\fR[\fB:\fINEWGID\fR]
|
||||
.EE
|
||||
|
||||
\fIOLDGRP\fR is either a valid group name or a GID prefixed with
|
||||
\fB+\fR. Unless \fINEWGID\fR is supplied, \fINEWGRP\fR must also be
|
||||
either a valid group name or a \fB+\fIGID\fR. Otherwise, both
|
||||
\fINEWGRP\fR and \fINEWGID\fR need not be listed in the system group
|
||||
database.
|
||||
|
||||
As a result, each input file with owner group \fIOLDGRP\fR will be
|
||||
stored in archive with owner group \fINEWGRP\fR and GID \fINEWGID\fR.
|
||||
.TP
|
||||
\fB\-\-mode\fR=\fICHANGES\fR
|
||||
Force symbolic mode \fICHANGES\fR for added files.
|
||||
.TP
|
||||
\fB\-\-mtime\fR=\fIDATE-OR-FILE\fR
|
||||
Set mtime for added files. \fIDATE-OR-FILE\fR is either a date/time
|
||||
in almost arbitrary formate, or the name of an existing file. In the
|
||||
in almost arbitrary format, or the name of an existing file. In the
|
||||
latter case the mtime of that file will be used.
|
||||
.TP
|
||||
\fB\-m\fR, \fB\-\-touch\fR
|
||||
@@ -491,21 +529,45 @@ Apply the user's umask when extracting permissions from the archive
|
||||
\fB\-\-numeric\-owner\fR
|
||||
Always use numbers for user/group names.
|
||||
.TP
|
||||
\fB\-\-owner\fR=\fINAME\fR
|
||||
Force \fINAME\fR as owner for added files.
|
||||
\fB\-\-owner\fR=\fINAME\fR[:\fIUID\fR]
|
||||
Force \fINAME\fR as owner for added files. If \fIUID\fR is not
|
||||
supplied, \fINAME\fR can be either a user name or numeric UID. In
|
||||
this case the missing part (UID or name) will be inferred from the
|
||||
current host's user database.
|
||||
|
||||
When used with \fB\-\-owner\-map\fR=\fIFILE\fR, affects only those
|
||||
files whose owner is not listed in \fIFILE\fR.
|
||||
.TP
|
||||
\fB\-\-owner\-map\fR=\fIFILE\fR
|
||||
Read owner translation map from \fIFILE\fR. Empty lines are ignored.
|
||||
Comments are introduced with \fB#\fR sign and extend to the end of line.
|
||||
Each non-empty line in \fIFILE\fR defines translation for a single
|
||||
UID. It must consist of two fields, delimited by any amount of whitespace:
|
||||
|
||||
.EX
|
||||
\fIOLDUSR\fR \fINEWUSR\fR[\fB:\fINEWUID\fR]
|
||||
.EE
|
||||
|
||||
\fIOLDUSR\fR is either a valid user name or a UID prefixed with
|
||||
\fB+\fR. Unless \fINEWUID\fR is supplied, \fINEWUSR\fR must also be
|
||||
either a valid user name or a \fB+\fIUID\fR. Otherwise, both
|
||||
\fINEWUSR\fR and \fINEWUID\fR need not be listed in the system user
|
||||
database.
|
||||
|
||||
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
|
||||
@@ -524,6 +586,34 @@ Using \fB\-\-sort=inode\fR reduces the number of disk seeks made when
|
||||
creating the archive and thus can considerably speed up archivation.
|
||||
This sorting order is supported only if the underlying system provides
|
||||
the necessary information.
|
||||
.SS Extended file attributes
|
||||
.TP
|
||||
.B \-\-acls
|
||||
Enable POSIX ACLs support.
|
||||
.TP
|
||||
.B \-\-no\-acls
|
||||
Disable POSIX ACLs support.
|
||||
.TP
|
||||
.B \-\-selinux
|
||||
Enable SELinux context support.
|
||||
.TP
|
||||
.B \-\-no-selinux
|
||||
Disable SELinux context support.
|
||||
.TP
|
||||
.B \-\-xattrs
|
||||
Enable extended attributes support.
|
||||
.TP
|
||||
.B \-\-no\-xattrs
|
||||
Disable extended attributes support.
|
||||
.TP
|
||||
.BI \-\-xattrs\-exclude= PATTERN
|
||||
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 globbing
|
||||
pattern.
|
||||
.SS Device selection and switching
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-file\fR=\fIARCHIVE\fR
|
||||
@@ -557,7 +647,7 @@ instead. You can do so by giving the following command line option:
|
||||
--rsh-command=/usr/bin/ssh
|
||||
.EE
|
||||
|
||||
The remote mashine should have the
|
||||
The remote machine should have the
|
||||
.BR rmt (8)
|
||||
command installed. If its pathname does not match \fBtar\fR's
|
||||
default, you can inform \fBtar\fR about the correct pathname using the
|
||||
@@ -567,7 +657,7 @@ option.
|
||||
\fB\-\-force\-local\fR
|
||||
Archive file is local even if it has a colon.
|
||||
.TP
|
||||
\fB\-\fRF, \fB\-\-info\-script\fR=\fICOMMAND\fR, \fB\-\-new\-volume\-script\fR=\fICOMMAND\fR
|
||||
\fB\-F\fR, \fB\-\-info\-script\fR=\fICOMMAND\fR, \fB\-\-new\-volume\-script\fR=\fICOMMAND\fR
|
||||
Run \fICOMMAND\fR at the end of each tape (implies \fB\-M\fR). The
|
||||
command can include arguments. When started, it will inherit \fBtar\fR's
|
||||
environment plus the following variables:
|
||||
@@ -601,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
|
||||
|
||||
@@ -609,7 +699,7 @@ If the info script fails, \fBtar\fR exits; otherwise, it begins writing
|
||||
the next volume.
|
||||
.RE
|
||||
.TP
|
||||
\fB\-L\fR, \fB\-\-tape\-length\fR=\fN\fR
|
||||
\fB\-L\fR, \fB\-\-tape\-length\fR=\fIN\fR
|
||||
Change tape after writing \fIN\fRx1024 bytes. If \fIN\fR is followed
|
||||
by a size suffix (see the subsection
|
||||
.B Size suffixes
|
||||
@@ -639,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
|
||||
@@ -647,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
|
||||
@@ -690,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.
|
||||
@@ -703,7 +794,7 @@ use \fITEXT\fR as a globbing pattern for volume name.
|
||||
\fB\-a\fR, \fB\-\-auto\-compress\fR
|
||||
Use archive suffix to determine the compression program.
|
||||
.TP
|
||||
\fB\-\fRI, \fB\-\-use\-compress\-program\fI=\fICOMMAND\fR
|
||||
\fB\-I\fR, \fB\-\-use\-compress\-program\fI=\fICOMMAND\fR
|
||||
Filter data through \fICOMMAND\fR. It must accept the \fB\-d\fR
|
||||
option, for decompression. The argument can contain command line
|
||||
options.
|
||||
@@ -735,9 +826,13 @@ Do not use archive suffix to determine the compression program.
|
||||
Filter the archive through
|
||||
.BR gzip (1).
|
||||
.TP
|
||||
\fB\-\fRZ, \fB\-\-compress\fR, \fB\-\-uncompress\fR
|
||||
\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
|
||||
@@ -768,7 +863,8 @@ environment variable. If it is not set, \fBexisting\fR is assumed.
|
||||
.RE
|
||||
.TP
|
||||
\fB\-C\fR, \fB\-\-directory\fR=\fIDIR\fR
|
||||
Change to directory DIR.
|
||||
Change to \fIDIR\fR before performing any operations. This option is
|
||||
order-sensitive, i.e. it affects all options that follow.
|
||||
.TP
|
||||
\fB\-\-exclude\fR=\fIPATTERN\fR
|
||||
Exclude files matching \fIPATTERN\fR, a
|
||||
@@ -841,13 +937,31 @@ Avoid descending automatically in directories.
|
||||
\fB\-\-no\-unquote\fR
|
||||
Do not unquote input file or member names.
|
||||
.TP
|
||||
\fB\-\-no\-verbatim\-files\-from\fR
|
||||
Treat each line read from a file list as if it were supplied in the
|
||||
command line. I.e., leading and trailing whitespace is removed and,
|
||||
if the resulting string begins with a dash, it is treated as \fBtar\fR
|
||||
command line option.
|
||||
|
||||
This is the default behavior. The \fB\-\-no\-verbatim\-files\-from\fR
|
||||
option is provided as a way to restore it after
|
||||
\fB\-\-verbatim\-files\-from\fR option.
|
||||
|
||||
This option is positional: it affects all \fB\-\-files\-from\fR
|
||||
options that occur after it in, until \fB\-\-verbatim\-files\-from\fR
|
||||
option or end of line, whichever occurs first.
|
||||
|
||||
It is implied by the \fB\-\-no\-null\fR option.
|
||||
.TP
|
||||
\fB\-\-null\fR
|
||||
Instruct subsequent \fB\-T\fR options to read null-terminated names,
|
||||
disable handling of the \fB\-C\fR option read from the file.
|
||||
Instruct subsequent \fB\-T\fR options to read null-terminated names
|
||||
verbatim (disables special handling of names that start with a dash).
|
||||
|
||||
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
|
||||
@@ -865,10 +979,43 @@ unless overridden by environment variable \fBSIMPLE_BACKUP_SUFFIX\fR.
|
||||
.TP
|
||||
\fB\-T\fR, \fB\-\-files\-from\fR=\fIFILE\fR
|
||||
Get names to extract or create from \fIFILE\fR.
|
||||
|
||||
Unless specified otherwise, the \fIFILE\fR must contain a list of
|
||||
names separated by ASCII \fBLF\fR (i.e. one name per line). The
|
||||
names read are handled the same way as command line arguments. They
|
||||
undergo quote removal and word splitting, and any string that starts
|
||||
with a \fB\-\fR is handled as \fBtar\fR command line option.
|
||||
|
||||
If this behavior is undesirable, it can be turned off using the
|
||||
\fB\-\-verbatim\-files\-from\fR option.
|
||||
|
||||
The \fB\-\-null\fR option instructs \fBtar\fR that the names in
|
||||
\fIFILE\fR are separated by ASCII \fBNUL\fR character, instead of
|
||||
\fBLF\fR. It is useful if the list is generated by
|
||||
.BR find (1)
|
||||
.B \-print0
|
||||
predicate.
|
||||
.TP
|
||||
\fB\-\-unquote\fR
|
||||
Unquote file or member names (default).
|
||||
.TP
|
||||
\fB\-\-verbatim\-files\-from\fR
|
||||
Treat each line obtained from a file list as a file name, even if it
|
||||
starts with a dash. File lists are supplied with the
|
||||
\fB\-\-files\-from\fR (\fB\-T\fR) option. The default behavior is to
|
||||
handle names supplied in file lists as if they were typed in the
|
||||
command line, i.e. any names starting with a dash are treated as
|
||||
\fBtar\fR options. The \fB\-\-verbatim\-files\-from\fR option
|
||||
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\fR option.
|
||||
|
||||
This option is implied by the \fB\-\-null\fR option.
|
||||
|
||||
See also \fB\-\-add\-file\fR.
|
||||
.TP
|
||||
\fB\-X\fR, \fB\-\-exclude\-from\fR=\fIFILE\fR
|
||||
Exclude files matching patterns listed in FILE.
|
||||
.SS File name transformations
|
||||
@@ -876,7 +1023,7 @@ Exclude files matching patterns listed in FILE.
|
||||
\fB\-\-strip\-components\fR=\fINUMBER\fR
|
||||
Strip \fINUMBER\fR leading components from file names on extraction.
|
||||
.TP
|
||||
\fB\-\-transform\fR=\fIEXPRESSION\dR, \fB\-\-xform\fR=\fIEXPRESSION\fR
|
||||
\fB\-\-transform\fR=\fIEXPRESSION\fR, \fB\-\-xform\fR=\fIEXPRESSION\fR
|
||||
Use sed replace \fIEXPRESSION\fR to transform file names.
|
||||
.SS File name matching options
|
||||
These options affect both exclude and include patterns.
|
||||
@@ -912,6 +1059,10 @@ Display progress messages every \fIN\fRth record (default 10).
|
||||
\fB\-\-checkpoint\-action\fR=\fIACTION\fR
|
||||
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
|
||||
\fB\-\-mtime\fR.
|
||||
.TP
|
||||
\fB\-\-full\-time\fR
|
||||
Print file time to its full resolution.
|
||||
.TP
|
||||
@@ -954,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"
|
||||
@@ -965,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
|
||||
@@ -1011,16 +1166,25 @@ 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"
|
||||
.TP
|
||||
.B file-changed
|
||||
"%s: file changed as we read it"
|
||||
.TP
|
||||
.B failed-read
|
||||
Suppresses warnings about unreadable files or directories. This
|
||||
keyword applies only if used together with the
|
||||
.B \-\-ignore\-failed\-read
|
||||
option.
|
||||
.HP
|
||||
Keywords applicable for \fBtar --extract\fR:
|
||||
.TP
|
||||
.B existing\-file
|
||||
"%s: skipping existing file"
|
||||
.TP
|
||||
.B timestamp
|
||||
"%s: implausibly old time stamp %s"
|
||||
.br
|
||||
@@ -1048,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
|
||||
@@ -1103,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
|
||||
@@ -1111,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.
|
||||
@@ -1139,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
|
||||
@@ -1152,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>
|
||||
@@ -1171,4 +1335,3 @@ There is NO WARRANTY, to the extent permitted by law.
|
||||
.\" time-stamp-end: "\""
|
||||
.\" time-stamp-line-limit: 20
|
||||
.\" end:
|
||||
|
||||
|
||||
1622
doc/tar.texi
1622
doc/tar.texi
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
# Copyright 2006-2007, 2013-2014 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 Free Software
|
||||
@c Foundation, Inc.
|
||||
@c Copyright 1992--2023 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Make the subset of Gnulib that GNU tar needs.
|
||||
include gnulib.mk
|
||||
AM_CFLAGS += $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
1
gnulib
Submodule
1
gnulib
Submodule
Submodule gnulib added at 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 Free Software Foundation, Inc.
|
||||
# Copyright 2005-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -18,15 +18,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/>.
|
||||
|
||||
acl
|
||||
alloca
|
||||
areadlinkat-with-size
|
||||
argmatch
|
||||
argp
|
||||
argp-version-etc
|
||||
attribute
|
||||
backupfile
|
||||
closeout
|
||||
configmake
|
||||
dirname
|
||||
dup2
|
||||
error
|
||||
exclude
|
||||
extern-inline
|
||||
@@ -37,9 +39,12 @@ fchownat
|
||||
fcntl-h
|
||||
fdopendir
|
||||
fdutimensat
|
||||
file-has-acl
|
||||
fileblocks
|
||||
flexmember
|
||||
fnmatch-gnu
|
||||
fprintftime
|
||||
free-posix
|
||||
fseeko
|
||||
fstatat
|
||||
full-write
|
||||
@@ -47,11 +52,12 @@ futimens
|
||||
getline
|
||||
getopt-gnu
|
||||
getpagesize
|
||||
gettext
|
||||
gettext-h
|
||||
gettime
|
||||
gitlog-to-changelog
|
||||
hash
|
||||
human
|
||||
idx
|
||||
inttostr
|
||||
inttypes
|
||||
lchown
|
||||
@@ -65,8 +71,6 @@ modechange
|
||||
obstack
|
||||
openat
|
||||
parse-datetime
|
||||
posix_openpt
|
||||
ptsname
|
||||
priv-set
|
||||
progname
|
||||
quote
|
||||
@@ -75,7 +79,7 @@ readlinkat
|
||||
renameat
|
||||
root-uid
|
||||
rpmatch
|
||||
safe-read
|
||||
full-read
|
||||
savedir
|
||||
selinux-at
|
||||
setenv
|
||||
@@ -84,18 +88,20 @@ stat-time
|
||||
stdbool
|
||||
stdint
|
||||
stpcpy
|
||||
stdopen
|
||||
strdup-posix
|
||||
strerror
|
||||
strnlen
|
||||
strtoimax
|
||||
strtol
|
||||
strtoul
|
||||
strtoumax
|
||||
symlinkat
|
||||
timespec
|
||||
timespec-sub
|
||||
unlinkat
|
||||
unlinkdir
|
||||
unlocked-io
|
||||
unlockpt
|
||||
utimensat
|
||||
version-etc-fsf
|
||||
xalloc
|
||||
@@ -103,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 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\
|
||||
@@ -41,10 +39,8 @@ noinst_HEADERS = \
|
||||
|
||||
libtar_a_SOURCES = \
|
||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||
prepargs.c prepargs.h \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h \
|
||||
wordsplit.c\
|
||||
xattr-at.c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Replacement <attr/xattr.h> for platforms that lack it.
|
||||
Copyright 2012-2014 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,83 +0,0 @@
|
||||
/* Parse arguments from a string and prepend them to an argv.
|
||||
Copyright 1999-2001, 2007, 2013-2014 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 <eggert@twinsun.com>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include "prepargs.h"
|
||||
#include <sys/types.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* Find the white-space-separated options specified by OPTIONS, and
|
||||
using BUF to store copies of these options, set ARGV[0], ARGV[1],
|
||||
etc. to the option copies. Return the number N of options found.
|
||||
Do not set ARGV[N]. If ARGV is null, do not store ARGV[0]
|
||||
etc. Backslash can be used to escape whitespace (and backslashes). */
|
||||
static int
|
||||
prepend_args (char const *options, char *buf, char **argv)
|
||||
{
|
||||
char const *o = options;
|
||||
char *b = buf;
|
||||
int n = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (isspace ((unsigned char) *o))
|
||||
o++;
|
||||
if (!*o)
|
||||
return n;
|
||||
if (argv)
|
||||
argv[n] = b;
|
||||
n++;
|
||||
|
||||
do
|
||||
if ((*b++ = *o++) == '\\' && *o)
|
||||
b[-1] = *o++;
|
||||
while (*o && ! isspace ((unsigned char) *o));
|
||||
|
||||
*b++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepend the whitespace-separated options in OPTIONS to the argument
|
||||
vector of a main program with argument count *PARGC and argument
|
||||
vector *PARGV. */
|
||||
void
|
||||
prepend_default_options (char const *options, int *pargc, char ***pargv)
|
||||
{
|
||||
if (options)
|
||||
{
|
||||
char *buf = xmalloc (strlen (options) + 1);
|
||||
int prepended = prepend_args (options, buf, (char **) 0);
|
||||
int argc = *pargc;
|
||||
char * const *argv = *pargv;
|
||||
char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
|
||||
*pargc = prepended + argc;
|
||||
*pargv = pp;
|
||||
*pp++ = *argv++;
|
||||
pp += prepend_args (options, buf, pp);
|
||||
while ((*pp++ = *argv++))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Parse arguments from a string and prepend them to an argv. */
|
||||
|
||||
void prepend_default_options (char const *, int *, char ***);
|
||||
@@ -1,76 +0,0 @@
|
||||
/* stdopen.c - ensure that the three standard file descriptors are in use
|
||||
|
||||
Copyright 2005, 2007, 2013-2014 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
|
||||
1727
lib/wordsplit.c
1727
lib/wordsplit.c
File diff suppressed because it is too large
Load Diff
209
lib/wordsplit.h
209
lib/wordsplit.h
@@ -1,5 +1,5 @@
|
||||
/* wordsplit - a word splitter
|
||||
Copyright (C) 2009-2014 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,52 +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>
|
||||
|
||||
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 *, ...)
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
ATTRIBUTE_FORMAT ((printf, 1, 2));
|
||||
/* [Input] (WRDSF_ERROR) Function used for error
|
||||
reporting */
|
||||
void (*ws_debug) (const char *, ...)
|
||||
__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
|
||||
@@ -65,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 */
|
||||
@@ -79,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 */
|
||||
@@ -107,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 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
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
|
||||
/* setxattrat */
|
||||
#define AT_FUNC_NAME setxattrat
|
||||
#define AT_FUNC_F1 setxattr
|
||||
@@ -108,3 +110,5 @@
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#endif /* HAVE_XATTRS */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Prototypes for openat-style fd-relative functions for operating with
|
||||
extended file attributes.
|
||||
|
||||
Copyright 2012-2014 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);
|
||||
|
||||
|
||||
1
paxutils
Submodule
1
paxutils
Submodule
Submodule paxutils added at 481bae1105
21
po/.gitignore
vendored
21
po/.gitignore
vendored
@@ -1,22 +1,23 @@
|
||||
/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 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright 1996-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Make GNU tar scripts.
|
||||
|
||||
# Copyright 2004, 2006-2007, 2013-2014 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,7 +82,7 @@ SLEEP_MESSAGE="`awk '
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright 2004, 2007, 2013-2014 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,13 +149,16 @@ message 20 "Variables:"
|
||||
message 20 "BACKUP_DIRS=$BACKUP_DIRS"
|
||||
message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
|
||||
# The buch of commands below is run in a subshell for which all output is
|
||||
# The bunch of commands below is run in a subshell for which all output is
|
||||
# piped through 'tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
message 1 "preparing tapes"
|
||||
$MT_BEGIN "${TAPE_FILE}"
|
||||
if ! $MT_BEGIN "${TAPE_FILE}"; then
|
||||
echo >&2 "$0: tape initialization failed"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
@@ -191,7 +194,7 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
# 'rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed." 1>&2
|
||||
echo "$0: backup of ${1} failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
@@ -238,17 +241,17 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
message 1 "final cleanup"
|
||||
|
||||
$MT_REWIND "${TAPE_FILE}"
|
||||
$MT_OFFLINE "${TAPE_FILE}"
|
||||
echo "."
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
RC=$?
|
||||
|
||||
if test "${ADMINISTRATOR}" != NONE; then
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
fi
|
||||
|
||||
exit $RC
|
||||
# EOF
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013-2014 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -311,7 +311,9 @@ backup_host() {
|
||||
CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
|
||||
message 10 "CMD: $CMD"
|
||||
sh -c "$CMD"
|
||||
message 10 "RC: $?"
|
||||
RC=$?
|
||||
message 10 "RC: $RC"
|
||||
return $RC
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +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 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Restore backups.
|
||||
|
||||
# Copyright 2004, 2006, 2013-2014 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -183,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,6 +1,6 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Display and edit the 'dev' field in tar's snapshots
|
||||
# Copyright 2007, 2011, 2013-2014 Free Software Foundation, Inc.
|
||||
# Copyright 2007-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -408,7 +408,7 @@ sub check_field_values ($) {
|
||||
}
|
||||
if ( $msg ne "" ) {
|
||||
$error_found = 1;
|
||||
print "\n shapshot file header:\n";
|
||||
print "\n snapshot file header:\n";
|
||||
print $msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +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 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* xsparse - expands compressed sparse file images extracted from GNU tar
|
||||
archives.
|
||||
|
||||
Copyright 2006-2007, 2010, 2013-2014 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 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1994-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
@@ -33,6 +32,7 @@ tar_SOURCES = \
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
list.c\
|
||||
map.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
sparse.c\
|
||||
@@ -49,10 +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)
|
||||
|
||||
if TAR_LIB_ATTR
|
||||
tar_LDADD += -lattr
|
||||
endif
|
||||
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,5 +1,5 @@
|
||||
/* Long integers, for GNU tar.
|
||||
Copyright 1999, 2007, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 1999-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
285
src/buffer.c
285
src/buffer.c
@@ -1,7 +1,6 @@
|
||||
/* Buffer management for tar.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2013-2014 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
|
||||
|
||||
@@ -105,13 +109,20 @@ bool write_archive_to_stdout;
|
||||
|
||||
/* When creating a multi-volume archive, each 'bufmap' represents
|
||||
a member stored (perhaps partly) in the current record buffer.
|
||||
Bufmaps are form a single-linked list in chronological order.
|
||||
|
||||
After flushing the record to the output media, all bufmaps that
|
||||
represent fully written members are removed from the list, then
|
||||
the sizeleft and start numbers in the remaining bufmaps are updated.
|
||||
represent fully written members are removed from the list, the
|
||||
nblocks and sizeleft values in the bufmap_head and start values
|
||||
in all remaining bufmaps are updated. The information stored
|
||||
in bufmap_head is used to form the volume header.
|
||||
|
||||
When reading from a multi-volume archive, the list degrades to a
|
||||
single element, which keeps information about the member currently
|
||||
being read.
|
||||
being read. In that case the sizeleft member is updated explicitly
|
||||
from the extractor code by calling the mv_size_left function. The
|
||||
information from bufmap_head is compared with the volume header data
|
||||
to ensure that subsequent volumes are fed in the right order.
|
||||
*/
|
||||
|
||||
struct bufmap
|
||||
@@ -121,6 +132,7 @@ struct bufmap
|
||||
char *file_name; /* Name of the stored file */
|
||||
off_t sizetotal; /* Size of the stored file */
|
||||
off_t sizeleft; /* Size left to read/write */
|
||||
size_t nblocks; /* Number of blocks written since reset */
|
||||
};
|
||||
static struct bufmap *bufmap_head, *bufmap_tail;
|
||||
|
||||
@@ -145,6 +157,7 @@ mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft)
|
||||
bp->file_name = xstrdup (file_name);
|
||||
bp->sizetotal = totsize;
|
||||
bp->sizeleft = sizeleft;
|
||||
bp->nblocks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +168,7 @@ bufmap_locate (size_t off)
|
||||
|
||||
for (map = bufmap_head; map; map = map->next)
|
||||
{
|
||||
if (!map->next
|
||||
|| off < map->next->start * BLOCKSIZE)
|
||||
if (!map->next || off < map->next->start * BLOCKSIZE)
|
||||
break;
|
||||
}
|
||||
return map;
|
||||
@@ -185,7 +197,10 @@ bufmap_reset (struct bufmap *map, ssize_t fixup)
|
||||
if (map)
|
||||
{
|
||||
for (; map; map = map->next)
|
||||
map->start += fixup;
|
||||
{
|
||||
map->start += fixup;
|
||||
map->nblocks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +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;
|
||||
@@ -297,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]))
|
||||
@@ -314,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)
|
||||
{
|
||||
@@ -339,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;
|
||||
|
||||
@@ -355,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;
|
||||
}
|
||||
@@ -391,7 +410,12 @@ check_compressed_archive (bool *pshort)
|
||||
/* Restore global values */
|
||||
read_full_records = sfr;
|
||||
|
||||
if (tar_checksum (record_start, true) == HEADER_SUCCESS)
|
||||
if (record_start != record_end /* no files smaller than BLOCKSIZE */
|
||||
&& (strcmp (record_start->header.magic, TMAGIC) == 0
|
||||
|| strcmp (record_start->buffer + offsetof (struct posix_header,
|
||||
magic),
|
||||
OLDGNU_MAGIC) == 0)
|
||||
&& tar_checksum (record_start, true) == HEADER_SUCCESS)
|
||||
/* Probably a valid header */
|
||||
return ct_tar;
|
||||
|
||||
@@ -402,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 */
|
||||
@@ -495,7 +488,7 @@ print_stats (FILE *fp, const char *text, tarlong numbytes)
|
||||
char abbr[LONGEST_HUMAN_READABLE + 1];
|
||||
char rate[LONGEST_HUMAN_READABLE + 1];
|
||||
int n = 0;
|
||||
|
||||
|
||||
int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
|
||||
|
||||
if (text && text[0])
|
||||
@@ -512,12 +505,12 @@ print_stats (FILE *fp, const char *text, tarlong numbytes)
|
||||
before each data item (bytes read, written, deleted, in that order).
|
||||
EOR is a delimiter to output after each item (used only if deleting
|
||||
from the archive), EOL is a delimiter to add at the end of the output
|
||||
line. */
|
||||
line. */
|
||||
int
|
||||
format_total_stats (FILE *fp, const char **formats, int eor, int eol)
|
||||
format_total_stats (FILE *fp, char const *const *formats, int eor, int eol)
|
||||
{
|
||||
int n;
|
||||
|
||||
|
||||
switch (subcommand_option)
|
||||
{
|
||||
case CREATE_SUBCOMMAND:
|
||||
@@ -536,7 +529,7 @@ format_total_stats (FILE *fp, const char **formats, int eor, int eol)
|
||||
|
||||
fputc (eor, fp);
|
||||
n++;
|
||||
|
||||
|
||||
n += print_stats (fp, formats[TF_WRITE],
|
||||
prev_written + bytes_written);
|
||||
|
||||
@@ -570,7 +563,7 @@ format_total_stats (FILE *fp, const char **formats, int eor, int eol)
|
||||
return n;
|
||||
}
|
||||
|
||||
const char *default_total_format[] = {
|
||||
static char const *const default_total_format[] = {
|
||||
N_("Total bytes read"),
|
||||
/* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
|
||||
N_("Total bytes written"),
|
||||
@@ -684,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")));
|
||||
@@ -778,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,
|
||||
@@ -814,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)
|
||||
{
|
||||
@@ -865,12 +872,19 @@ _flush_write (void)
|
||||
if (map)
|
||||
{
|
||||
size_t delta = status - map->start * BLOCKSIZE;
|
||||
ssize_t diff;
|
||||
map->nblocks += delta / BLOCKSIZE;
|
||||
if (delta > map->sizeleft)
|
||||
delta = map->sizeleft;
|
||||
map->sizeleft -= delta;
|
||||
if (map->sizeleft == 0)
|
||||
map = map->next;
|
||||
bufmap_reset (map, map ? (- map->start) : 0);
|
||||
{
|
||||
diff = map->start + map->nblocks;
|
||||
map = map->next;
|
||||
}
|
||||
else
|
||||
diff = map->start;
|
||||
bufmap_reset (map, - diff);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
@@ -973,25 +987,36 @@ 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. */
|
||||
void
|
||||
flush_archive (void)
|
||||
{
|
||||
size_t buffer_level = current_block->buffer - record_start->buffer;
|
||||
record_start_block += record_end - record_start;
|
||||
current_block = record_start;
|
||||
record_end = record_start + blocking_factor;
|
||||
size_t buffer_level;
|
||||
|
||||
if (access_mode == ACCESS_READ && time_to_start_writing)
|
||||
{
|
||||
access_mode = ACCESS_WRITE;
|
||||
time_to_start_writing = false;
|
||||
backspace_output ();
|
||||
if (record_end - record_start < blocking_factor)
|
||||
{
|
||||
memset (record_end, 0,
|
||||
(blocking_factor - (record_end - record_start))
|
||||
* BLOCKSIZE);
|
||||
record_end = record_start + blocking_factor;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_level = current_block->buffer - record_start->buffer;
|
||||
record_start_block += record_end - record_start;
|
||||
current_block = record_start;
|
||||
record_end = record_start + blocking_factor;
|
||||
|
||||
switch (access_mode)
|
||||
{
|
||||
case ACCESS_READ:
|
||||
@@ -1013,25 +1038,15 @@ 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);
|
||||
|
||||
/* Seek back to the beginning of this record and start writing there. */
|
||||
|
||||
position -= record_size;
|
||||
position -= record_end->buffer - record_start->buffer;
|
||||
if (position < 0)
|
||||
position = 0;
|
||||
if (rmtlseek (archive, position, SEEK_SET) != position)
|
||||
@@ -1092,9 +1107,9 @@ close_archive (void)
|
||||
{
|
||||
if (time_to_start_writing || access_mode == ACCESS_WRITE)
|
||||
{
|
||||
flush_archive ();
|
||||
if (current_block > record_start)
|
||||
flush_archive ();
|
||||
do
|
||||
flush_archive ();
|
||||
while (current_block > record_start);
|
||||
}
|
||||
|
||||
compute_duration ();
|
||||
@@ -1112,6 +1127,16 @@ close_archive (void)
|
||||
bufmap_free (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
write_fatal_details (char const *name, ssize_t status, size_t size)
|
||||
{
|
||||
write_error_details (name, status, size);
|
||||
if (rmtclose (archive) != 0)
|
||||
close_error (*archive_name_cursor);
|
||||
sys_wait_for_child (child_pid, false);
|
||||
fatal_exit ();
|
||||
}
|
||||
|
||||
/* Called to initialize the global volume number. */
|
||||
void
|
||||
init_volume_number (void)
|
||||
@@ -1253,8 +1278,7 @@ change_tape_menu (FILE *read_file)
|
||||
sys_spawn_shell ();
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
fprintf (stderr, _("Invalid input. Type ? for help.\n"));
|
||||
}
|
||||
@@ -1281,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;
|
||||
|
||||
@@ -1328,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:
|
||||
@@ -1353,7 +1376,7 @@ new_volume (enum access_mode mode)
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
SET_BINARY_MODE (archive);
|
||||
get_archive_status (mode, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1406,7 +1429,10 @@ try_new_volume (void)
|
||||
|
||||
header = find_next_block ();
|
||||
if (!header)
|
||||
return false;
|
||||
{
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (header->header.typeflag)
|
||||
{
|
||||
@@ -1416,7 +1442,7 @@ try_new_volume (void)
|
||||
if (read_header (&header, &dummy, read_header_x_global)
|
||||
!= HEADER_SUCCESS_EXTENDED)
|
||||
{
|
||||
ERROR ((0, 0, _("This does not look like a tar archive")));
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1445,7 +1471,7 @@ try_new_volume (void)
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR ((0, 0, _("This does not look like a tar archive")));
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -1455,18 +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;
|
||||
/* FALL THROUGH */
|
||||
|
||||
FALLTHROUGH;
|
||||
case GNUTYPE_MULTIVOL:
|
||||
if (!read_header0 (&dummy))
|
||||
return false;
|
||||
tar_stat_destroy (&dummy);
|
||||
assign_string (&continued_file_name, current_header->header.name);
|
||||
ASSIGN_STRING_N (&continued_file_name, current_header->header.name);
|
||||
continued_file_size =
|
||||
UINTMAX_FROM_HEADER (current_header->header.size);
|
||||
continued_file_offset =
|
||||
@@ -1480,8 +1505,14 @@ try_new_volume (void)
|
||||
if (bufmap_head)
|
||||
{
|
||||
uintmax_t s;
|
||||
if (!continued_file_name
|
||||
|| strcmp (continued_file_name, bufmap_head->file_name))
|
||||
if (!continued_file_name)
|
||||
{
|
||||
WARN ((0, 0, _("%s is not continued on this volume"),
|
||||
quote (bufmap_head->file_name)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp (continued_file_name, bufmap_head->file_name))
|
||||
{
|
||||
if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)
|
||||
&& strlen (bufmap_head->file_name) >= NAME_FIELD_SIZE
|
||||
@@ -1603,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)
|
||||
{
|
||||
@@ -1644,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);
|
||||
|
||||
@@ -1679,7 +1702,6 @@ add_chunk_header (struct bufmap *map)
|
||||
{
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
off_t block_ordinal;
|
||||
union block *blk;
|
||||
struct tar_stat_info st;
|
||||
|
||||
@@ -1689,16 +1711,15 @@ add_chunk_header (struct bufmap *map)
|
||||
st.stat.st_uid = getuid ();
|
||||
st.stat.st_gid = getgid ();
|
||||
st.orig_file_name = xheader_format_name (&st,
|
||||
"%d/GNUFileParts.%p/%f.%n",
|
||||
"%d/GNUFileParts/%f.%n",
|
||||
volno);
|
||||
st.file_name = st.orig_file_name;
|
||||
st.archive_file_size = st.stat.st_size = map->sizeleft;
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
blk = start_header (&st);
|
||||
if (!blk)
|
||||
abort (); /* FIXME */
|
||||
finish_header (&st, blk, block_ordinal);
|
||||
simple_finish_header (write_extended (false, &st, blk));
|
||||
free (st.orig_file_name);
|
||||
}
|
||||
}
|
||||
@@ -1720,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);
|
||||
@@ -1803,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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
201
src/common.h
201
src/common.h
@@ -1,7 +1,6 @@
|
||||
/* Common declarations for the tar program.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2012-2014 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -50,12 +49,16 @@
|
||||
|
||||
|
||||
#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
|
||||
@@ -211,13 +214,20 @@ GLOBAL bool multi_volume_option;
|
||||
do not get archived (also see after_date_option above). */
|
||||
GLOBAL struct timespec newer_mtime_option;
|
||||
|
||||
/* If true, override actual mtime (see below) */
|
||||
GLOBAL bool set_mtime_option;
|
||||
/* Value to be put in mtime header field instead of the actual mtime */
|
||||
enum set_mtime_option_mode
|
||||
{
|
||||
USE_FILE_MTIME,
|
||||
FORCE_MTIME,
|
||||
CLAMP_MTIME,
|
||||
};
|
||||
|
||||
/* Override actual mtime if set to FORCE_MTIME or CLAMP_MTIME */
|
||||
GLOBAL enum set_mtime_option_mode set_mtime_option;
|
||||
/* Value to use when forcing or clamping the mtime header field. */
|
||||
GLOBAL struct timespec mtime_option;
|
||||
|
||||
/* Return true if newer_mtime_option is initialized. */
|
||||
#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
|
||||
/* Return true if mtime_option or newer_mtime_option is initialized. */
|
||||
#define TIME_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
|
||||
|
||||
/* Return true if the struct stat ST's M time is less than
|
||||
newer_mtime_option. */
|
||||
@@ -280,6 +290,19 @@ GLOBAL bool sparse_option;
|
||||
GLOBAL unsigned tar_sparse_major;
|
||||
GLOBAL unsigned tar_sparse_minor;
|
||||
|
||||
enum hole_detection_method
|
||||
{
|
||||
HOLE_DETECTION_DEFAULT,
|
||||
HOLE_DETECTION_RAW,
|
||||
HOLE_DETECTION_SEEK
|
||||
};
|
||||
|
||||
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). */
|
||||
@@ -315,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;
|
||||
|
||||
@@ -351,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 */
|
||||
|
||||
@@ -369,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;
|
||||
@@ -379,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;
|
||||
@@ -398,10 +427,6 @@ GLOBAL bool show_transformed_names_option;
|
||||
timestamps from archives with an unusual member order. It is automatically
|
||||
set for incremental archives. */
|
||||
GLOBAL bool delay_directory_restore_option;
|
||||
|
||||
/* Warn about implicit use of the wildcards in command line arguments.
|
||||
(Default for tar prior to 1.15.91, but changed afterwards */
|
||||
GLOBAL bool warn_regex_usage;
|
||||
|
||||
/* Declarations for each module. */
|
||||
|
||||
@@ -445,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);
|
||||
@@ -453,7 +478,7 @@ void set_start_time (void);
|
||||
#define TF_READ 0
|
||||
#define TF_WRITE 1
|
||||
#define TF_DELETED 2
|
||||
int format_total_stats (FILE *fp, const char **formats, int eor, int eol);
|
||||
int format_total_stats (FILE *fp, char const *const *formats, int eor, int eol);
|
||||
void print_total_stats (void);
|
||||
|
||||
void mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft);
|
||||
@@ -480,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);
|
||||
@@ -523,6 +549,8 @@ void extract_archive (void);
|
||||
void extract_finish (void);
|
||||
bool rename_directory (char *src, char *dst);
|
||||
|
||||
void remove_delayed_set_stat (const char *fname);
|
||||
|
||||
/* Module delete.c. */
|
||||
|
||||
void delete_archive_members (void);
|
||||
@@ -590,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));
|
||||
@@ -598,14 +626,22 @@ 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. */
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
void assign_string (char **dest, const char *src);
|
||||
|
||||
char const *quote_n_colon (int n, char const *arg);
|
||||
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);
|
||||
@@ -618,8 +654,6 @@ typedef struct namebuf *namebuf_t;
|
||||
namebuf_t namebuf_create (const char *dir);
|
||||
void namebuf_free (namebuf_t buf);
|
||||
char *namebuf_name (namebuf_t buf, const char *name);
|
||||
void namebuf_add_dir (namebuf_t buf, const char *name);
|
||||
char *namebuf_finish (namebuf_t buf);
|
||||
|
||||
const char *tar_dirname (void);
|
||||
|
||||
@@ -642,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. */
|
||||
@@ -701,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]);
|
||||
@@ -714,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);
|
||||
@@ -723,23 +773,22 @@ void uid_to_uname (uid_t uid, char **uname);
|
||||
int uname_to_uid (char const *uname, uid_t *puid);
|
||||
|
||||
void name_init (void);
|
||||
void name_add_name (const char *name, int matching_flags);
|
||||
void name_add_dir (const char *name);
|
||||
void name_add_file (const char *name, int term);
|
||||
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 *new_name (const char *dir_name, const char *name);
|
||||
char *make_file_name (const char *dir_name, const char *name);
|
||||
size_t stripped_prefix_len (char const *file_name, size_t num);
|
||||
bool all_names_found (struct tar_stat_info *st);
|
||||
|
||||
@@ -748,28 +797,69 @@ bool is_avoided_name (char const *name);
|
||||
|
||||
bool contains_dot_dot (char const *name);
|
||||
|
||||
#define ISFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
(c)->found_count == occurrence_option)
|
||||
#define WASFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
(c)->found_count >= occurrence_option)
|
||||
#define ISFOUND(c) (occurrence_option == 0 \
|
||||
? (c)->found_count != 0 \
|
||||
: (c)->found_count == occurrence_option)
|
||||
#define WASFOUND(c) (occurrence_option == 0 \
|
||||
? (c)->found_count != 0 \
|
||||
: (c)->found_count >= occurrence_option)
|
||||
|
||||
/* 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);
|
||||
void set_exit_status (int val);
|
||||
|
||||
void request_stdin (const char *option);
|
||||
void more_options (int argc, char **argv);
|
||||
|
||||
int decode_signal (const char *);
|
||||
|
||||
/* Where an option comes from: */
|
||||
enum option_source
|
||||
{
|
||||
OPTS_ENVIRON, /* Environment variable TAR_OPTIONS */
|
||||
OPTS_COMMAND_LINE, /* Command line */
|
||||
OPTS_FILE /* File supplied by --files-from */
|
||||
};
|
||||
|
||||
/* Option location */
|
||||
struct option_locus
|
||||
{
|
||||
enum option_source source; /* Option origin */
|
||||
char const *name; /* File or variable name */
|
||||
size_t line; /* Number of input line if source is OPTS_FILE */
|
||||
struct option_locus *prev; /* Previous occurrence of the option of same
|
||||
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. */
|
||||
|
||||
@@ -789,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);
|
||||
@@ -801,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);
|
||||
@@ -828,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);
|
||||
@@ -839,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 */
|
||||
@@ -893,21 +988,25 @@ void checkpoint_flush_actions (void);
|
||||
#define WARN_EXISTING_FILE 0x00100000
|
||||
#define WARN_XATTR_WRITE 0x00200000
|
||||
#define WARN_RECORD_SIZE 0x00400000
|
||||
#define WARN_FAILED_READ 0x00800000
|
||||
#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);
|
||||
|
||||
extern int warning_option;
|
||||
|
||||
#define WARNING_ENABLED(opt) (warning_option & (opt))
|
||||
|
||||
#define WARNOPT(opt,args) \
|
||||
do \
|
||||
{ \
|
||||
if (warning_option & opt) WARN (args); \
|
||||
if (WARNING_ENABLED(opt)) WARN (args); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
@@ -926,9 +1025,15 @@ extern void (*fatal_exit_hook) (void);
|
||||
|
||||
void excfile_add (const char *name, int flags);
|
||||
void info_attach_exclist (struct tar_stat_info *dir);
|
||||
void info_cleanup_exclist (struct tar_stat_info *dir);
|
||||
void info_free_exclist (struct tar_stat_info *dir);
|
||||
bool excluded_name (char const *name, struct tar_stat_info *st);
|
||||
void exclude_vcs_ignores (void);
|
||||
|
||||
/* Module map.c */
|
||||
void owner_map_read (char const *name);
|
||||
int owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name);
|
||||
void group_map_read (char const *file);
|
||||
int group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name);
|
||||
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* Diff files from a tar archive.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2007,
|
||||
2009-2010, 2012-2014 Free Software Foundation, Inc.
|
||||
Copyright 1988-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -51,6 +50,8 @@ diff_init (void)
|
||||
read_directory_file ();
|
||||
}
|
||||
|
||||
enum { QUOTE_ARG, QUOTE_NAME };
|
||||
|
||||
/* Sigh about something that differs by writing a MESSAGE to stdlis,
|
||||
given MESSAGE is nonzero. Also set the exit status if not already. */
|
||||
void
|
||||
@@ -60,7 +61,7 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stdlis, "%s: ", quotearg_colon (st->file_name));
|
||||
fprintf (stdlis, "%s: ", quote_n_colon (QUOTE_NAME, st->file_name));
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stdlis, fmt, ap);
|
||||
va_end (ap);
|
||||
@@ -72,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;
|
||||
}
|
||||
@@ -263,18 +263,20 @@ diff_link (void)
|
||||
&& !sys_compare_links (&file_data, &link_data))
|
||||
report_difference (¤t_stat_info,
|
||||
_("Not linked to %s"),
|
||||
quote (current_stat_info.link_name));
|
||||
quote_n_colon (QUOTE_ARG,
|
||||
current_stat_info.link_name));
|
||||
}
|
||||
|
||||
#ifdef HAVE_READLINK
|
||||
static void
|
||||
diff_symlink (void)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t len = strlen (current_stat_info.link_name);
|
||||
char *linkbuf = alloca (len + 1);
|
||||
char *linkbuf = len < sizeof buf ? buf : xmalloc (len + 1);
|
||||
|
||||
int status = readlinkat (chdir_fd, current_stat_info.file_name,
|
||||
linkbuf, len + 1);
|
||||
ssize_t status = readlinkat (chdir_fd, current_stat_info.file_name,
|
||||
linkbuf, len + 1);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
@@ -285,8 +287,11 @@ diff_symlink (void)
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
}
|
||||
else if (status != len
|
||||
|| strncmp (current_stat_info.link_name, linkbuf, len) != 0)
|
||||
|| memcmp (current_stat_info.link_name, linkbuf, len) != 0)
|
||||
report_difference (¤t_stat_info, _("Symlink differs"));
|
||||
|
||||
if (linkbuf != buf)
|
||||
free (linkbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -473,8 +478,7 @@ diff_archive (void)
|
||||
ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
|
||||
quotearg_colon (current_stat_info.file_name),
|
||||
current_header->header.typeflag));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case AREGTYPE:
|
||||
case REGTYPE:
|
||||
case GNUTYPE_SPARSE:
|
||||
@@ -561,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;
|
||||
|
||||
267
src/create.c
267
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 Free Software Foundation, Inc.
|
||||
Copyright 1985-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -22,6 +21,8 @@
|
||||
|
||||
#include <system.h>
|
||||
|
||||
#include <areadlink.h>
|
||||
#include <flexmember.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -36,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
|
||||
@@ -174,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 =
|
||||
@@ -201,17 +202,17 @@ to_base256 (int negative, uintmax_t value, char *where, size_t size)
|
||||
#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
|
||||
#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
|
||||
|
||||
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
#define UNAME_TO_CHARS(name, buf) string_to_chars (name, buf, sizeof (buf))
|
||||
#define GNAME_TO_CHARS(name, buf) string_to_chars (name, buf, sizeof (buf))
|
||||
|
||||
static bool
|
||||
to_chars (int negative, uintmax_t value, size_t valsize,
|
||||
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
|
||||
@@ -245,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:
|
||||
@@ -272,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))
|
||||
@@ -308,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;
|
||||
}
|
||||
@@ -321,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';
|
||||
@@ -342,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
|
||||
@@ -383,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
|
||||
@@ -398,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)
|
||||
@@ -428,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
|
||||
@@ -452,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
|
||||
@@ -517,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;
|
||||
}
|
||||
|
||||
@@ -541,15 +542,19 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
size_t size = strlen (p) + 1;
|
||||
size_t bufsize;
|
||||
union block *header;
|
||||
char *tmpname;
|
||||
|
||||
header = start_private_header ("././@LongLink", size, 0);
|
||||
uid_to_uname (0, &tmpname);
|
||||
UNAME_TO_CHARS (tmpname, header->header.uname);
|
||||
free (tmpname);
|
||||
gid_to_gname (0, &tmpname);
|
||||
GNAME_TO_CHARS (tmpname, header->header.gname);
|
||||
free (tmpname);
|
||||
if (! numeric_owner_option)
|
||||
{
|
||||
static char *uname, *gname;
|
||||
if (!uname)
|
||||
{
|
||||
uid_to_uname (0, &uname);
|
||||
gid_to_gname (0, &gname);
|
||||
}
|
||||
UNAME_TO_CHARS (uname, header->header.uname);
|
||||
GNAME_TO_CHARS (gname, header->header.gname);
|
||||
}
|
||||
|
||||
strcpy (header->buffer + offsetof (struct posix_header, magic),
|
||||
OLDGNU_MAGIC);
|
||||
@@ -706,7 +711,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header)
|
||||
{
|
||||
type = XHDTYPE;
|
||||
p = xheader_xhdr_name (st);
|
||||
t = st->stat.st_mtime;
|
||||
t = set_mtime_option ? mtime_option.tv_sec : st->stat.st_mtime;
|
||||
}
|
||||
xheader_write (type, p, t, &st->xhdr);
|
||||
free (p);
|
||||
@@ -740,17 +745,17 @@ union block *
|
||||
start_header (struct tar_stat_info *st)
|
||||
{
|
||||
union block *header;
|
||||
char const *uname = NULL;
|
||||
char const *gname = NULL;
|
||||
|
||||
header = write_header_name (st);
|
||||
if (!header)
|
||||
return NULL;
|
||||
|
||||
/* Override some stat fields, if requested to do so. */
|
||||
owner_map_translate (st->stat.st_uid, &st->stat.st_uid, &uname);
|
||||
group_map_translate (st->stat.st_gid, &st->stat.st_gid, &gname);
|
||||
|
||||
if (owner_option != (uid_t) -1)
|
||||
st->stat.st_uid = owner_option;
|
||||
if (group_option != (gid_t) -1)
|
||||
st->stat.st_gid = group_option;
|
||||
if (mode_option)
|
||||
st->stat.st_mode =
|
||||
((st->stat.st_mode & ~MODE_ALL)
|
||||
@@ -822,7 +827,24 @@ start_header (struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
{
|
||||
struct timespec mtime = set_mtime_option ? mtime_option : st->mtime;
|
||||
struct timespec mtime;
|
||||
|
||||
switch (set_mtime_option)
|
||||
{
|
||||
case USE_FILE_MTIME:
|
||||
mtime = st->mtime;
|
||||
break;
|
||||
|
||||
case FORCE_MTIME:
|
||||
mtime = mtime_option;
|
||||
break;
|
||||
|
||||
case CLAMP_MTIME:
|
||||
mtime = timespec_cmp (st->mtime, mtime_option) > 0
|
||||
? mtime_option : st->mtime;
|
||||
break;
|
||||
}
|
||||
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
|
||||
@@ -860,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)
|
||||
{
|
||||
@@ -895,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:
|
||||
@@ -909,13 +925,13 @@ start_header (struct tar_stat_info *st)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (owner_name_option)
|
||||
st->uname = xstrdup (owner_name_option);
|
||||
if (uname)
|
||||
st->uname = xstrdup (uname);
|
||||
else
|
||||
uid_to_uname (st->stat.st_uid, &st->uname);
|
||||
|
||||
if (group_name_option)
|
||||
st->gname = xstrdup (group_name_option);
|
||||
if (gname)
|
||||
st->gname = xstrdup (gname);
|
||||
else
|
||||
gid_to_gname (st->stat.st_gid, &st->gname);
|
||||
|
||||
@@ -945,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1114,7 +1125,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
|
||||
return;
|
||||
|
||||
info_attach_exclist (st);
|
||||
|
||||
|
||||
if (incremental_option && archive_format != POSIX_FORMAT)
|
||||
blk->header.typeflag = GNUTYPE_DUMPDIR;
|
||||
else /* if (standard_option) */
|
||||
@@ -1198,7 +1209,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
|
||||
char const *entry;
|
||||
size_t entry_len;
|
||||
size_t name_len;
|
||||
|
||||
|
||||
name_buf = xstrdup (st->orig_file_name);
|
||||
name_size = name_len = strlen (name_buf);
|
||||
|
||||
@@ -1327,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 ();
|
||||
@@ -1350,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;
|
||||
@@ -1373,23 +1380,21 @@ create_archive (void)
|
||||
open_searchdir_flags);
|
||||
if (fd < 0)
|
||||
{
|
||||
open_diag (p->name);
|
||||
file_removed_diag (p->name, !p->parent,
|
||||
open_diag);
|
||||
break;
|
||||
}
|
||||
st.fd = fd;
|
||||
if (fstat (fd, &st.stat) != 0)
|
||||
{
|
||||
stat_diag (p->name);
|
||||
file_removed_diag (p->name, !p->parent,
|
||||
stat_diag);
|
||||
break;
|
||||
}
|
||||
st.orig_file_name = xstrdup (p->name);
|
||||
}
|
||||
if (buffer_size < plen + qlen)
|
||||
{
|
||||
while ((buffer_size *=2 ) < plen + qlen)
|
||||
continue;
|
||||
buffer = xrealloc (buffer, buffer_size);
|
||||
}
|
||||
while (buffer_size < plen + qlen)
|
||||
buffer = x2realloc (buffer, &buffer_size);
|
||||
strcpy (buffer + plen, q + 1);
|
||||
dump_file (&st, q + 1, buffer);
|
||||
}
|
||||
@@ -1472,8 +1477,8 @@ dump_hard_link (struct tar_stat_info *st)
|
||||
/* We found a link. */
|
||||
char const *link_name = safer_name_suffix (duplicate->name, true,
|
||||
absolute_names_option);
|
||||
|
||||
duplicate->nlink--;
|
||||
if (duplicate->nlink)
|
||||
duplicate->nlink--;
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
assign_string (&st->link_name, link_name);
|
||||
@@ -1510,11 +1515,11 @@ file_count_links (struct tar_stat_info *st)
|
||||
char *linkname = NULL;
|
||||
struct link *lp;
|
||||
|
||||
assign_string (&linkname, st->orig_file_name);
|
||||
assign_string (&linkname, safer_name_suffix (st->orig_file_name, true,
|
||||
absolute_names_option));
|
||||
transform_name (&linkname, XFORM_LINK);
|
||||
|
||||
lp = xmalloc (offsetof (struct link, name)
|
||||
+ 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;
|
||||
@@ -1634,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;
|
||||
@@ -1678,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))
|
||||
@@ -1718,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;
|
||||
}
|
||||
@@ -1731,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);
|
||||
|
||||
@@ -1799,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);
|
||||
}
|
||||
@@ -1837,22 +1864,17 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
#ifdef HAVE_READLINK
|
||||
else if (S_ISLNK (st->stat.st_mode))
|
||||
{
|
||||
char *buffer;
|
||||
int size;
|
||||
size_t linklen = st->stat.st_size;
|
||||
if (linklen != st->stat.st_size || linklen + 1 == 0)
|
||||
xalloc_die ();
|
||||
buffer = (char *) alloca (linklen + 1);
|
||||
size = readlinkat (parentfd, name, buffer, linklen + 1);
|
||||
if (size < 0)
|
||||
st->link_name = areadlinkat_with_size (parentfd, name, st->stat.st_size);
|
||||
if (!st->link_name)
|
||||
{
|
||||
if (errno == ENOMEM)
|
||||
xalloc_die ();
|
||||
file_removed_diag (p, top_level, readlink_diag);
|
||||
return;
|
||||
}
|
||||
buffer[size] = '\0';
|
||||
assign_string (&st->link_name, buffer);
|
||||
transform_name (&st->link_name, XFORM_SYMLINK);
|
||||
if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
|
||||
if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT)
|
||||
< strlen (st->link_name))
|
||||
write_long_link (st);
|
||||
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
@@ -1878,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);
|
||||
}
|
||||
@@ -1926,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);
|
||||
|
||||
287
src/delete.c
287
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 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,19 +184,18 @@ 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;
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
logical_status = status;
|
||||
break;
|
||||
@@ -199,7 +206,7 @@ delete_archive_members (void)
|
||||
set_next_block_after (current_header);
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_END_OF_FILE:
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
@@ -210,14 +217,12 @@ delete_archive_members (void)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_FAILURE:
|
||||
break;
|
||||
|
||||
@@ -247,15 +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;
|
||||
|
||||
@@ -263,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 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,15 +41,16 @@ struct excfile
|
||||
{
|
||||
struct excfile *next;
|
||||
int flags;
|
||||
char name[1];
|
||||
char name[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
struct excfile *excfile_head, *excfile_tail;
|
||||
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);
|
||||
@@ -72,7 +74,7 @@ info_attach_exclist (struct tar_stat_info *dir)
|
||||
struct excfile *file;
|
||||
struct exclist *head = NULL, *tail = NULL, *ent;
|
||||
struct vcs_ignore_file *vcsfile;
|
||||
|
||||
|
||||
if (dir->exclude_list)
|
||||
return;
|
||||
for (file = excfile_head; file; file = file->next)
|
||||
@@ -102,16 +104,17 @@ info_attach_exclist (struct tar_stat_info *dir)
|
||||
|
||||
if (vcsfile->initfn)
|
||||
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;
|
||||
FATAL_ERROR ((0, e, "%s", quotearg_colon (file->name)));
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
|
||||
ent = xmalloc (sizeof (*ent));
|
||||
ent->excluded = ex;
|
||||
ent->flags = file->flags == EXCL_DEFAULT
|
||||
@@ -129,34 +132,6 @@ info_attach_exclist (struct tar_stat_info *dir)
|
||||
dir->exclude_list = head;
|
||||
}
|
||||
|
||||
void
|
||||
info_cleanup_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
struct exclist *ep = dir->exclude_list;
|
||||
|
||||
while (ep)
|
||||
{
|
||||
struct exclist *next = ep->next;
|
||||
|
||||
if (ep->flags & EXCL_NON_RECURSIVE)
|
||||
{
|
||||
|
||||
/* Remove the entry */
|
||||
if (ep->prev)
|
||||
ep->prev->next = ep->next;
|
||||
else
|
||||
dir->exclude_list = ep->next;
|
||||
|
||||
if (ep->next)
|
||||
ep->next->prev = ep->prev;
|
||||
|
||||
free_exclude (ep->excluded);
|
||||
free (ep);
|
||||
}
|
||||
ep = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
info_free_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
@@ -172,7 +147,7 @@ info_free_exclist (struct tar_stat_info *dir)
|
||||
|
||||
dir->exclude_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return nonzero if file NAME is excluded. */
|
||||
bool
|
||||
@@ -183,7 +158,7 @@ excluded_name (char const *name, struct tar_stat_info *st)
|
||||
char *bname = NULL;
|
||||
bool result;
|
||||
int nr = 0;
|
||||
|
||||
|
||||
name += FILE_SYSTEM_PREFIX_LEN (name);
|
||||
|
||||
/* Try global exclusion list first */
|
||||
@@ -192,7 +167,7 @@ excluded_name (char const *name, struct tar_stat_info *st)
|
||||
|
||||
if (!st)
|
||||
return false;
|
||||
|
||||
|
||||
for (result = false; st && !result; st = st->parent, nr = EXCL_NON_RECURSIVE)
|
||||
{
|
||||
for (ep = st->exclude_list; ep; ep = ep->next)
|
||||
@@ -201,7 +176,7 @@ excluded_name (char const *name, struct tar_stat_info *st)
|
||||
continue;
|
||||
if ((result = excluded_file_name (ep->excluded, name)))
|
||||
break;
|
||||
|
||||
|
||||
if (!rname)
|
||||
{
|
||||
rname = name;
|
||||
@@ -225,12 +200,14 @@ 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;
|
||||
|
||||
if (wordsplit (pattern, &ws,
|
||||
|
||||
options |= EXCLUDE_ALLOC;
|
||||
if (wordsplit (pattern, &ws,
|
||||
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS))
|
||||
return;
|
||||
for (i = 0; i < ws.ws_wordc; i++)
|
||||
@@ -239,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;
|
||||
@@ -251,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;
|
||||
@@ -278,22 +257,18 @@ bzr_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
static void *
|
||||
hg_initfn (void *data)
|
||||
{
|
||||
int *hgopt;
|
||||
static int hg_options;
|
||||
|
||||
if (!data)
|
||||
hgopt = &hg_options;
|
||||
|
||||
int *hgopt = data ? data : &hg_options;
|
||||
*hgopt = EXCLUDE_REGEX;
|
||||
return hgopt;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hg_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
{
|
||||
int *hgopt = data;
|
||||
size_t len;
|
||||
|
||||
|
||||
while (isspace (*pattern))
|
||||
++pattern;
|
||||
if (*pattern == 0 || *pattern == '#')
|
||||
@@ -318,27 +293,27 @@ hg_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
|
||||
--len;
|
||||
p = xmalloc (len+1);
|
||||
memcpy (p, pattern, len);
|
||||
memcpy (p, pattern, len);
|
||||
p[len] = 0;
|
||||
pattern = p;
|
||||
exclude_add_pattern_buffer (ex, p);
|
||||
options |= FNM_LEADING_DIR|EXCLUDE_ALLOC;
|
||||
}
|
||||
|
||||
|
||||
add_exclude (ex, pattern,
|
||||
((*hgopt == EXCLUDE_REGEX)
|
||||
? (options & ~EXCLUDE_WILDCARDS)
|
||||
: (options & ~EXCLUDE_REGEX)) | *hgopt);
|
||||
}
|
||||
|
||||
struct vcs_ignore_file vcs_ignore_files[] = {
|
||||
static struct vcs_ignore_file vcs_ignore_files[] = {
|
||||
{ ".cvsignore", EXCL_NON_RECURSIVE, cvs_addfn, NULL, NULL },
|
||||
{ ".gitignore", 0, git_addfn, NULL, NULL },
|
||||
{ ".bzrignore", 0, bzr_addfn, NULL, NULL },
|
||||
{ ".hgignore", 0, hg_addfn, hg_initfn , NULL },
|
||||
{ ".hgignore", 0, hg_addfn, hg_initfn, NULL },
|
||||
{ NULL, 0, git_addfn, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static struct vcs_ignore_file *
|
||||
get_vcs_ignore_file (const char *name)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Exit from GNU tar.
|
||||
|
||||
Copyright 2009, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2009-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
949
src/extract.c
949
src/extract.c
File diff suppressed because it is too large
Load Diff
131
src/incremen.c
131
src/incremen.c
@@ -1,7 +1,6 @@
|
||||
/* GNU dump extensions to tar.
|
||||
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2009, 2013-2014
|
||||
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
|
||||
@@ -735,7 +744,7 @@ scan_directory (struct tar_stat_info *st)
|
||||
savedir_error (dir);
|
||||
|
||||
info_attach_exclist (st);
|
||||
|
||||
|
||||
tmp = xstrdup (dir);
|
||||
zap_slashes (tmp);
|
||||
|
||||
@@ -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);
|
||||
@@ -1155,11 +1158,14 @@ read_num (FILE *fp, char const *fieldname,
|
||||
}
|
||||
|
||||
if (c)
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("%s: byte %s: %s %s followed by invalid byte 0x%02x"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (fp), offbuf),
|
||||
fieldname, buf, c));
|
||||
{
|
||||
unsigned uc = c;
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("%s: byte %s: %s %s followed by invalid byte 0x%02x"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (fp), offbuf),
|
||||
fieldname, buf, uc));
|
||||
}
|
||||
|
||||
*pval = strtosysint (buf, NULL, min_val, max_val);
|
||||
conversion_errno = errno;
|
||||
@@ -1541,9 +1547,10 @@ dumpdir_ok (char *dumpdir)
|
||||
{
|
||||
if (expect && *p != expect)
|
||||
{
|
||||
unsigned char uc = *p;
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: expected '%c' but found %#3o"),
|
||||
expect, *p));
|
||||
expect, uc));
|
||||
return false;
|
||||
}
|
||||
switch (*p)
|
||||
@@ -1578,7 +1585,7 @@ dumpdir_ok (char *dumpdir)
|
||||
if (expect != 'T')
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: 'T' not preceeded by 'R'")));
|
||||
_("Malformed dumpdir: 'T' not preceded by 'R'")));
|
||||
return false;
|
||||
}
|
||||
if (p[1] == 0 && !has_tempdir)
|
||||
@@ -1708,7 +1715,7 @@ try_purge_directory (char const *directory_name)
|
||||
const char *entry;
|
||||
struct stat st;
|
||||
free (p);
|
||||
p = new_name (directory_name, cur);
|
||||
p = make_file_name (directory_name, cur);
|
||||
|
||||
if (deref_stat (p, &st) != 0)
|
||||
{
|
||||
|
||||
153
src/list.c
153
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-2014 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 */
|
||||
@@ -120,22 +119,24 @@ enforce_one_top_level (char **pfile_name)
|
||||
{
|
||||
char *file_name = *pfile_name;
|
||||
char *p;
|
||||
|
||||
|
||||
for (p = file_name; *p && (ISSLASH (*p) || *p == '.'); p++)
|
||||
;
|
||||
|
||||
if (!*p)
|
||||
return;
|
||||
|
||||
if (strncmp (p, one_top_level_dir, strlen (one_top_level_dir)) == 0)
|
||||
if (*p)
|
||||
{
|
||||
int pos = strlen (one_top_level_dir);
|
||||
if (ISSLASH (p[pos]) || p[pos] == 0)
|
||||
return;
|
||||
}
|
||||
if (strncmp (p, one_top_level_dir, pos) == 0)
|
||||
{
|
||||
if (ISSLASH (p[pos]) || p[pos] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
*pfile_name = new_name (one_top_level_dir, file_name);
|
||||
normalize_filename_x (*pfile_name);
|
||||
*pfile_name = make_file_name (one_top_level_dir, file_name);
|
||||
normalize_filename_x (*pfile_name);
|
||||
}
|
||||
else
|
||||
*pfile_name = xstrdup (one_top_level_dir);
|
||||
free (file_name);
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ read_and (void (*do_something) (void))
|
||||
decode_header (current_header, ¤t_stat_info,
|
||||
¤t_format, 1);
|
||||
if (! name_match (current_stat_info.file_name)
|
||||
|| (NEWER_OPTION_INITIALIZED (newer_mtime_option)
|
||||
|| (TIME_OPTION_INITIALIZED (newer_mtime_option)
|
||||
/* FIXME: We get mtime now, and again later; this causes
|
||||
duplicate diagnostics if header.mtime is bogus. */
|
||||
&& ((mtime.tv_sec
|
||||
@@ -216,7 +217,7 @@ read_and (void (*do_something) (void))
|
||||
if (show_omitted_dirs_option)
|
||||
WARN ((0, 0, _("%s: Omitting"),
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
skip_member ();
|
||||
continue;
|
||||
@@ -255,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];
|
||||
@@ -271,8 +279,7 @@ read_and (void (*do_something) (void))
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
ERROR ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_ZERO_BLOCK:
|
||||
case HEADER_SUCCESS:
|
||||
if (block_number_option)
|
||||
@@ -408,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. */
|
||||
|
||||
@@ -437,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
|
||||
@@ -447,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;
|
||||
@@ -517,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! */
|
||||
@@ -536,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
|
||||
{
|
||||
@@ -567,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
|
||||
{
|
||||
@@ -578,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')
|
||||
@@ -630,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);
|
||||
|
||||
@@ -689,7 +714,6 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
}
|
||||
}
|
||||
|
||||
stat_info->archive_file_size = stat_info->stat.st_size;
|
||||
xheader_decode (stat_info);
|
||||
|
||||
if (sparse_member_p (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;
|
||||
}
|
||||
|
||||
@@ -1218,18 +1239,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
&& !numeric_owner_option)
|
||||
user = st->uname;
|
||||
else
|
||||
{
|
||||
/* Try parsing it as an unsigned integer first, and as a
|
||||
uid_t if that fails. This method can list positive user
|
||||
ids that are too large to fit in a uid_t. */
|
||||
uintmax_t u = from_header (blk->header.uid,
|
||||
sizeof blk->header.uid, 0,
|
||||
0, UINTMAX_MAX,
|
||||
false, false);
|
||||
user = (u != -1
|
||||
? STRINGIFY_BIGINT (u, uform)
|
||||
: imaxtostr (UID_FROM_HEADER (blk->header.uid), uform));
|
||||
}
|
||||
user = STRINGIFY_BIGINT (st->stat.st_uid, uform);
|
||||
|
||||
if (st->gname
|
||||
&& st->gname[0]
|
||||
@@ -1237,18 +1247,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
&& !numeric_owner_option)
|
||||
group = st->gname;
|
||||
else
|
||||
{
|
||||
/* Try parsing it as an unsigned integer first, and as a
|
||||
gid_t if that fails. This method can list positive group
|
||||
ids that are too large to fit in a gid_t. */
|
||||
uintmax_t g = from_header (blk->header.gid,
|
||||
sizeof blk->header.gid, 0,
|
||||
0, UINTMAX_MAX,
|
||||
false, false);
|
||||
group = (g != -1
|
||||
? STRINGIFY_BIGINT (g, gform)
|
||||
: imaxtostr (GID_FROM_HEADER (blk->header.gid), gform));
|
||||
}
|
||||
group = STRINGIFY_BIGINT (st->stat.st_gid, gform);
|
||||
|
||||
/* Format the file size or major/minor device numbers. */
|
||||
|
||||
@@ -1377,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];
|
||||
|
||||
@@ -1400,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)
|
||||
@@ -1435,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)
|
||||
{
|
||||
@@ -1444,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 ();
|
||||
}
|
||||
@@ -1465,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)
|
||||
{
|
||||
|
||||
283
src/map.c
Normal file
283
src/map.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/* Owner/group mapping for tar
|
||||
|
||||
Copyright 2015-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
GNU tar is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU tar is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
#include "wordsplit.h"
|
||||
#include <hash.h>
|
||||
#include <pwd.h>
|
||||
|
||||
struct mapentry
|
||||
{
|
||||
uintmax_t orig_id;
|
||||
uintmax_t new_id;
|
||||
char *new_name;
|
||||
};
|
||||
|
||||
static size_t
|
||||
map_hash (void const *entry, size_t nbuckets)
|
||||
{
|
||||
struct mapentry const *map = entry;
|
||||
return map->orig_id % nbuckets;
|
||||
}
|
||||
|
||||
static bool
|
||||
map_compare (void const *entry1, void const *entry2)
|
||||
{
|
||||
struct mapentry const *map1 = entry1;
|
||||
struct mapentry const *map2 = entry2;
|
||||
return map1->orig_id == map2->orig_id;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_id (uintmax_t *retval,
|
||||
char const *arg, char const *what, uintmax_t maxval,
|
||||
char const *file, unsigned line)
|
||||
{
|
||||
uintmax_t v;
|
||||
char *p;
|
||||
|
||||
errno = 0;
|
||||
v = strtoumax (arg, &p, 10);
|
||||
if (*p || errno)
|
||||
{
|
||||
error (0, 0, _("%s:%u: invalid %s: %s"), file, line, what, arg);
|
||||
return -1;
|
||||
}
|
||||
if (v > maxval)
|
||||
{
|
||||
error (0, 0, _("%s:%u: %s out of range: %s"), file, line, what, arg);
|
||||
return -1;
|
||||
}
|
||||
*retval = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
map_read (Hash_table **ptab, char const *file,
|
||||
uintmax_t (*name_to_id) (char const *), char const *what,
|
||||
uintmax_t maxval)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = NULL;
|
||||
size_t bufsize = 0;
|
||||
ssize_t n;
|
||||
struct wordsplit ws;
|
||||
int wsopt;
|
||||
unsigned line;
|
||||
int err = 0;
|
||||
|
||||
fp = fopen (file, "r");
|
||||
if (!fp)
|
||||
open_fatal (file);
|
||||
|
||||
ws.ws_comment = "#";
|
||||
wsopt = WRDSF_COMMENT | WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS
|
||||
| WRDSF_QUOTE;
|
||||
line = 0;
|
||||
while ((n = getline (&buf, &bufsize, fp)) > 0)
|
||||
{
|
||||
struct mapentry *ent;
|
||||
uintmax_t orig_id, new_id;
|
||||
char *name = NULL;
|
||||
char *colon;
|
||||
|
||||
++line;
|
||||
if (wordsplit (buf, &ws, wsopt))
|
||||
FATAL_ERROR ((0, 0, _("%s:%u: cannot split line: %s"),
|
||||
file, line, wordsplit_strerror (&ws)));
|
||||
wsopt |= WRDSF_REUSE;
|
||||
if (ws.ws_wordc == 0)
|
||||
continue;
|
||||
if (ws.ws_wordc != 2)
|
||||
{
|
||||
error (0, 0, _("%s:%u: malformed line"), file, line);
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ws.ws_wordv[0][0] == '+')
|
||||
{
|
||||
if (parse_id (&orig_id, ws.ws_wordv[0]+1, what, maxval, file, line))
|
||||
{
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (name_to_id)
|
||||
{
|
||||
orig_id = name_to_id (ws.ws_wordv[0]);
|
||||
if (orig_id == UINTMAX_MAX)
|
||||
{
|
||||
error (0, 0, _("%s:%u: can't obtain %s of %s"),
|
||||
file, line, what, ws.ws_wordv[0]);
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
colon = strchr (ws.ws_wordv[1], ':');
|
||||
if (colon)
|
||||
{
|
||||
if (colon > ws.ws_wordv[1])
|
||||
name = ws.ws_wordv[1];
|
||||
*colon++ = 0;
|
||||
if (parse_id (&new_id, colon, what, maxval, file, line))
|
||||
{
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (ws.ws_wordv[1][0] == '+')
|
||||
{
|
||||
if (parse_id (&new_id, ws.ws_wordv[1], what, maxval, file, line))
|
||||
{
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = ws.ws_wordv[1];
|
||||
new_id = name_to_id (ws.ws_wordv[1]);
|
||||
if (new_id == UINTMAX_MAX)
|
||||
{
|
||||
error (0, 0, _("%s:%u: can't obtain %s of %s"),
|
||||
file, line, what, ws.ws_wordv[1]);
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ent = xmalloc (sizeof (*ent));
|
||||
ent->orig_id = orig_id;
|
||||
ent->new_id = new_id;
|
||||
ent->new_name = name ? xstrdup (name) : NULL;
|
||||
|
||||
if (!((*ptab
|
||||
|| (*ptab = hash_initialize (0, 0, map_hash, map_compare, 0)))
|
||||
&& hash_insert (*ptab, ent)))
|
||||
xalloc_die ();
|
||||
}
|
||||
if (wsopt & WRDSF_REUSE)
|
||||
wordsplit_free (&ws);
|
||||
fclose (fp);
|
||||
if (err)
|
||||
FATAL_ERROR ((0, 0, _("errors reading map file")));
|
||||
}
|
||||
|
||||
/* UID translation */
|
||||
|
||||
static Hash_table *owner_map;
|
||||
|
||||
static uintmax_t
|
||||
name_to_uid (char const *name)
|
||||
{
|
||||
struct passwd *pw = getpwnam (name);
|
||||
return pw ? pw->pw_uid : UINTMAX_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
owner_map_read (char const *file)
|
||||
{
|
||||
map_read (&owner_map, file, name_to_uid, "UID", TYPE_MAXIMUM (uid_t));
|
||||
}
|
||||
|
||||
int
|
||||
owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (owner_map)
|
||||
{
|
||||
struct mapentry ent, *res;
|
||||
|
||||
ent.orig_id = uid;
|
||||
res = hash_lookup (owner_map, &ent);
|
||||
if (res)
|
||||
{
|
||||
*new_uid = res->new_id;
|
||||
*new_name = res->new_name;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (owner_option != (uid_t) -1)
|
||||
{
|
||||
*new_uid = owner_option;
|
||||
rc = 0;
|
||||
}
|
||||
if (owner_name_option)
|
||||
{
|
||||
*new_name = owner_name_option;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* GID translation */
|
||||
|
||||
static Hash_table *group_map;
|
||||
|
||||
static uintmax_t
|
||||
name_to_gid (char const *name)
|
||||
{
|
||||
struct group *gr = getgrnam (name);
|
||||
return gr ? gr->gr_gid : UINTMAX_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
group_map_read (char const *file)
|
||||
{
|
||||
map_read (&group_map, file, name_to_gid, "GID", TYPE_MAXIMUM (gid_t));
|
||||
}
|
||||
|
||||
int
|
||||
group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (group_map)
|
||||
{
|
||||
struct mapentry ent, *res;
|
||||
|
||||
ent.orig_id = gid;
|
||||
res = hash_lookup (group_map, &ent);
|
||||
if (res)
|
||||
{
|
||||
*new_gid = res->new_id;
|
||||
*new_name = res->new_name;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (group_option != (uid_t) -1)
|
||||
{
|
||||
*new_gid = group_option;
|
||||
rc = 0;
|
||||
}
|
||||
if (group_name_option)
|
||||
{
|
||||
*new_name = group_name_option;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
180
src/misc.c
180
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 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
|
||||
@@ -29,18 +28,58 @@
|
||||
# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
|
||||
#endif
|
||||
|
||||
static void namebuf_add_dir (namebuf_t, char const *);
|
||||
static char *namebuf_finish (namebuf_t);
|
||||
static const char *tar_getcdpath (int);
|
||||
|
||||
char const *
|
||||
quote_n_colon (int n, char const *arg)
|
||||
{
|
||||
return quotearg_n_style_colon (n, get_quoting_style (NULL), arg);
|
||||
}
|
||||
|
||||
/* Handling strings. */
|
||||
|
||||
/* 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
|
||||
@@ -294,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]));
|
||||
@@ -586,7 +623,12 @@ safer_rmdir (const char *file_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return unlinkat (chdir_fd, file_name, AT_REMOVEDIR);
|
||||
if (unlinkat (chdir_fd, file_name, AT_REMOVEDIR) == 0)
|
||||
{
|
||||
remove_delayed_set_stat (file_name);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove FILE_NAME, returning 1 on success. If FILE_NAME is a directory,
|
||||
@@ -650,16 +692,14 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
(entrylen = strlen (entry)) != 0;
|
||||
entry += entrylen + 1)
|
||||
{
|
||||
char *file_name_buffer = new_name (file_name, entry);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -692,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. */
|
||||
|
||||
@@ -715,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 ();
|
||||
|
||||
@@ -735,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;
|
||||
}
|
||||
}
|
||||
@@ -759,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,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)
|
||||
@@ -789,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;
|
||||
}
|
||||
|
||||
@@ -885,8 +927,6 @@ chdir_count (void)
|
||||
int
|
||||
chdir_arg (char const *dir)
|
||||
{
|
||||
char *absdir;
|
||||
|
||||
if (wd_count == wd_alloc)
|
||||
{
|
||||
if (wd_alloc == 0)
|
||||
@@ -896,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++;
|
||||
}
|
||||
@@ -913,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++;
|
||||
}
|
||||
@@ -1022,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;
|
||||
}
|
||||
|
||||
@@ -1032,7 +1096,10 @@ void
|
||||
close_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
close_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
close_warn (name);
|
||||
}
|
||||
else
|
||||
close_error (name);
|
||||
}
|
||||
@@ -1041,7 +1108,10 @@ void
|
||||
open_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
open_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
open_warn (name);
|
||||
}
|
||||
else
|
||||
open_error (name);
|
||||
}
|
||||
@@ -1050,7 +1120,10 @@ void
|
||||
read_diag_details (char const *name, off_t offset, size_t size)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
read_warn_details (name, offset, size);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
read_warn_details (name, offset, size);
|
||||
}
|
||||
else
|
||||
read_error_details (name, offset, size);
|
||||
}
|
||||
@@ -1059,7 +1132,10 @@ void
|
||||
readlink_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
readlink_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
readlink_warn (name);
|
||||
}
|
||||
else
|
||||
readlink_error (name);
|
||||
}
|
||||
@@ -1068,7 +1144,10 @@ void
|
||||
savedir_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
savedir_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
savedir_warn (name);
|
||||
}
|
||||
else
|
||||
savedir_error (name);
|
||||
}
|
||||
@@ -1077,7 +1156,10 @@ void
|
||||
seek_diag_details (char const *name, off_t offset)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
seek_warn_details (name, offset);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
seek_warn_details (name, offset);
|
||||
}
|
||||
else
|
||||
seek_error_details (name, offset);
|
||||
}
|
||||
@@ -1086,7 +1168,10 @@ void
|
||||
stat_diag (char const *name)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
stat_warn (name);
|
||||
{
|
||||
if (WARNING_ENABLED(WARN_FAILED_READ))
|
||||
stat_warn (name);
|
||||
}
|
||||
else
|
||||
stat_error (name);
|
||||
}
|
||||
@@ -1106,13 +1191,6 @@ file_removed_diag (const char *name, bool top_level,
|
||||
diagfn (name);
|
||||
}
|
||||
|
||||
void
|
||||
write_fatal_details (char const *name, ssize_t status, size_t size)
|
||||
{
|
||||
write_error_details (name, status, size);
|
||||
fatal_exit ();
|
||||
}
|
||||
|
||||
/* Fork, aborting if unsuccessful. */
|
||||
pid_t
|
||||
xfork (void)
|
||||
@@ -1136,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;
|
||||
@@ -1197,7 +1275,7 @@ namebuf_name (namebuf_t buf, const char *name)
|
||||
return buf->buffer;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
namebuf_add_dir (namebuf_t buf, const char *name)
|
||||
{
|
||||
static char dirsep[] = { DIRECTORY_SEPARATOR, 0 };
|
||||
@@ -1210,7 +1288,7 @@ namebuf_add_dir (namebuf_t buf, const char *name)
|
||||
buf->dir_length += strlen (name);
|
||||
}
|
||||
|
||||
char *
|
||||
static char *
|
||||
namebuf_finish (namebuf_t buf)
|
||||
{
|
||||
char *res = buf->buffer;
|
||||
|
||||
828
src/names.c
828
src/names.c
File diff suppressed because it is too large
Load Diff
277
src/sparse.c
277
src/sparse.c
@@ -1,6 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright 2003-2007, 2010, 2013-2014 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
|
||||
@@ -208,9 +208,9 @@ sparse_add_map (struct tar_stat_info *st, struct sp_array const *sp)
|
||||
st->sparse_map_avail = avail + 1;
|
||||
}
|
||||
|
||||
/* Scan the sparse file and create its map */
|
||||
/* Scan the sparse file byte-by-byte and create its map. */
|
||||
static bool
|
||||
sparse_scan_file (struct tar_sparse_file *file)
|
||||
sparse_scan_file_raw (struct tar_sparse_file *file)
|
||||
{
|
||||
struct tar_stat_info *st = file->stat_info;
|
||||
int fd = file->fd;
|
||||
@@ -221,41 +221,38 @@ sparse_scan_file (struct tar_sparse_file *file)
|
||||
|
||||
st->archive_file_size = 0;
|
||||
|
||||
if (ST_NBLOCKS (st->stat) == 0)
|
||||
offset = st->stat.st_size;
|
||||
else
|
||||
if (!tar_sparse_scan (file, scan_begin, NULL))
|
||||
return false;
|
||||
|
||||
while ((count = blocking_read (fd, buffer, sizeof buffer)) != 0
|
||||
&& count != SAFE_READ_ERROR)
|
||||
{
|
||||
if (!tar_sparse_scan (file, scan_begin, NULL))
|
||||
return false;
|
||||
/* Analyze the block. */
|
||||
if (zero_block_p (buffer, count))
|
||||
{
|
||||
if (sp.numbytes)
|
||||
{
|
||||
sparse_add_map (st, &sp);
|
||||
sp.numbytes = 0;
|
||||
if (!tar_sparse_scan (file, scan_block, NULL))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
sp.numbytes += count;
|
||||
st->archive_file_size += count;
|
||||
if (!tar_sparse_scan (file, scan_block, buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((count = blocking_read (fd, buffer, sizeof buffer)) != 0
|
||||
&& count != SAFE_READ_ERROR)
|
||||
{
|
||||
/* Analyze the block. */
|
||||
if (zero_block_p (buffer, count))
|
||||
{
|
||||
if (sp.numbytes)
|
||||
{
|
||||
sparse_add_map (st, &sp);
|
||||
sp.numbytes = 0;
|
||||
if (!tar_sparse_scan (file, scan_block, NULL))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
sp.numbytes += count;
|
||||
st->archive_file_size += count;
|
||||
if (!tar_sparse_scan (file, scan_block, buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += count;
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
|
||||
/* save one more sparse segment of length 0 to indicate that
|
||||
the file ends with a hole */
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
|
||||
@@ -264,6 +261,113 @@ sparse_scan_file (struct tar_sparse_file *file)
|
||||
return tar_sparse_scan (file, scan_end, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
sparse_scan_file_wholesparse (struct tar_sparse_file *file)
|
||||
{
|
||||
struct tar_stat_info *st = file->stat_info;
|
||||
struct sp_array sp = {0, 0};
|
||||
|
||||
/* Note that this function is called only for truly sparse files of size >= 1
|
||||
block size (checked via ST_IS_SPARSE before). See the thread
|
||||
http://www.mail-archive.com/bug-tar@gnu.org/msg04209.html for more info */
|
||||
if (ST_NBLOCKS (st->stat) == 0)
|
||||
{
|
||||
st->archive_file_size = 0;
|
||||
sp.offset = st->stat.st_size;
|
||||
sparse_add_map (st, &sp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SEEK_HOLE
|
||||
/* Try to engage SEEK_HOLE/SEEK_DATA feature. */
|
||||
static bool
|
||||
sparse_scan_file_seek (struct tar_sparse_file *file)
|
||||
{
|
||||
struct tar_stat_info *st = file->stat_info;
|
||||
int fd = file->fd;
|
||||
struct sp_array sp = {0, 0};
|
||||
off_t offset = 0;
|
||||
off_t data_offset;
|
||||
off_t hole_offset;
|
||||
|
||||
st->archive_file_size = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* locate first chunk of data */
|
||||
data_offset = lseek (fd, offset, SEEK_DATA);
|
||||
|
||||
if (data_offset == (off_t)-1)
|
||||
/* ENXIO == EOF; error otherwise */
|
||||
{
|
||||
if (errno == ENXIO)
|
||||
{
|
||||
/* file ends with hole, add one more empty chunk of data */
|
||||
sp.numbytes = 0;
|
||||
sp.offset = st->stat.st_size;
|
||||
sparse_add_map (st, &sp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hole_offset = lseek (fd, data_offset, SEEK_HOLE);
|
||||
|
||||
/* according to specs, if FS does not fully support
|
||||
SEEK_DATA/SEEK_HOLE it may just implement kind of "wrapper" around
|
||||
classic lseek() call. We must detect it here and try to use other
|
||||
hole-detection methods. */
|
||||
if (offset == 0 /* first loop */
|
||||
&& data_offset == 0
|
||||
&& hole_offset == st->stat.st_size)
|
||||
{
|
||||
lseek (fd, 0, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
|
||||
sp.offset = data_offset;
|
||||
sp.numbytes = hole_offset - data_offset;
|
||||
sparse_add_map (st, &sp);
|
||||
|
||||
st->archive_file_size += sp.numbytes;
|
||||
offset = hole_offset;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
sparse_scan_file (struct tar_sparse_file *file)
|
||||
{
|
||||
/* always check for completely sparse files */
|
||||
if (sparse_scan_file_wholesparse (file))
|
||||
return true;
|
||||
|
||||
switch (hole_detection)
|
||||
{
|
||||
case HOLE_DETECTION_DEFAULT:
|
||||
case HOLE_DETECTION_SEEK:
|
||||
#ifdef SEEK_HOLE
|
||||
if (sparse_scan_file_seek (file))
|
||||
return true;
|
||||
#else
|
||||
if (hole_detection == HOLE_DETECTION_SEEK)
|
||||
WARN((0, 0,
|
||||
_("\"seek\" hole detection is not supported, using \"raw\".")));
|
||||
/* fall back to "raw" for this and all other files */
|
||||
hole_detection = HOLE_DETECTION_RAW;
|
||||
#endif
|
||||
FALLTHROUGH;
|
||||
case HOLE_DETECTION_RAW:
|
||||
if (sparse_scan_file_raw (file))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct tar_sparse_optab const oldgnu_optab;
|
||||
static struct tar_sparse_optab const star_optab;
|
||||
static struct tar_sparse_optab const pax_optab;
|
||||
@@ -311,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,
|
||||
@@ -321,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;
|
||||
@@ -358,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)
|
||||
@@ -440,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;
|
||||
@@ -455,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;
|
||||
@@ -467,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;
|
||||
}
|
||||
|
||||
@@ -484,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,
|
||||
@@ -492,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)];
|
||||
@@ -503,6 +657,7 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
|
||||
beg += bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -529,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,
|
||||
@@ -539,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;
|
||||
@@ -560,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;
|
||||
@@ -578,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);
|
||||
@@ -612,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;
|
||||
}
|
||||
@@ -756,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;
|
||||
}
|
||||
@@ -876,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
|
||||
@@ -1107,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 \
|
||||
{ \
|
||||
@@ -1123,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; \
|
||||
} \
|
||||
@@ -1134,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)))
|
||||
@@ -1162,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));
|
||||
@@ -1172,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;
|
||||
|
||||
15
src/suffix.c
15
src/suffix.c
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2007, 2009, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2007-2023 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff.
|
||||
|
||||
@@ -45,6 +45,8 @@ static struct compression_suffix compression_suffixes[] = {
|
||||
{ S(lzo, LZOP) },
|
||||
{ S(xz, XZ) },
|
||||
{ S(txz, XZ) }, /* Slackware */
|
||||
{ S(zst, ZSTD) },
|
||||
{ S(tzst, ZSTD) },
|
||||
{ NULL }
|
||||
#undef S
|
||||
#undef __CAT2__
|
||||
@@ -59,7 +61,7 @@ find_compression_suffix (const char *name, size_t *ret_len)
|
||||
{
|
||||
size_t len;
|
||||
struct compression_suffix *p;
|
||||
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
@@ -98,10 +100,14 @@ strip_compression_suffix (const char *name)
|
||||
{
|
||||
char *s = NULL;
|
||||
size_t len;
|
||||
struct compression_suffix const *p = find_compression_suffix (name, &len);
|
||||
|
||||
if (find_compression_suffix (name, &len))
|
||||
if (p)
|
||||
{
|
||||
if (strncmp (name + len - 4, ".tar", 4) == 0)
|
||||
/* Strip an additional ".tar" suffix, but only if the just-stripped
|
||||
"outer" suffix did not begin with "t". */
|
||||
if (len > 4 && strncmp (name + len - 4, ".tar", 4) == 0
|
||||
&& p->suffix[0] != 't')
|
||||
len -= 4;
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
@@ -111,4 +117,3 @@ strip_compression_suffix (const char *name)
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
124
src/system.c
124
src/system.c
@@ -1,6 +1,6 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright 2003-2008, 2010, 2013-2014 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
|
||||
@@ -16,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>
|
||||
@@ -26,16 +27,46 @@
|
||||
static _Noreturn void
|
||||
xexec (const char *cmd)
|
||||
{
|
||||
struct wordsplit ws;
|
||||
char *argv[4];
|
||||
|
||||
ws.ws_env = (const char **) environ;
|
||||
if (wordsplit (cmd, &ws, (WRDSF_DEFFLAGS | WRDSF_ENV) & ~WRDSF_NOVAR))
|
||||
FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"),
|
||||
cmd, wordsplit_strerror (&ws)));
|
||||
execvp (ws.ws_wordv[0], ws.ws_wordv);
|
||||
argv[0] = (char *) "/bin/sh";
|
||||
argv[1] = (char *) "-c";
|
||||
argv[2] = (char *) cmd;
|
||||
argv[3] = NULL;
|
||||
|
||||
execv ("/bin/sh", argv);
|
||||
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
|
||||
@@ -50,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)
|
||||
{
|
||||
@@ -127,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". */
|
||||
@@ -159,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
|
||||
@@ -269,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
|
||||
@@ -276,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;
|
||||
@@ -330,6 +351,7 @@ sys_child_open_for_compress (void)
|
||||
pid_t grandchild_pid;
|
||||
pid_t child_pid;
|
||||
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
xpipe (parent_pipe);
|
||||
child_pid = xfork ();
|
||||
|
||||
@@ -538,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);
|
||||
|
||||
21
src/tar.h
21
src/tar.h
@@ -1,7 +1,6 @@
|
||||
/* GNU tar Archive Format description.
|
||||
|
||||
Copyright 1988-1989, 1991-1997, 2000-2001, 2003-2007, 2012-2014 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 */
|
||||
@@ -327,8 +333,15 @@ struct tar_stat_info
|
||||
size_t sparse_map_size; /* Size of the sparse map */
|
||||
struct sp_array *sparse_map;
|
||||
|
||||
size_t xattr_map_size; /* Size of the xattr map */
|
||||
struct xattr_array *xattr_map;
|
||||
off_t real_size; /* The real size of sparse file */
|
||||
bool real_size_set; /* True when GNU.sparse.realsize is set in
|
||||
archived file */
|
||||
|
||||
bool sparse_name_done; /* Set to true if 'GNU.sparse.name' header was
|
||||
processed pax header parsing. Following 'path'
|
||||
header (lower priority) will be ignored. */
|
||||
|
||||
struct xattr_map xattr_map;
|
||||
|
||||
/* Extended headers */
|
||||
struct xheader xhdr;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2006-2008, 2013-2014 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
|
||||
@@ -100,7 +100,7 @@ add_segment (struct transform *tf)
|
||||
}
|
||||
|
||||
static void
|
||||
add_literal_segment (struct transform *tf, char *str, char *end)
|
||||
add_literal_segment (struct transform *tf, const char *str, const char *end)
|
||||
{
|
||||
size_t len = end - str;
|
||||
if (len)
|
||||
@@ -208,6 +208,8 @@ parse_transform_expr (const char *expr)
|
||||
}
|
||||
|
||||
delim = expr[1];
|
||||
if (!delim)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
|
||||
/* Scan regular expression */
|
||||
for (i = 2; expr[i] && expr[i] != delim; i++)
|
||||
@@ -272,7 +274,7 @@ parse_transform_expr (const char *expr)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
|
||||
}
|
||||
|
||||
if (str[0] == '^' || str[strlen (str) - 1] == '$')
|
||||
if (str[0] == '^' || (i > 2 && str[i - 3] == '$'))
|
||||
tf->transform_type = transform_first;
|
||||
|
||||
free (str);
|
||||
@@ -378,13 +380,15 @@ parse_transform_expr (const char *expr)
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Try to be nice */
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = '\\';
|
||||
buf[1] = *cur;
|
||||
add_literal_segment (tf, buf, buf + 2);
|
||||
}
|
||||
if (*cur == delim)
|
||||
add_char_segment (tf, delim);
|
||||
else
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = '\\';
|
||||
buf[1] = *cur;
|
||||
add_literal_segment (tf, buf, buf + 2);
|
||||
}
|
||||
cur++;
|
||||
break;
|
||||
}
|
||||
@@ -400,6 +404,7 @@ parse_transform_expr (const char *expr)
|
||||
cur++;
|
||||
}
|
||||
add_literal_segment (tf, beg, cur);
|
||||
free(str);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -488,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)
|
||||
{
|
||||
@@ -499,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)
|
||||
@@ -547,7 +552,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
FALLTHROUGH;
|
||||
|
||||
case ctl_upcase:
|
||||
case ctl_locase:
|
||||
|
||||
101
src/unlink.c
101
src/unlink.c
@@ -1,6 +1,6 @@
|
||||
/* Unlink files.
|
||||
|
||||
Copyright 2009, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2009-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -32,6 +32,10 @@ struct deferred_unlink
|
||||
entry got added to the queue */
|
||||
};
|
||||
|
||||
#define IS_CWD(p) \
|
||||
((p)->is_dir \
|
||||
&& ((p)->file_name[0] == 0 || strcmp ((p)->file_name, ".") == 0))
|
||||
|
||||
/* The unlink queue */
|
||||
static struct deferred_unlink *dunlink_head, *dunlink_tail;
|
||||
|
||||
@@ -60,6 +64,24 @@ dunlink_alloc (void)
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
dunlink_insert (struct deferred_unlink *anchor, struct deferred_unlink *p)
|
||||
{
|
||||
if (anchor)
|
||||
{
|
||||
p->next = anchor->next;
|
||||
anchor->next = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->next = dunlink_head;
|
||||
dunlink_head = p;
|
||||
}
|
||||
if (!p->next)
|
||||
dunlink_tail = p;
|
||||
dunlink_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
dunlink_reclaim (struct deferred_unlink *p)
|
||||
{
|
||||
@@ -73,7 +95,7 @@ flush_deferred_unlinks (bool force)
|
||||
{
|
||||
struct deferred_unlink *p, *prev = NULL;
|
||||
int saved_chdir = chdir_current;
|
||||
|
||||
|
||||
for (p = dunlink_head; p; )
|
||||
{
|
||||
struct deferred_unlink *next = p->next;
|
||||
@@ -86,12 +108,11 @@ flush_deferred_unlinks (bool force)
|
||||
{
|
||||
const char *fname;
|
||||
|
||||
if (p->dir_idx
|
||||
&& (p->file_name[0] == 0
|
||||
|| strcmp (p->file_name, ".") == 0))
|
||||
if (p->dir_idx && IS_CWD (p))
|
||||
{
|
||||
fname = tar_dirname ();
|
||||
chdir_do (p->dir_idx - 1);
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
fname = p->file_name;
|
||||
@@ -103,16 +124,18 @@ flush_deferred_unlinks (bool force)
|
||||
case ENOENT:
|
||||
/* nothing to worry about */
|
||||
break;
|
||||
case EEXIST:
|
||||
/* OpenSolaris >=10 sets EEXIST instead of ENOTEMPTY
|
||||
if trying to remove a non-empty directory */
|
||||
#if defined ENOTEMPTY && ENOTEMPTY != EEXIST
|
||||
case ENOTEMPTY:
|
||||
if (!force)
|
||||
{
|
||||
/* Keep the record in list, in the hope we'll
|
||||
be able to remove it later */
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
}
|
||||
/* fall through */
|
||||
#endif
|
||||
/* Keep the record in list, in the hope we'll
|
||||
be able to remove it later */
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
|
||||
default:
|
||||
rmdir_error (fname);
|
||||
}
|
||||
@@ -139,6 +162,34 @@ flush_deferred_unlinks (bool force)
|
||||
}
|
||||
if (!dunlink_head)
|
||||
dunlink_tail = NULL;
|
||||
else if (force)
|
||||
{
|
||||
for (p = dunlink_head; p; )
|
||||
{
|
||||
struct deferred_unlink *next = p->next;
|
||||
const char *fname;
|
||||
|
||||
chdir_do (p->dir_idx);
|
||||
if (p->dir_idx && IS_CWD (p))
|
||||
{
|
||||
fname = tar_dirname ();
|
||||
chdir_do (p->dir_idx - 1);
|
||||
}
|
||||
else
|
||||
fname = p->file_name;
|
||||
|
||||
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
rmdir_error (fname);
|
||||
}
|
||||
dunlink_reclaim (p);
|
||||
dunlink_count--;
|
||||
p = next;
|
||||
}
|
||||
dunlink_head = dunlink_tail = NULL;
|
||||
}
|
||||
|
||||
chdir_do (saved_chdir);
|
||||
}
|
||||
|
||||
@@ -146,6 +197,7 @@ void
|
||||
finish_deferred_unlinks (void)
|
||||
{
|
||||
flush_deferred_unlinks (true);
|
||||
|
||||
while (dunlink_avail)
|
||||
{
|
||||
struct deferred_unlink *next = dunlink_avail->next;
|
||||
@@ -171,10 +223,17 @@ queue_deferred_unlink (const char *name, bool is_dir)
|
||||
p->is_dir = is_dir;
|
||||
p->records_written = records_written;
|
||||
|
||||
if (dunlink_tail)
|
||||
dunlink_tail->next = p;
|
||||
if (IS_CWD (p))
|
||||
{
|
||||
struct deferred_unlink *q, *prev;
|
||||
for (q = dunlink_head, prev = NULL; q; prev = q, q = q->next)
|
||||
if (IS_CWD (q) && q->dir_idx < p->dir_idx)
|
||||
break;
|
||||
if (q)
|
||||
dunlink_insert (prev, p);
|
||||
else
|
||||
dunlink_insert (dunlink_tail, p);
|
||||
}
|
||||
else
|
||||
dunlink_head = p;
|
||||
dunlink_tail = p;
|
||||
dunlink_count++;
|
||||
dunlink_insert (dunlink_tail, p);
|
||||
}
|
||||
|
||||
101
src/update.c
101
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 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,29 +145,34 @@ 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),
|
||||
0, false, NULL);
|
||||
name->change_dir, false, NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -186,13 +191,11 @@ update_archive (void)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
|
||||
FALLTHROUGH;
|
||||
case HEADER_FAILURE:
|
||||
break;
|
||||
|
||||
|
||||
32
src/utf8.c
32
src/utf8.c
@@ -1,6 +1,6 @@
|
||||
/* Charset handling for GNU tar.
|
||||
|
||||
Copyright 2004, 2006-2007, 2013-2014 Free Software Foundation, Inc.
|
||||
Copyright 2004-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -35,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
|
||||
|
||||
|
||||
@@ -64,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)
|
||||
@@ -80,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 Free Software Foundation, Inc.
|
||||
Copyright 2009-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -47,6 +47,9 @@ static char const *const warning_args[] = {
|
||||
"existing-file",
|
||||
"xattr-write",
|
||||
"record-size",
|
||||
"failed-read",
|
||||
"missing-zero-blocks",
|
||||
"verbose",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -74,12 +77,15 @@ static int warning_types[] = {
|
||||
WARN_DECOMPRESS_PROGRAM,
|
||||
WARN_EXISTING_FILE,
|
||||
WARN_XATTR_WRITE,
|
||||
WARN_RECORD_SIZE
|
||||
WARN_RECORD_SIZE,
|
||||
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)
|
||||
|
||||
236
src/xattrs.c
236
src/xattrs.c
@@ -1,6 +1,6 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014 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
|
||||
}
|
||||
}
|
||||
@@ -434,8 +534,12 @@ xattrs_clear_setup (void)
|
||||
clear_mask_map (&xattrs_setup.excl);
|
||||
}
|
||||
|
||||
/* get all xattrs from file given by FILE_NAME or FD (when non-zero). This
|
||||
includes all the user.*, security.*, system.*, etc. available domains */
|
||||
static bool xattrs_masked_out (const char *kw, bool archiving);
|
||||
|
||||
/* get xattrs from file given by FILE_NAME or FD (when non-zero)
|
||||
xattrs are checked against the user supplied include/exclude mask
|
||||
if no mask is given this includes all the user.*, security.*, system.*,
|
||||
etc. available domains */
|
||||
void
|
||||
xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd)
|
||||
@@ -480,8 +584,6 @@ xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
size_t len = strlen (attr);
|
||||
ssize_t aret = 0;
|
||||
|
||||
/* Archive all xattrs during creation, decide at extraction time
|
||||
* which ones are of interest/use for the target filesystem. */
|
||||
while (((fd == 0)
|
||||
? ((aret = lgetxattrat (parentfd, file_name, attr,
|
||||
val, asz)) == -1)
|
||||
@@ -492,7 +594,10 @@ xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
}
|
||||
|
||||
if (aret != -1)
|
||||
xheader_xattr_add (st, attr, val, aret);
|
||||
{
|
||||
if (!xattrs_masked_out (attr, true))
|
||||
xheader_xattr_add (st, attr, val, aret);
|
||||
}
|
||||
else if (errno != ENOATTR)
|
||||
call_arg_warn ((fd == 0) ? "lgetxattrat"
|
||||
: "fgetxattr", file_name);
|
||||
@@ -507,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)
|
||||
@@ -624,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;
|
||||
@@ -636,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
|
||||
@@ -652,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
|
||||
@@ -676,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
|
||||
}
|
||||
@@ -702,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 = '*';
|
||||
@@ -735,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 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,
|
||||
|
||||
414
src/xheader.c
414
src/xheader.c
@@ -1,7 +1,6 @@
|
||||
/* POSIX extended headers for tar.
|
||||
|
||||
Copyright (C) 2003-2007, 2009-2010, 2012-2014 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;
|
||||
}
|
||||
@@ -755,11 +709,21 @@ xheader_decode (struct tar_stat_info *st)
|
||||
continue;
|
||||
}
|
||||
run_override_list (keyword_override_list, st);
|
||||
|
||||
/* The archived (effective) file size is always set directly in tar header
|
||||
field, possibly overridden by "size" extended header - in both cases,
|
||||
result is now decoded in st->stat.st_size */
|
||||
st->archive_file_size = st->stat.st_size;
|
||||
|
||||
/* The real file size (given by stat()) may be redefined for sparse
|
||||
files in "GNU.sparse.realsize" extended header */
|
||||
if (st->real_size_set)
|
||||
st->stat.st_size = st->real_size;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -803,11 +767,11 @@ xheader_store (char const *keyword, struct tar_stat_info *st,
|
||||
t = locate_handler (keyword);
|
||||
if (!t || !t->coder)
|
||||
return;
|
||||
if (xheader_keyword_deleted_p (keyword)
|
||||
|| xheader_keyword_override_p (keyword))
|
||||
if (xheader_keyword_deleted_p (keyword))
|
||||
return;
|
||||
xheader_init (&st->xhdr);
|
||||
t->coder (st, keyword, &st->xhdr, data);
|
||||
if (!xheader_keyword_override_p (keyword))
|
||||
t->coder (st, keyword, &st->xhdr, data);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -875,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);
|
||||
}
|
||||
@@ -1017,7 +981,7 @@ xheader_string_end (struct xheader *xhdr, char const *keyword)
|
||||
}
|
||||
x_obstack_blank (xhdr, p);
|
||||
x_obstack_1grow (xhdr, '\n');
|
||||
cp = obstack_next_free (xhdr->stk) - xhdr->string_length - p - 1;
|
||||
cp = (char*) obstack_next_free (xhdr->stk) - xhdr->string_length - p - 1;
|
||||
memmove (cp + p, cp, xhdr->string_length);
|
||||
cp = stpcpy (cp, np);
|
||||
*cp++ = ' ';
|
||||
@@ -1095,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;
|
||||
@@ -1151,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);
|
||||
}
|
||||
@@ -1177,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))
|
||||
@@ -1186,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);
|
||||
@@ -1196,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),
|
||||
@@ -1206,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);
|
||||
}
|
||||
@@ -1247,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))
|
||||
@@ -1266,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))
|
||||
@@ -1275,25 +1245,46 @@ 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);
|
||||
}
|
||||
|
||||
static void
|
||||
path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
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,
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
if (! st->sparse_name_done)
|
||||
raw_path_decoder (st, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_path_decoder (struct tar_stat_info *st,
|
||||
MAYBE_UNUSED char const *keyword,
|
||||
char const *arg,
|
||||
MAYBE_UNUSED size_t size)
|
||||
{
|
||||
st->sparse_name_done = true;
|
||||
raw_path_decoder (st, arg);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1302,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))
|
||||
@@ -1311,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);
|
||||
@@ -1321,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),
|
||||
@@ -1331,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);
|
||||
}
|
||||
@@ -1356,17 +1347,20 @@ 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))
|
||||
st->stat.st_size = u;
|
||||
{
|
||||
st->real_size_set = true;
|
||||
st->real_size = u;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1375,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))
|
||||
@@ -1398,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))
|
||||
@@ -1423,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))
|
||||
@@ -1440,16 +1434,16 @@ 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;
|
||||
|
||||
st->sparse_map_avail = 0;
|
||||
while (1)
|
||||
{
|
||||
intmax_t u;
|
||||
char *delim;
|
||||
struct sp_array e;
|
||||
|
||||
if (!ISDIGIT (*arg))
|
||||
{
|
||||
@@ -1514,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));
|
||||
@@ -1522,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)
|
||||
{
|
||||
@@ -1531,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;
|
||||
@@ -1555,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))
|
||||
@@ -1566,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;
|
||||
@@ -1574,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))
|
||||
@@ -1584,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;
|
||||
@@ -1623,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;
|
||||
@@ -1640,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);
|
||||
}
|
||||
@@ -1677,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))
|
||||
@@ -1686,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);
|
||||
}
|
||||
@@ -1695,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))
|
||||
@@ -1717,7 +1713,7 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
{ "uname", uname_coder, uname_decoder, 0, false },
|
||||
|
||||
/* Sparse file handling */
|
||||
{ "GNU.sparse.name", path_coder, path_decoder,
|
||||
{ "GNU.sparse.name", path_coder, sparse_path_decoder,
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
|
||||
XHDR_PROTECTED, false },
|
||||
|
||||
5
tests/.gitignore
vendored
5
tests/.gitignore
vendored
@@ -8,3 +8,8 @@ argcv.c
|
||||
argcv.h
|
||||
genfile.c
|
||||
genfile
|
||||
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-2013 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. ##
|
||||
@@ -42,28 +46,43 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
## ------------ ##
|
||||
|
||||
TESTSUITE_AT = \
|
||||
testsuite.at\
|
||||
compress.m4\
|
||||
T-cd.at\
|
||||
T-dir00.at\
|
||||
T-dir01.at\
|
||||
T-empty.at\
|
||||
T-null.at\
|
||||
T-null2.at\
|
||||
T-rec.at\
|
||||
T-recurse.at\
|
||||
T-zfile.at\
|
||||
T-nonl.at\
|
||||
T-mult.at\
|
||||
T-nest.at\
|
||||
testsuite.at\
|
||||
add-file.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
append02.at\
|
||||
append03.at\
|
||||
append04.at\
|
||||
append05.at\
|
||||
backup01.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\
|
||||
exclude02.at\
|
||||
@@ -100,8 +119,16 @@ TESTSUITE_AT = \
|
||||
extrac17.at\
|
||||
extrac18.at\
|
||||
extrac19.at\
|
||||
extrac20.at\
|
||||
extrac21.at\
|
||||
extrac22.at\
|
||||
extrac23.at\
|
||||
extrac24.at\
|
||||
extrac25.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
dirrem01.at\
|
||||
dirrem02.at\
|
||||
gzip.at\
|
||||
grow.at\
|
||||
incremental.at\
|
||||
@@ -114,9 +141,10 @@ TESTSUITE_AT = \
|
||||
incr07.at\
|
||||
incr08.at\
|
||||
incr09.at\
|
||||
incr10.at\
|
||||
incr11.at\
|
||||
indexfile.at\
|
||||
ignfail.at\
|
||||
iotty.at\
|
||||
label01.at\
|
||||
label02.at\
|
||||
label03.at\
|
||||
@@ -136,6 +164,7 @@ TESTSUITE_AT = \
|
||||
lustar01.at\
|
||||
lustar02.at\
|
||||
lustar03.at\
|
||||
map.at\
|
||||
multiv01.at\
|
||||
multiv02.at\
|
||||
multiv03.at\
|
||||
@@ -144,19 +173,27 @@ TESTSUITE_AT = \
|
||||
multiv06.at\
|
||||
multiv07.at\
|
||||
multiv08.at\
|
||||
multiv09.at\
|
||||
multiv10.at\
|
||||
numeric.at\
|
||||
old.at\
|
||||
onetop01.at\
|
||||
onetop02.at\
|
||||
onetop03.at\
|
||||
onetop04.at\
|
||||
onetop05.at\
|
||||
opcomp01.at\
|
||||
opcomp02.at\
|
||||
opcomp03.at\
|
||||
opcomp04.at\
|
||||
opcomp05.at\
|
||||
opcomp06.at\
|
||||
positional01.at\
|
||||
positional02.at\
|
||||
positional03.at\
|
||||
options.at\
|
||||
options02.at\
|
||||
options03.at\
|
||||
owner.at\
|
||||
pipe.at\
|
||||
recurse.at\
|
||||
@@ -166,6 +203,7 @@ TESTSUITE_AT = \
|
||||
rename03.at\
|
||||
rename04.at\
|
||||
rename05.at\
|
||||
rename06.at\
|
||||
remfiles01.at\
|
||||
remfiles02.at\
|
||||
remfiles03.at\
|
||||
@@ -198,16 +236,25 @@ TESTSUITE_AT = \
|
||||
sparse02.at\
|
||||
sparse03.at\
|
||||
sparse04.at\
|
||||
sparse05.at\
|
||||
sparse06.at\
|
||||
sparse07.at\
|
||||
sparsemv.at\
|
||||
sparsemvp.at\
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
sptrcreat.at\
|
||||
sptrdiff00.at\
|
||||
sptrdiff01.at\
|
||||
time01.at\
|
||||
time02.at\
|
||||
truncate.at\
|
||||
update.at\
|
||||
update01.at\
|
||||
update02.at\
|
||||
update03.at\
|
||||
update04.at\
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
@@ -215,6 +262,8 @@ TESTSUITE_AT = \
|
||||
version.at\
|
||||
xform-h.at\
|
||||
xform01.at\
|
||||
xform02.at\
|
||||
xform03.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
star/multi-fail.at\
|
||||
@@ -226,6 +275,9 @@ TESTSUITE_AT = \
|
||||
xattr03.at\
|
||||
xattr04.at\
|
||||
xattr05.at\
|
||||
xattr06.at\
|
||||
xattr07.at\
|
||||
xattr08.at\
|
||||
acls01.at\
|
||||
acls02.at\
|
||||
acls03.at\
|
||||
@@ -233,6 +285,9 @@ TESTSUITE_AT = \
|
||||
selacl01.at\
|
||||
capabs_raw01.at
|
||||
|
||||
distclean-local:
|
||||
-rm -rf download
|
||||
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
|
||||
AUTOTEST = $(AUTOM4TE) --language=autotest
|
||||
@@ -255,7 +310,7 @@ check-full:
|
||||
#check_SCRIPTS = tar
|
||||
|
||||
# Run the test suite on the *installed* tree.
|
||||
installcheck-local:
|
||||
installcheck-local: $(check_PROGRAMS)
|
||||
$(SHELL) $(TESTSUITE) $(TESTSUITEFLAGS) AUTOTEST_PATH=$(exec_prefix)/bin
|
||||
|
||||
|
||||
@@ -263,15 +318,10 @@ installcheck-local:
|
||||
## genfile ##
|
||||
## ------------ ##
|
||||
|
||||
check_PROGRAMS = genfile
|
||||
|
||||
if TAR_COND_GRANTPT
|
||||
check_PROGRAMS += ttyemu
|
||||
endif
|
||||
check_PROGRAMS = genfile checkseekhole ckmtime
|
||||
|
||||
genfile_SOURCES = genfile.c argcv.c argcv.h
|
||||
|
||||
ttyemu_SOURCES = ttyemu.c
|
||||
checkseekhole_SOURCES = checkseekhole.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
AM_CPPFLAGS = \
|
||||
@@ -281,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 Free Software Foundation, Inc.
|
||||
# Copyright 2013-2023 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
@@ -19,7 +19,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([-C in file lists])
|
||||
AT_KEYWORDS([files-from T-cd])
|
||||
AT_KEYWORDS([files-from T-cd chdir])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
46
tests/T-dir00.at
Normal file
46
tests/T-dir00.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2014-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Tar 1.27 and 1.28 did not extract files under directory members listed
|
||||
# in the file read by --file-from.
|
||||
#
|
||||
# Reported-by: Jean-Louis Martineau <martineau@zmanda.com>
|
||||
# References: <541AE02C.2050008@zmanda.com>,
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2014-09/msg00006.html
|
||||
|
||||
AT_SETUP([recursive extraction from --files-from])
|
||||
AT_KEYWORDS([files-from extract T-dir T-dir00])
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir dir
|
||||
genfile -f dir/file1
|
||||
genfile -f dir/file2
|
||||
tar cf archive dir
|
||||
rm -rf dir
|
||||
echo dir > list
|
||||
tar xfTv archive list | sort
|
||||
],
|
||||
[0],
|
||||
[dir/
|
||||
dir/file1
|
||||
dir/file2
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
46
tests/T-dir01.at
Normal file
46
tests/T-dir01.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2014-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU tar.
|
||||
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Tar 1.27 and 1.28 did not remove trailing slashes from file names
|
||||
# obtained with the --file-from option.
|
||||
#
|
||||
# Reported-by: Jean-Louis Martineau <martineau@zmanda.com>
|
||||
# References: <541AE02C.2050008@zmanda.com>,
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2014-09/msg00006.html
|
||||
|
||||
AT_SETUP([trailing slash in --files-from])
|
||||
AT_KEYWORDS([files-from extract T-dir T-dir01])
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir dir
|
||||
genfile -f dir/file1
|
||||
genfile -f dir/file2
|
||||
tar cf archive dir
|
||||
rm -rf dir
|
||||
echo dir/ > list
|
||||
tar xfTv archive list | sort
|
||||
],
|
||||
[0],
|
||||
[dir/
|
||||
dir/file1
|
||||
dir/file2
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2006-2007, 2013-2014 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 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 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 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,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2006-2007, 2013-2014 Free Software Foundation, Inc.
|
||||
# Copyright 2006-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