Compare commits
371 Commits
release_1_
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
b500277de7 | ||
|
|
002bf86821 | ||
|
|
fcde08534b | ||
|
|
a5db4ba5cb | ||
|
|
20ab569dc3 | ||
|
|
f86e0605d0 | ||
|
|
4423e1743e | ||
|
|
8d087fbb0b | ||
|
|
dc72f4d114 | ||
|
|
576e99a21c | ||
|
|
fc58a8bd98 | ||
|
|
7808b6981b | ||
|
|
852895847f | ||
|
|
b0902369e7 | ||
|
|
da546e69af | ||
|
|
f24b30ec8c | ||
|
|
93906c238d | ||
|
|
9df17e6005 | ||
|
|
efbf4cce0b | ||
|
|
7fe7adcbb9 | ||
|
|
8e10d93d01 | ||
|
|
3cb4693c65 | ||
|
|
48a546b02c | ||
|
|
46da9968df | ||
|
|
29a6964af3 | ||
|
|
62497f0e26 | ||
|
|
c86b0c2149 | ||
|
|
8b6a1a5990 | ||
|
|
8cfcbfddd4 | ||
|
|
e9e94531f0 | ||
|
|
288dd472e3 | ||
|
|
8706301479 | ||
|
|
45ccda1193 | ||
|
|
1689ed4388 | ||
|
|
2af87fa277 | ||
|
|
95a51b93d0 | ||
|
|
f504821589 | ||
|
|
a09e840507 | ||
|
|
eb7e2aa933 | ||
|
|
717a07e208 | ||
|
|
f0a1f78196 | ||
|
|
7f21a4d3f5 | ||
|
|
2bd9c15391 | ||
|
|
481572c63f | ||
|
|
47da28892e | ||
|
|
5c5f62e0dc | ||
|
|
49f3145092 | ||
|
|
ca8cb48d02 | ||
|
|
b4afdd0e28 | ||
|
|
6e8bca8b56 | ||
|
|
00054440c7 | ||
|
|
a2e0cd0c05 | ||
|
|
f6c25db5fe | ||
|
|
6d5cfeb757 | ||
|
|
3de5db2a15 | ||
|
|
db9b81eb6b | ||
|
|
f3c8bc7c3f | ||
|
|
576e1fcd6a | ||
|
|
3125d311e1 | ||
|
|
74ce228f6d | ||
|
|
d28eee6b4f | ||
|
|
d3fd92c6fb | ||
|
|
f7077dd38b | ||
|
|
5cb79ed519 | ||
|
|
b41b004638 | ||
|
|
e3d28d84bd | ||
|
|
2c06a80918 | ||
|
|
570a2c5f3d | ||
|
|
b6979c7278 | ||
|
|
751b61ab25 | ||
|
|
738fb9c2f4 | ||
|
|
0ea6e68655 | ||
|
|
dd549cc257 | ||
|
|
28b44aaacb | ||
|
|
88cb5008a6 | ||
|
|
bff9c3637d | ||
|
|
1fe0c83de4 | ||
|
|
077d7bceff | ||
|
|
162bbcb45f | ||
|
|
69007e652a | ||
|
|
95d7b37a34 | ||
|
|
ddff3e9038 | ||
|
|
47560a0498 | ||
|
|
6e5e4420f4 | ||
|
|
26538c9bfc | ||
|
|
8a834dfa10 | ||
|
|
cf199be81d | ||
|
|
cfebb3cedf | ||
|
|
87369861f9 | ||
|
|
f547c0332d | ||
|
|
57e5a7a1e7 | ||
|
|
f678e47eb0 | ||
|
|
f92cb1fe16 | ||
|
|
beca89bccb | ||
|
|
a40e565719 | ||
|
|
17f99bc6f1 | ||
|
|
7b5e803963 | ||
|
|
20dcc4d122 | ||
|
|
9cf743abf8 | ||
|
|
2f6c03cba2 | ||
|
|
cd7bdd4076 | ||
|
|
d99ecd6c75 | ||
|
|
53358983eb | ||
|
|
7c43775f4f | ||
|
|
df7b55a8f6 | ||
|
|
d8ac237663 | ||
|
|
f39eadac4b | ||
|
|
8ebbef8a15 | ||
|
|
616e421350 | ||
|
|
cbc51277aa | ||
|
|
8c0146d2c9 | ||
|
|
4bfa82acd5 | ||
|
|
d350b509c0 | ||
|
|
383701a590 | ||
|
|
545e4cd69d | ||
|
|
a974e9c997 | ||
|
|
4a3564fe85 | ||
|
|
6bd463c97e | ||
|
|
3c4e51fad6 | ||
|
|
4ac671c49b | ||
|
|
085cace180 | ||
|
|
d36f5a3cc3 | ||
|
|
696338043e | ||
|
|
b997c90f9e | ||
|
|
643a8844a5 | ||
|
|
099f71f78d | ||
|
|
07ef59cab8 | ||
|
|
0708c153e4 | ||
|
|
1cd2725227 | ||
|
|
6a61354ea0 | ||
|
|
273dfb16cc | ||
|
|
2a61a3701f | ||
|
|
5bb0433507 | ||
|
|
8c75b1387a | ||
|
|
debc485626 | ||
|
|
6689e8db4f | ||
|
|
9a82a0215b | ||
|
|
03858cf583 | ||
|
|
7a5a3708cb | ||
|
|
02bf3a96a9 | ||
|
|
79138eaef1 | ||
|
|
d88b2a613f | ||
|
|
1e1fc0336b | ||
|
|
02533d1a60 | ||
|
|
d0dd0473f7 | ||
|
|
8f70a3294c | ||
|
|
a6cc856fbe | ||
|
|
51b272f572 | ||
|
|
1f9b376c90 | ||
|
|
9fe65e2520 | ||
|
|
fa307a6655 | ||
|
|
49bd102a1b | ||
|
|
189e436474 | ||
|
|
9708b248e8 | ||
|
|
afcdb89492 | ||
|
|
aea443b9e8 | ||
|
|
881e5626c5 | ||
|
|
67ae04ba31 | ||
|
|
2807513841 | ||
|
|
bb0af96c54 | ||
|
|
ec586b37e0 | ||
|
|
a7fc5ecead | ||
|
|
649b747913 | ||
|
|
bb971a1e8a | ||
|
|
50a57a0147 | ||
|
|
1584b72ff2 | ||
|
|
065cf0958c | ||
|
|
2a55b4b037 | ||
|
|
27225be1a3 | ||
|
|
73d0d1a0f8 | ||
|
|
ff2bc5c0a1 | ||
|
|
24214ca5d5 | ||
|
|
777042e024 | ||
|
|
1801399830 | ||
|
|
ecd700fbfb | ||
|
|
f1fed3996a | ||
|
|
b32edff5aa | ||
|
|
3913675640 | ||
|
|
b8feb2b142 | ||
|
|
3fe59ed5ef | ||
|
|
5af29cb944 | ||
|
|
7dd57ebdfa | ||
|
|
e23d123b93 | ||
|
|
6398c7a79c | ||
|
|
28e91b48f6 | ||
|
|
3c0bedd494 | ||
|
|
c520964e84 | ||
|
|
acb77ac5bd | ||
|
|
983113b140 | ||
|
|
9447e799ab | ||
|
|
502abd93bd | ||
|
|
241b72ffad | ||
|
|
c5c196310e | ||
|
|
14efeb9f95 | ||
|
|
efe26f98ec | ||
|
|
4bde4f39d0 | ||
|
|
fc5e44c99c | ||
|
|
098ad10c71 | ||
|
|
6e08ab7694 | ||
|
|
cecb7ac8e6 | ||
|
|
ea964cce81 | ||
|
|
e3fdb78d4b | ||
|
|
d945888643 | ||
|
|
ecbcb7b6d7 | ||
|
|
59146768ef | ||
|
|
0fb3020da0 | ||
|
|
d7db30d0e8 | ||
|
|
8da503cad6 | ||
|
|
c743301494 | ||
|
|
de328a580a | ||
|
|
bad4b0006c | ||
|
|
e985feb292 | ||
|
|
fbc54fa337 | ||
|
|
45a574151a | ||
|
|
0adf4027f5 | ||
|
|
fce1c1c8cb | ||
|
|
372ac37d01 | ||
|
|
a9895fd20c | ||
|
|
a59c819beb | ||
|
|
57b11473b0 | ||
|
|
fbcadc9592 | ||
|
|
3b219f943e | ||
|
|
37ddfb0b7e | ||
|
|
09f039050e | ||
|
|
34795cedb7 | ||
|
|
9764a6b1d3 | ||
|
|
a1a15e3202 | ||
|
|
0ab5e64ac0 | ||
|
|
0a694a16e5 | ||
|
|
b3b15f7cbc | ||
|
|
8c662c9f29 | ||
|
|
427b3b8c79 | ||
|
|
c1b30c268f | ||
|
|
cc40c57a37 | ||
|
|
ab6dd4948d | ||
|
|
b4bcb97e38 | ||
|
|
9c194c9942 | ||
|
|
80a6ef7d94 | ||
|
|
9b31db388e | ||
|
|
f6edb92580 | ||
|
|
e21d54e8cd | ||
|
|
c79f0d06bc | ||
|
|
2c97cb7ea2 | ||
|
|
fc61c17410 | ||
|
|
2981fcc5cb | ||
|
|
40dea1ae7f | ||
|
|
b60e56fdb6 | ||
|
|
340dbf5aab | ||
|
|
c1d3d13493 | ||
|
|
67b4f3519d | ||
|
|
0ba8bdf5f3 | ||
|
|
8d3cc6c3cf | ||
|
|
3f4a6d83f0 | ||
|
|
a3f1d933cc |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -24,8 +24,7 @@ config.log
|
||||
config.status
|
||||
configure
|
||||
gnu
|
||||
gnulib
|
||||
libtool
|
||||
m4
|
||||
paxutils
|
||||
rmt
|
||||
stamp-h1
|
||||
|
||||
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
|
||||
18
COPYING
18
COPYING
@@ -1,12 +1,11 @@
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
@@ -69,7 +68,7 @@ patents cannot be used to render the program non-free.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
@@ -77,7 +76,7 @@ modification follow.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
@@ -510,7 +509,7 @@ actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
@@ -619,9 +618,9 @@ an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@@ -673,4 +672,3 @@ may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
|
||||
21
ChangeLog.1
21
ChangeLog.1
@@ -1,26 +1,23 @@
|
||||
Currently there is just one ChangeLog file for tar, but
|
||||
Currently there is just one ChangeLog file for tar, but
|
||||
there used to be separate ChangeLog files for each subdirectory.
|
||||
This file records what used to be in those separate files.
|
||||
|
||||
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1989-1997, 2013 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Tar.
|
||||
This file is part of GNU tar.
|
||||
|
||||
GNU Tar is free software; you can redistribute it and/or modify
|
||||
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 2, or (at your option)
|
||||
any later version.
|
||||
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,
|
||||
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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
----- ChangeLog -----
|
||||
@@ -3189,7 +3186,7 @@ Boston, MA 02110-1301, USA.
|
||||
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.
|
||||
|
||||
113
ChangeLog.CVS
113
ChangeLog.CVS
@@ -1,3 +1,24 @@
|
||||
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.
|
||||
|
||||
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/>.
|
||||
|
||||
2009-03-05 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/incremen.c: --no-recursive works with --incremental.
|
||||
@@ -5,7 +26,7 @@
|
||||
2009-03-04 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
Add xz support.
|
||||
|
||||
|
||||
* src/buffer.c, src/suffix.c: Add support for xz compression.
|
||||
* src/tar.c: New option --xz, for compression/decompression using xz.
|
||||
Re-assign -J as a short equivalent of --xz.
|
||||
@@ -34,8 +55,8 @@
|
||||
2008-11-25 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
Do not try to drain the input pipe before closing the
|
||||
archive.
|
||||
|
||||
archive.
|
||||
|
||||
* src/buffer.c (close_archive): Remove call to
|
||||
sys_drain_input_pipe. Pass hit_eof as the second
|
||||
argument to sys_wait_for_child.
|
||||
@@ -63,7 +84,7 @@
|
||||
* src/extract.c (extract_link, extract_symlink): Remove calls to
|
||||
transform_member_name. It is done in read_header.
|
||||
* src/list.c (decode_xform): Reflect change in data type of 2nd
|
||||
argument.
|
||||
argument.
|
||||
(transform_member_name): 2nd arg is int.
|
||||
(decode_header): Transform file name and link target names.
|
||||
* src/tar.c: Remove --transform-symlinks.
|
||||
@@ -73,7 +94,7 @@
|
||||
set global flags using `flags=' syntax.
|
||||
(_transform_name_to_obstack, transform_name_fp)
|
||||
(transform_name): Take an additional argument, specifying scope
|
||||
flags.
|
||||
flags.
|
||||
|
||||
2008-10-19 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -86,7 +107,7 @@
|
||||
* tests/sparsemvp.at: Likewise.
|
||||
* tests/volsize.at: Likewise.
|
||||
* NEWS: Update.
|
||||
|
||||
|
||||
2008-10-16 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/common.h (transform_symlinks_option): New global.
|
||||
@@ -99,11 +120,11 @@
|
||||
* doc/tar.texi: Document --transform-symlinks
|
||||
* NEWS: Update.
|
||||
* THANKS: Update.
|
||||
|
||||
|
||||
* src/names.c (name_gather): Use xzalloc.
|
||||
* src/buffer.c (short_read): Move record size detection before
|
||||
the loop.
|
||||
|
||||
|
||||
2008-10-07 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/tar.c (options): Add --lzop option.
|
||||
@@ -111,7 +132,7 @@
|
||||
2008-10-05 Xavier Hienne <xavier.hienne@free.fr> (tiny change)
|
||||
|
||||
* src/checkpoint.c (checkpoint_compile_action): Add missing
|
||||
`else'.
|
||||
`else'.
|
||||
|
||||
2008-09-24 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -157,7 +178,7 @@
|
||||
* tests/atlocal.in (decho): New function.
|
||||
* tests/multiv06.at: Use decho instead of echo2.
|
||||
* tests/incremental.at: Raise wait interval to 2 seconds.
|
||||
|
||||
|
||||
2008-07-24 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/tar.c (decode_options): Do not allow volume length less
|
||||
@@ -193,21 +214,21 @@
|
||||
tests/longv7.at, tests/lustar01.at, tests/lustar02.at,
|
||||
tests/shortfile.at: Update to match new diagnostic wording
|
||||
(see 2008-05-06).
|
||||
|
||||
|
||||
* NEWS: Update.
|
||||
|
||||
2008-06-14 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi (exclude): Document support for new VCS.
|
||||
* THANKS: Update.
|
||||
* NEWS: Update.
|
||||
* NEWS: Update.
|
||||
* tests/multiv05.at: Fix typos.
|
||||
* tests/volsize.at: Remove a TZ dependency.
|
||||
|
||||
|
||||
2008-06-14 Dan Drake <dan@dandrake.org> (tiny change)
|
||||
|
||||
* src/tar.c (exclude_vcs_files): Support for Bazaar, Mercurial and
|
||||
Darcs.
|
||||
Darcs.
|
||||
|
||||
2008-05-06 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -231,23 +252,23 @@
|
||||
* tests/incr03.at, tests/incr04.at, tests/rename02.at,
|
||||
tests/rename03.at: Insert calls to sleep between creation of files
|
||||
and adding them to the archive.
|
||||
|
||||
|
||||
2008-03-31 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/create.c (dump_file0): Count links only for actually dumped
|
||||
files.
|
||||
files.
|
||||
|
||||
2008-03-27 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* NEWS: Document --no-check-device and --check-device.
|
||||
* doc/rendition.texi: Change the way FIXME-*refs are handled in
|
||||
!PROOF.
|
||||
!PROOF.
|
||||
* doc/intern.texi, doc/tar.texi: Update.
|
||||
* doc/untabify.el: New file.
|
||||
* doc/Makefile.am (EXTRA_DIST): Add untabify.el
|
||||
(untabify, final, check-format, check-refs, check-fixmes)
|
||||
(check-unrevised, all-check-docs, check-docs): New rules.
|
||||
|
||||
|
||||
* src/common.h (check_device_option): New global.
|
||||
* src/incremen.c (procdir): Use boolean and instead of bitwise
|
||||
one. Patch by Jean-Louis Martineau.
|
||||
@@ -256,7 +277,7 @@
|
||||
--check-device. Proposed by Jean-Louis Martineau.
|
||||
(parse_opt): Hanlde new options.
|
||||
(decode_options): Initialize check_device_option to true.
|
||||
|
||||
|
||||
* THANKS: Update
|
||||
|
||||
2008-03-06 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
@@ -267,7 +288,7 @@
|
||||
* po/.cvsignore: Update
|
||||
* src/system.c: Remove include setenv.h.
|
||||
* tests/atlocal.in (STAR_DATA_URL): Update.
|
||||
* tests/star/README: Update URL.
|
||||
* tests/star/README: Update URL.
|
||||
|
||||
2008-02-09 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -303,7 +324,7 @@
|
||||
Exit with nonzero status if a close fails on an archive.
|
||||
Problem (and initial trivial fix)
|
||||
* src/buffer.c (close_archive, new_volume): close_error, not
|
||||
close_warn.
|
||||
close_warn.
|
||||
|
||||
2007-12-05 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -1007,7 +1028,7 @@
|
||||
this has undefined behavior. Likewise for assigning arbitrary
|
||||
uintmax_t values to other types.
|
||||
(read_negative_num, read_unsigned_num, read_timespec):
|
||||
New functions, to check input values a bit more carefuly.
|
||||
New functions, to check input values a bit more carefully.
|
||||
(read_num): Use read_unsigned_num. New arg MAX_VAL;
|
||||
all callers changed.
|
||||
(read_incr_db_2): Use these new functions.
|
||||
@@ -1187,7 +1208,7 @@
|
||||
* src/delete.c: Remove second argument from calls to name_scan
|
||||
* src/update.c: Likewise
|
||||
* src/incremen.c (procdir): Use is_individual_file to check for
|
||||
files explicitely specified in the command line. Fixes bug
|
||||
files explicitly specified in the command line. Fixes bug
|
||||
reported by Dat Head on 19 Jun 2006 (descending into mountpoints
|
||||
with --one-file-system in use)
|
||||
* src/misc.c (maybe_backup_file): Second argument is bool
|
||||
@@ -1246,7 +1267,7 @@
|
||||
* src/delete.c (records_skipped): Remove static qualifier, the
|
||||
variable is used by print_total_stats in buffer.c
|
||||
* src/extract.c (check_time): Use volume_start_time when checking
|
||||
for timestamp plausability.
|
||||
for timestamp plausibility.
|
||||
* src/tar.c: (options, parse_opt): Allow for optional argument to
|
||||
the --totals option, which specifies a signal upon delivery of which
|
||||
the statistics must be output.
|
||||
@@ -1304,7 +1325,7 @@
|
||||
|
||||
* src/transform.c (set_transform_expr,_transform_name_to_obstack):
|
||||
Implement NUMBER flag.
|
||||
(add_char_segment): Fix length assignement
|
||||
(add_char_segment): Fix length assignment
|
||||
|
||||
* doc/tar.texi: Update
|
||||
|
||||
@@ -1361,7 +1382,7 @@
|
||||
* doc/tar.texi: Update
|
||||
* configure.ac (AM_INIT_AUTOMAKE): Use tar-ustar option. Raise
|
||||
version requirement to 1.9
|
||||
* src/common.h (struct name): Refactured
|
||||
* src/common.h (struct name): Refactored
|
||||
(warn_regex_usage): New variable.
|
||||
(dump_file): First argument is const char*.
|
||||
(name_init,name_add): Removed
|
||||
@@ -1736,13 +1757,13 @@
|
||||
* src/common.h (struct name): New member `explicit'. Remove unused
|
||||
member `isdir'.
|
||||
* src/incremen.c (procdir): If name_scan() returns something,
|
||||
check if it was explicitely given in the command line
|
||||
check if it was explicitly given in the command line
|
||||
* src/names.c (addname,add_hierarchy_to_namelist): Initialize
|
||||
explicit member appropriately.
|
||||
|
||||
* src/incremen.c (procdir): If --one-file-system is given and a
|
||||
directory is found to be on another device, *and* this directory
|
||||
is explicitely given in the command line, then do not omit it.
|
||||
is explicitly given in the command line, then do not omit it.
|
||||
|
||||
2005-12-11 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -1777,7 +1798,7 @@
|
||||
(mode_to_chars, off_to_chars, size_to_chars, time_to_chars)
|
||||
(uid_to_chars, uintmax_to_chars): Return bool
|
||||
(to_chars): Return bool
|
||||
(start_header): Check return values of convertion routines. Fail
|
||||
(start_header): Check return values of conversion routines. Fail
|
||||
if unable to store data in the header.
|
||||
|
||||
2005-12-07 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
@@ -2077,13 +2098,13 @@
|
||||
archives.
|
||||
* src/incremen.c (dumpdir_size, get_gnu_dumpdir): New functions.
|
||||
(purge_directory): Use stat_info.dumpdir instead of getting its
|
||||
value explicitely.
|
||||
value explicitly.
|
||||
* src/list.c (list_archive): Handle incremental backups in pax
|
||||
format.
|
||||
(decode_header): Initialize stat_info.dumpdir
|
||||
* src/sparse.c (sparse_diff_file): Bugfix: set seekable.
|
||||
(pax_dump_header): Store sparse map in GNU.sparse.map. If this
|
||||
variable has been explicitely deleted, use GNU.sparse.offset/
|
||||
variable has been explicitly deleted, use GNU.sparse.offset/
|
||||
GNU.sparse.numbytes variables.
|
||||
* src/tar.c (decode_options): Incremental options are allowed with
|
||||
--format=pax
|
||||
@@ -2161,7 +2182,7 @@
|
||||
|
||||
* bootstrap: Fix quoting in help output.
|
||||
(update_po): Use backward-compatible wget option --cache instead
|
||||
of deprecated -C to accomodate for wget 1.10.
|
||||
of deprecated -C to accommodate for wget 1.10.
|
||||
Changes proposed by Eric Blake
|
||||
* THANKS: Add Eric Blake
|
||||
|
||||
@@ -2712,7 +2733,7 @@
|
||||
* src/list.c: Likewise
|
||||
|
||||
* tests/multiv03.at: Modified to match the new behavior
|
||||
* tests/multiv04.at: New file. Test splittind directory members between
|
||||
* tests/multiv04.at: New file. Test splitting directory members between
|
||||
the archive volumes.
|
||||
* tests/Makefile.am: Add multiv04.at
|
||||
* tests/testsuite.at: Likewise.
|
||||
@@ -4466,7 +4487,7 @@
|
||||
|
||||
* src/create.c: Do not zero-terminate name field if
|
||||
the name is exactly 100 characters long.
|
||||
(write_ustar_long_name): Fixed cheking for unsplittable
|
||||
(write_ustar_long_name): Fixed checking for unsplittable
|
||||
names.
|
||||
|
||||
2003-11-14 Sergey Poznyakoff <gray@Mirddin.farlep.net>
|
||||
@@ -5163,7 +5184,7 @@
|
||||
interface.
|
||||
(child_open_for_compress): Do not increase size to BLOCKSIZE.
|
||||
(open_archive): Open index file name.
|
||||
Strip trailing slahes from file names.
|
||||
Strip trailing slashes from file names.
|
||||
(flush_write): Set size to 0 if not saving names.
|
||||
(flush_write, flush_read): Use safer_name_suffix rather than
|
||||
inline code.
|
||||
@@ -5996,7 +6017,7 @@
|
||||
(decode_options): Dates that look like an absolute path name,
|
||||
or that start with '.', are presumed to be file names whose
|
||||
dates are taken.
|
||||
Remove 'I' as an aliase for 'T'.
|
||||
Remove 'I' as an alias for 'T'.
|
||||
Update copyright.
|
||||
|
||||
* src/extract.c (<time.h>): Do not include; system.h now does this.
|
||||
@@ -8806,26 +8827,6 @@
|
||||
See ChangeLog.1 for earlier changes.
|
||||
|
||||
-----
|
||||
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007
|
||||
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, 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 GNU tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
|
||||
Local Variables:
|
||||
mode: change-log
|
||||
|
||||
70
ChangeLog.amend
Normal file
70
ChangeLog.amend
Normal file
@@ -0,0 +1,70 @@
|
||||
# Fix typos in tar ChangeLog entries generated from git log
|
||||
|
||||
f24b30ec8ca1851b7bd14694241de3b38194c99c
|
||||
s/commit 2bd9c153_\./commit 2bd9c153)./
|
||||
|
||||
29a6964af3e1baabe978ce608e0466e1250d08ab
|
||||
s/ORDER \(none, name, or order\)\./ORDER (none, name, or inode)./
|
||||
|
||||
2af87fa2776c8125a587a9b0c2c4fae3bf921ff7
|
||||
s/contant\./content./
|
||||
|
||||
2bd9c15391b0bd6ef0bff76aebf09cfb53003199
|
||||
s/ocurrence/occurrence/
|
||||
|
||||
47da28892e6860a3a6fc06745f640e3bb878c757
|
||||
s/aruond/around/
|
||||
|
||||
f7077dd38b018f19d3a5c7df6accc6b07b8a2356
|
||||
s/absoulte/absolute/
|
||||
|
||||
28b44aaacb45680aa6640e0a6d7ceab04cfdbf11
|
||||
s/warniing/warning/
|
||||
|
||||
47560a0498bde20621ce4e367b1d68bf8cd8f1a3
|
||||
s/interacton/interaction/
|
||||
|
||||
26538c9bfc5fd726d625bef5fa3f08212d50173a
|
||||
s/consuption/consumption/;
|
||||
s/misfunctioned/malfunctioned/;
|
||||
s/misssing/missing/;
|
||||
|
||||
696338043e52f440853e1143c52b81b41cd59723
|
||||
s/suuport/support/
|
||||
|
||||
643a8844a578ff146cfe746fe6091d29502b6c40
|
||||
s/incrfental/incremental/;
|
||||
s/afterwards/afterward/;
|
||||
|
||||
03858cf583ce299b836d8a848967ce290a6bf303
|
||||
s/Peformance/Performance/
|
||||
|
||||
fa307a665545753b6729191fd2559ce872fa470a
|
||||
s/filags/flags/
|
||||
|
||||
73d0d1a0f883be5f67534362c99382f1eae8d178
|
||||
s/contais/contains/
|
||||
|
||||
5af29cb944c84e2d539ce9df527d63c29f6012b9
|
||||
s/appendig/appending/
|
||||
|
||||
7dd57ebdfa9ac0d2af4622449f45b5025f6c184f
|
||||
s/encounted/encountered/
|
||||
|
||||
ecbcb7b6d74c2d69386c8d7e435486a4690c9993
|
||||
s/inadvertantly/inadvertently/
|
||||
|
||||
4dfcd6c054a5e9e1a371c822a3be90564dd9b690
|
||||
s/succesfully/successfully/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
35
Makefile.am
35
Makefile.am
@@ -1,32 +1,32 @@
|
||||
# Main Makefile for GNU tar.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2007,
|
||||
# 2009 Free Software Foundation, Inc.
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2007, 2009, 2013-2014, 2016-2017
|
||||
# Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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/>.
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = ChangeLog.1 Make.rules
|
||||
SUBDIRS = doc gnu lib rmt src scripts po tests
|
||||
|
||||
dist-hook:
|
||||
dist-hook:
|
||||
$(MAKE) changelog_dir=$(distdir) ChangeLog
|
||||
-rm -f $(distdir).cpio
|
||||
find $(distdir) | cpio -Hcrc -o | \
|
||||
GZIP=$(GZIP_ENV) gzip -c > $(distdir).cpio.gz
|
||||
eval GZIP= gzip $(GZIP_ENV) -c > $(distdir).cpio.gz
|
||||
|
||||
distclean-local:
|
||||
-rm -f $(distdir).cpio.gz
|
||||
@@ -36,5 +36,4 @@ include Make.rules
|
||||
gen_start_date = 2009-03-06
|
||||
prev_change_log = ChangeLog.CVS
|
||||
changelog_dir = .
|
||||
|
||||
|
||||
changelog_amend_file=ChangeLog.amend
|
||||
|
||||
620
NEWS
620
NEWS
@@ -1,6 +1,449 @@
|
||||
GNU tar NEWS - User visible changes. 2010-03-10
|
||||
GNU tar NEWS - User visible changes. 2017-12-17
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
|
||||
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
|
||||
|
||||
* New checkpoint action: totals
|
||||
|
||||
The --checkpoint-action=totals option instructs tar to output the
|
||||
total number of bytes transferred at each checkpoint.
|
||||
|
||||
* Extended checkpoint format specification.
|
||||
|
||||
New conversion specifiers are implemented. Some of them take
|
||||
optional arguments, supplied in curly braces between the percent
|
||||
sign and the specifier letter.
|
||||
|
||||
%d - Number of seconds since tar started.
|
||||
%{r,w,d}T - I/O totals; optional arguments supply prefixes
|
||||
to be used before number of bytes read, written and
|
||||
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
|
||||
current screen width, if {N} is not given.
|
||||
%c - A shortcut for "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r"
|
||||
|
||||
* New option --one-top-level
|
||||
|
||||
The option --one-top-level tells tar to extract all files into a
|
||||
subdirectory named by the base name of the archive (minus standard
|
||||
compression suffixes recognizable by --auto-compress). When used with
|
||||
an argument, as in --one-top-level=DIR, the files are extracted into the
|
||||
supplied DIRectory. This ensures that no archive members are
|
||||
extracted outside of the specified directory, even if the archive is
|
||||
crafted so as to put them elsewhere.
|
||||
|
||||
* New option --sort
|
||||
|
||||
The --sort=ORDER option instructs tar to sort directory entries
|
||||
according to ORDER. It takes effect when creating archives.
|
||||
Available ORDERs are: none (the default), name and inode. The
|
||||
latter may be absent, if the underlying system does not provide
|
||||
the necessary information.
|
||||
|
||||
Using --sort=name ensures the member ordering in the created archive
|
||||
is uniform and reproducible. Using --sort=inode reduces the number
|
||||
of disk seeks made when creating the archive and thus can considerably
|
||||
speed up archivation.
|
||||
|
||||
* New exclusion options
|
||||
|
||||
--exclude-ignore=FILE Before dumping a directory check if it
|
||||
contains FILE, and if so read exclude
|
||||
patterns for this directory from FILE.
|
||||
--exclude-ignore-recursive=FILE
|
||||
Same as above, but the exclusion patterns
|
||||
read from FILE remain in effect for any
|
||||
subdirectory, recursively.
|
||||
--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.
|
||||
|
||||
* Manpages
|
||||
|
||||
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
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Fix unquoting of file names obtained via the -T option.
|
||||
|
||||
* Fix GNU long link header timestamp (backward compatibility).
|
||||
|
||||
* Fix extracting sparse members from star archives.
|
||||
|
||||
|
||||
version 1.27 - Sergey Poznyakoff, 2013-10-05
|
||||
|
||||
* Bug fixes
|
||||
|
||||
** Sparse files with large data
|
||||
|
||||
When creating a PAX-format archive, tar no longer arbitrarily restricts
|
||||
the size of the representation of a sparse file to be less than 8 GiB.
|
||||
|
||||
* Quoting
|
||||
|
||||
In the default C locale, diagnostics and output of 'tar' have been
|
||||
adjusted to quote 'like this' (with apostrophes) instead of `like this'
|
||||
(with an accent grave character and an apostrophe). This tracks
|
||||
recent changes to the GNU coding standards.
|
||||
|
||||
* --owner and --group names and numbers
|
||||
|
||||
The --owner and --group options now accept operands of the form
|
||||
NAME:NUM, so that you can specify both symbolic name and numeric ID
|
||||
for owner and group. In these options, NAME no longer needs to be
|
||||
present in the current host's user and group databases.
|
||||
|
||||
* The --keep-old-files and --skip-old-files options.
|
||||
|
||||
This release restores the traditional functionality of the
|
||||
--keep-old-files. This option causes tar to avoid replacing
|
||||
existing files while extracting and to treat such files as errors.
|
||||
Tar will emit a prominent error message upon encountering such files
|
||||
and will exit with code 2 when finished extracting the archive.
|
||||
|
||||
A new option --skip-old-files is introduced, which acts exactly as
|
||||
--keep-old-files, except that it does not treat existing files as
|
||||
errors. Instead it just silently skips them. An additional level of
|
||||
verbosity can be obtained by using the option --warning=existing-file
|
||||
together with this option.
|
||||
|
||||
* Support for POSIX ACLs, extended attributes and SELinux context.
|
||||
|
||||
Starting with this version tar is able to store, extract and list
|
||||
extended file attributes, POSIX.1e ACLs and SELinux context. This is
|
||||
controlled by the command line options --xattrs, --acls and --selinux,
|
||||
correspondingly. Each of these options has a `--no-' counterpart
|
||||
(e.g. --no-xattrs), which disables the corresponding feature.
|
||||
Additionally, the options --xattrs-include and --xattrs-exclude allow
|
||||
you to selectively control for which files to store (or extract) the
|
||||
extended attributes.
|
||||
|
||||
* Passing command line arguments to external commands.
|
||||
|
||||
Any option taking a command name as its argument now accepts a full
|
||||
command line as well. Thus, it is now possible to pass additional
|
||||
arguments to invoked programs. The affected options are:
|
||||
|
||||
--checkpoint-action=exec
|
||||
-I, --use-compress-program
|
||||
-F, --info-script
|
||||
--to-command
|
||||
|
||||
Furthermore, if any additional information is supplied to such a
|
||||
command via environment variables, these variables can now be used in
|
||||
the command line itself. Care should be taken to escape them, to
|
||||
prevent from being expanded too early, for example:
|
||||
|
||||
tar -x -f a.tar --info-script='changevol $TAR_ARCHIVE $TAR_VOLUME'
|
||||
|
||||
* New configure option --enable-gcc-warnings, intended for debugging.
|
||||
|
||||
* New warning control option --warning=[no-]record-size
|
||||
|
||||
On extraction, this option controls whether to display actual record
|
||||
size, if it differs from the default.
|
||||
|
||||
* New command line option --keep-directory-symlink
|
||||
|
||||
By default, if trying to extract a directory from the archive,
|
||||
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.
|
||||
|
||||
It is mainly intended to provide compatibility with the Slackware
|
||||
installation scripts.
|
||||
|
||||
|
||||
version 1.26 - Sergey Poznyakoff, 2011-03-12
|
||||
|
||||
* Bugfixes
|
||||
|
||||
** Fix the --verify option, which broke in version 1.24.
|
||||
|
||||
** Fix storing long sparse file names in PAX archives.
|
||||
|
||||
** Fix correctness of --atime-preserve=replace
|
||||
|
||||
tar --atime-preserve=replace no longer tries to restore atime of
|
||||
zero-sized files.
|
||||
|
||||
** Work around POSIX incompatibilities on FreeBSD, NetBSD and Tru64
|
||||
|
||||
** Fix bug with --one-file-system --listed-incremental
|
||||
|
||||
When invoked with these two options, tar 1.25 would add only the
|
||||
top-level directory to the archive, but not its contents.
|
||||
|
||||
|
||||
version 1.25 - Sergey Poznyakoff, 2010-11-07
|
||||
|
||||
* Fix extraction of empty directories with the -C option in effect.
|
||||
* Fix extraction of device nodes.
|
||||
* Make sure name matching occurs before eventual name transformation.
|
||||
|
||||
Tar 1.24 changed the ordering of name matching and name transformation
|
||||
so that the former saw already transformed file names. This made it
|
||||
impossible to match file names in certain cases. It is fixed now.
|
||||
|
||||
* Fix the behavior of tar -x --overwrite on hosts lacking O_NOFOLLOW.
|
||||
|
||||
* Improve the testsuite.
|
||||
|
||||
* Alternative decompression programs.
|
||||
|
||||
If extraction from a compressed archive fails because the corresponding
|
||||
compression program is not installed and the following two conditions
|
||||
are met, tar retries extraction using an alternative decompressor:
|
||||
|
||||
1. Another compression program supported by tar is able to handle this
|
||||
compression format.
|
||||
2. The compression program was not explicitly requested in the command
|
||||
line by the use of such options as -z, -j, etc.
|
||||
|
||||
For example, if 'compress' is not available, tar will try 'gzip'.
|
||||
|
||||
|
||||
version 1.24 - Sergey Poznyakoff, 2010-10-24
|
||||
|
||||
* The --full-time option.
|
||||
|
||||
New command line option '--full-time' instructs tar to output file
|
||||
time stamps to the full resolution.
|
||||
|
||||
* Bugfixes.
|
||||
|
||||
** More reliable directory traversal when creating archives
|
||||
|
||||
Tar now checks for inconsistencies caused when a file system is
|
||||
modified while tar is creating an archive. In the new approach, tar
|
||||
maintains a cache of file descriptors to directories, so it uses more
|
||||
file descriptors than before, but it adjusts to system limits on
|
||||
the number of file descriptors. Tar also takes more care when
|
||||
a file system is modified while tar is extracting from an archive.
|
||||
|
||||
The new checks are implemented via the openat and related calls
|
||||
standardized by POSIX.1-2008. On an older system where these calls do
|
||||
not exist or do not return useful results, tar emulates the calls at
|
||||
some cost in efficiency and reliability.
|
||||
|
||||
** Symbolic link attributes
|
||||
|
||||
When extracting symbolic links, tar now restores attributes such as
|
||||
last-modified time and link permissions, if the operating system
|
||||
supports this. For example, recent versions of the Linux kernel
|
||||
support setting times on symlinks, and some BSD kernels also support
|
||||
symlink permissions.
|
||||
|
||||
** --dereference consistency
|
||||
|
||||
The --dereference (-h) option now applies to files that are copied
|
||||
into or out of archives, independently of other options. For example,
|
||||
if F is a symbolic link and archive.tar contains a regular-file member
|
||||
also named F, "tar --overwrite -x -f archive.tar F" now overwrites F
|
||||
itself, rather than the file that F points to. (To overwrite the file
|
||||
that F points to, add the --dereference (-h) option.) Formerly,
|
||||
--dereference was intended to apply only when using the -c option, but
|
||||
the implementation was not consistent.
|
||||
|
||||
Also, the --dereference option no longer affects accesses to other
|
||||
files, such as archives and time stamp files. Symbolic links to these
|
||||
files are always followed. Previously, the links were usually but not
|
||||
always followed.
|
||||
|
||||
** Spurious error diagnostics on broken pipe.
|
||||
|
||||
When receiving SIGPIPE, tar would exit with error status and
|
||||
"write error" diagnostics. In particular, this occurred if
|
||||
invoked as in the example below:
|
||||
|
||||
tar tf archive.tar | head -n 1
|
||||
|
||||
** --remove-files
|
||||
|
||||
'tar --remove-files' failed to remove a directory which contained
|
||||
symlinks to another files within that directory.
|
||||
|
||||
** --test-label behavior
|
||||
|
||||
In case of a mismatch, 'tar --test-label LABEL' exits with code 1,
|
||||
not 2 as it did in previous versions.
|
||||
|
||||
The '--verbose' option used with '--test-label' provides additional
|
||||
diagnostics.
|
||||
|
||||
Several volume labels may be specified in a command line, e.g.:
|
||||
|
||||
tar --test-label -f archive 'My volume' 'New volume' 'Test volume'
|
||||
|
||||
In this case, tar exits with code 0 if any one of the arguments
|
||||
matches the actual volume label.
|
||||
|
||||
** --label used with --update
|
||||
|
||||
The '--label' option can be used with '--update' to prevent accidental
|
||||
update of an archive:
|
||||
|
||||
tar -rf archive --label 'My volume' .
|
||||
|
||||
This did not work in previous versions, in spite of what the docs said.
|
||||
|
||||
** --record-size and --tape-length (-L) options
|
||||
|
||||
Usual size suffixes are allowed for these options. For example,
|
||||
-L10k stands for a 10 kilobyte tape length.
|
||||
|
||||
** Fix dead loop on extracting existing symlinks with the -k option.
|
||||
|
||||
|
||||
version 1.23 - Sergey Poznyakoff, 2010-03-10
|
||||
|
||||
@@ -15,28 +458,28 @@ to regular files and pipes).
|
||||
When a read-only operation (e.g. --list or --extract) is requested
|
||||
on a regular file, tar attemtps to speed up accesses by using lseek.
|
||||
|
||||
* New command line option `--warning'
|
||||
* New command line option '--warning'
|
||||
|
||||
The `--warning' command line option allows to suppress or enable
|
||||
particular warning messages during `tar' run. It takes a single
|
||||
argument (a `keyword'), identifying the class of warning messages
|
||||
to affect. If the argument is prefixed with `no-', such warning
|
||||
The '--warning' command line option allows to suppress or enable
|
||||
particular warning messages during 'tar' run. It takes a single
|
||||
argument (a 'keyword'), identifying the class of warning messages
|
||||
to affect. If the argument is prefixed with 'no-', such warning
|
||||
messages are suppressed. For example,
|
||||
|
||||
tar --warning=no-alone-zero-block -x -f archive
|
||||
|
||||
suppresses the output of `A lone zero block' diagnostics, which is
|
||||
normally issued if `archive' ends with a single block of zeros.
|
||||
suppresses the output of "A lone zero block" diagnostics, which is
|
||||
normally issued if 'archive' ends with a single block of zeros.
|
||||
|
||||
See Tar Manual, section 3.9 "Controlling Warning Messages", for a
|
||||
detailed discussion.
|
||||
|
||||
* New command line option `--level'
|
||||
* New command line option '--level'
|
||||
|
||||
The `--level=N' option sets the incremental dump level N. It
|
||||
The '--level=N' option sets the incremental dump level N. It
|
||||
is valid when used in conjunction with the -c and --listed-incremental
|
||||
options. So far the only meaningful value for N is 0. The
|
||||
`--level=0' option forces creating the level 0 dump, by truncating
|
||||
'--level=0' option forces creating the level 0 dump, by truncating
|
||||
the snapshot file if it exists.
|
||||
|
||||
* Files removed during incremental dumps
|
||||
@@ -62,28 +505,28 @@ 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).
|
||||
the Epoch or a "Time reference" (see below).
|
||||
|
||||
Modification times in ustar header blocks of global extended
|
||||
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).
|
||||
the Epoch or a "Time reference" (see below).
|
||||
|
||||
* Time references in --pax-option argument.
|
||||
|
||||
Any value from the --pax-option argument that is enclosed in a pair
|
||||
of curly braces represents a time reference. The string between the
|
||||
of curly braces represents a time reference. The string between the
|
||||
braces is understood either as a textual time representation, as described in
|
||||
chapter 7, "Date input formats", of the Tar manual, or as a name of
|
||||
an existing file, starting with `/' or `.'. In the latter
|
||||
an existing file, starting with '/' or '.'. In the latter
|
||||
case, it is replaced with the modification time of that file.
|
||||
|
||||
* Environment of --to-command script.
|
||||
@@ -114,14 +557,14 @@ version 1.22 - Sergey Poznyakoff, 2009-03-05
|
||||
|
||||
* Support for xz compression
|
||||
|
||||
Tar uses xz for compression if one of the following conditions is met:
|
||||
Tar uses xz for compression if one of the following conditions is met:
|
||||
|
||||
1. The option --xz or -J (see below) is used.
|
||||
2. The xz binary is set as compressor using --use-compress-program option.
|
||||
3. The file name of the archive being created ends in `.xz' and
|
||||
3. The file name of the archive being created ends in '.xz' and
|
||||
auto-compress option (-a) is used.
|
||||
|
||||
Xz is used for decompression if one of the following conditions is met:
|
||||
Xz is used for decompression if one of the following conditions is met:
|
||||
|
||||
1. The option --xz or -J is used.
|
||||
2. The xz binary is set as compressor using --use-compress-program option.
|
||||
@@ -174,21 +617,21 @@ control type of archive members affected by them. The flags are:
|
||||
- s
|
||||
Apply transformation to symbolic link targets.
|
||||
|
||||
- h
|
||||
- h
|
||||
Apply transformation to hard link targets.
|
||||
|
||||
Corresponding upper-case letters negate the meaning, so that
|
||||
`H' means ``do not apply transformation to hard link targets.''
|
||||
'H' means "do not apply transformation to hard link targets".
|
||||
|
||||
The scope flags are listed in the third part of an `s' expression,
|
||||
The scope flags are listed in the third part of an 's' expression,
|
||||
e.g.:
|
||||
|
||||
tar --transform 's|^|/usr/local/|S'
|
||||
|
||||
Default is `rsh', which means that transformations are applied to
|
||||
Default is 'rsh', which means that transformations are applied to
|
||||
both regular archive members and to the targets of symbolic and hard
|
||||
links. If several transform expressions are used, the default flags
|
||||
can be changed using `flags=' statement before the expressions, e.g.:
|
||||
can be changed using 'flags=' statement before the expressions, e.g.:
|
||||
|
||||
tar --transform 'flags=S;s|^|/usr/local/|S'
|
||||
|
||||
@@ -196,10 +639,10 @@ can be changed using `flags=' statement before the expressions, e.g.:
|
||||
|
||||
** The --null option disabled handling of tar options in list files. This
|
||||
is fixed.
|
||||
** Fixed record size autodetection. If detected record size differs from
|
||||
the expected value (either default, or set on the command line), tar
|
||||
always prints a warning if verbosity level is set to 1 or greater,
|
||||
i.e. if either -t or -v option is given.
|
||||
** Fixed record size autodetection. If the detected record size differs from
|
||||
the expected value (either default one, or the one set from the
|
||||
command line), tar always prints a warning if verbosity level is set
|
||||
to 1 or greater, i.e. if either -t or -v option is given.
|
||||
|
||||
|
||||
|
||||
@@ -224,36 +667,36 @@ they refer to, instead of creating usual hard link members (type '1').
|
||||
This action allows to specify an action to be executed upon hitting a
|
||||
checkpoint. Recognized actions are: dot, echo (the default),
|
||||
echo=string, ttyout=string, exec=cmdline, and sleep=value. Any number
|
||||
of `--checkpoint-action' options can be specified, the actions will be
|
||||
of '--checkpoint-action' options can be specified, the actions will be
|
||||
executed in order of their appearance in the command line. See
|
||||
chapter 3.8 "Checkpoints" for a complete description.
|
||||
|
||||
* New options --no-check-device, --check-device.
|
||||
|
||||
The `--no-check-device' option disables comparing device numbers during
|
||||
The '--no-check-device' option disables comparing device numbers during
|
||||
preparatory stage of an incremental dump. This allows to avoid
|
||||
creating full dumps if the device numbers change (e.g. when using an
|
||||
LVM snapshot).
|
||||
|
||||
The `--check-device' option enables comparing device numbers. This is
|
||||
The '--check-device' option enables comparing device numbers. This is
|
||||
the default. This option is provided to undo the effect of the previous
|
||||
`--no-check-device' option, e.g. if it was set in TAR_OPTIONS
|
||||
'--no-check-device' option, e.g. if it was set in TAR_OPTIONS
|
||||
environment variable.
|
||||
|
||||
* The --transform option.
|
||||
|
||||
Any number of `--transform' options can be given in the command line.
|
||||
Any number of '--transform' options can be given in the command line.
|
||||
The specified transformations will be applied in turn.
|
||||
|
||||
The argument to `--transform' option can be a list of replace
|
||||
expressions, separated by a semicolon (as in `sed').
|
||||
The argument to '--transform' option can be a list of replace
|
||||
expressions, separated by a semicolon (as in 'sed').
|
||||
|
||||
Filename transformations are applied to symbolic link targets
|
||||
during both creation and extraction. Tar 1.19 used them only
|
||||
during extraction.
|
||||
|
||||
For a detailed description, see chapter 6.7 "Modifying File and Member
|
||||
Names".
|
||||
Names".
|
||||
|
||||
* Info (end-of-volume) scripts
|
||||
|
||||
@@ -280,8 +723,8 @@ control systems, e.g. "CVS/", ".svn/", etc.
|
||||
|
||||
The following options now work with incremental archives as well:
|
||||
|
||||
--exclude-caches
|
||||
--exclude-caches-all
|
||||
--exclude-caches
|
||||
--exclude-caches-all
|
||||
--exclude-tag
|
||||
--exclude-tag-all
|
||||
--exclude-tag-under
|
||||
@@ -292,14 +735,14 @@ Previous versions always stored absolute file names in rename
|
||||
records, even if -P was not used. This is fixed: rename records
|
||||
contain file names processed in accordance with the command line
|
||||
settings.
|
||||
|
||||
|
||||
* Fix --version output.
|
||||
|
||||
* Recognition of broken archives.
|
||||
|
||||
When supplied an archive smaller than 512 bytes in reading mode (-x,
|
||||
-t), the previous version of tar silently ignored it, exiting with
|
||||
code 0. It is fixed. Tar now issues the following diagnostic message:
|
||||
code 0. It is fixed. Tar now issues the following diagnostic message:
|
||||
'This does not look like a tar archive', and exits with code 2.
|
||||
|
||||
* Fix double-dot recognition in archive member names in case of duplicate '/.'.
|
||||
@@ -332,7 +775,7 @@ option affects hard and soft link targets and the --strip-components
|
||||
option affects hard link targets as well.
|
||||
|
||||
* End-of-volume script can send the new volume name to tar by writing
|
||||
it to the file descriptor stored in the environment variable `TAR_FD'.
|
||||
it to the file descriptor stored in the environment variable TAR_FD.
|
||||
|
||||
|
||||
version 1.16.1 - Sergey Poznyakoff, 2006-12-09
|
||||
@@ -402,7 +845,7 @@ following command line options:
|
||||
--wildcards use wildcards
|
||||
--anchored patterns match file name start
|
||||
--ignore-case ignore case
|
||||
--wildcards-match-slash wildcards match `/'
|
||||
--wildcards-match-slash wildcards match '/'
|
||||
|
||||
Each of these options has a '--no-' counterpart that disables its
|
||||
effect (e.g. --no-wildcards).
|
||||
@@ -442,7 +885,7 @@ or archive. It generalizes --show-stored-names option, introduced in
|
||||
1.15.90. In particular, when creating an archive in verbose mode, it lists
|
||||
member names as stored in the archive, i.e., with any eventual prefixes
|
||||
removed and file name transformations applied. The option is useful,
|
||||
for example, while comparing `tar cv' and `tar tv' outputs.
|
||||
for example, while comparing 'tar cv' and 'tar tv' outputs.
|
||||
|
||||
** New incremental snapshot file format keeps information about file names
|
||||
as well as that about directories.
|
||||
@@ -467,7 +910,7 @@ version 1.15.90 - Sergey Poznyakoff, 2006-02-19
|
||||
* New features
|
||||
|
||||
** Any number of -T (--files-from) options may be used in the command line.
|
||||
The file specified with -T may include any valid `tar' options,
|
||||
The file specified with -T may include any valid 'tar' options,
|
||||
including another -T option.
|
||||
Compatibility note: older versions of tar would only recognize -C
|
||||
as an option name within the file list file. Now any file whose name
|
||||
@@ -478,7 +921,7 @@ dash, use the --add-file option.
|
||||
automatically. It is no longer necessary to give the --null option.
|
||||
|
||||
** New option --no-unquote disables the unquoting of input file names.
|
||||
This is useful for processing output from `find dir -print0'.
|
||||
This is useful for processing output from 'find dir -print0'.
|
||||
An orthogonal option --unquote is provided as well.
|
||||
|
||||
** New option --test-label tests the archive volume label.
|
||||
@@ -492,7 +935,7 @@ tar prints the label name if present and exits with code 0.
|
||||
** New option --show-stored-names. When creating an archive in verbose mode,
|
||||
it lists member names as stored in the archive, i.e., with any eventual
|
||||
prefixes removed. The option is useful, for example, while comparing
|
||||
`tar cv' and `tar tv' outputs.
|
||||
'tar cv' and 'tar tv' outputs.
|
||||
|
||||
** New option --to-command pipes the contents of archive members to the
|
||||
specified command.
|
||||
@@ -565,7 +1008,7 @@ version 1.15 - Sergey Poznyakoff, 2004-12-20
|
||||
|
||||
* Compressed archives are recognised automatically, it is no longer
|
||||
necessary to specify -Z, -z, or -j options to read them. Thus, you can
|
||||
now run `tar tf archive.tar.gz'.
|
||||
now run 'tar tf archive.tar.gz'.
|
||||
|
||||
* When restoring incremental dumps, --one-file-system option
|
||||
prevents directory hierarchies residing on different devices
|
||||
@@ -585,7 +1028,7 @@ seeks.
|
||||
* Restore script starts restoring only if it is given --all (-a) option,
|
||||
or some patterns. This is to prevent accidental restores.
|
||||
|
||||
* `tar --verify' prints a warning if during archive creation some of
|
||||
* 'tar --verify' prints a warning if during archive creation some of
|
||||
the file names had their prefixes stripped off.
|
||||
|
||||
* New option --exclude-caches instructs tar to exclude cache directories
|
||||
@@ -595,11 +1038,11 @@ containing a standardized tag file, as specified at:
|
||||
http://www.brynosaurus.com/cachedir/spec.html
|
||||
|
||||
* New configure option --with-rmt allows to specify full path name to
|
||||
the `rmt' utility. This supersedes DEFAULT_RMT_COMMAND variable
|
||||
the 'rmt' utility. This supersedes DEFAULT_RMT_COMMAND variable
|
||||
introduced in version 1.14
|
||||
|
||||
* New configure variable DEFAULT_RMT_DIR allows to specify the directory
|
||||
where to install `rmt' utility. This is necessary since modifying
|
||||
where to install 'rmt' utility. This is necessary since modifying
|
||||
--libexecdir as was suggested for version 1.14 produced a side effect: it
|
||||
also modified installation prefix for backup scripts (if
|
||||
--enable-backup-scripts was given).
|
||||
@@ -653,12 +1096,12 @@ version 1.14 - Sergey Poznyakoff, 2004-05-11
|
||||
the subcommands --delete, --diff, --extract or --list when a list of
|
||||
files is given either on the command line or via -T option. This
|
||||
option instructs tar to process only the Nth occurrence of each named
|
||||
file. N defaults to 1, so `tar -x -f archive --occurrence filename'
|
||||
extracts the first occurrence of `filename' from `archive'
|
||||
file. N defaults to 1, so 'tar -x -f archive --occurrence filename'
|
||||
extracts the first occurrence of 'filename' from 'archive'
|
||||
and terminates without scanning to the end of the archive.
|
||||
|
||||
* New option --pax-option allows to control the handling of POSIX
|
||||
keywords in `pax' extended headers. It is equivalent to `pax'
|
||||
keywords in 'pax' extended headers. It is equivalent to 'pax'
|
||||
-o option.
|
||||
|
||||
* --incremental and --listed-incremental options work correctly on
|
||||
@@ -764,7 +1207,7 @@ version 1.13.19 - Paul Eggert, 2001-01-13
|
||||
|
||||
version 1.13.18 - Paul Eggert, 2000-10-29
|
||||
|
||||
* Some security problems have been fixed. `tar -x' now modifies only
|
||||
* Some security problems have been fixed. 'tar -x' now modifies only
|
||||
files under the working directory, unless you also specify an unsafe
|
||||
option like --absolute-names or --overwrite.
|
||||
|
||||
@@ -790,12 +1233,12 @@ version 1.13.18 - Paul Eggert, 2000-10-29
|
||||
* This version of tar works best with GNU gzip test version 1.3 or later.
|
||||
Please see <ftp://alpha.gnu.org/gnu/gzip/>.
|
||||
|
||||
* `tar --delete -f -' now works again.
|
||||
* 'tar --delete -f -' now works again.
|
||||
|
||||
|
||||
version 1.13.17 - Paul Eggert, 2000-01-07.
|
||||
|
||||
* `tar --delete -f -' is no longer allowed; it was too buggy.
|
||||
* 'tar --delete -f -' is no longer allowed; it was too buggy.
|
||||
* Diagnostic messages have been made more regular and consistent.
|
||||
|
||||
|
||||
@@ -812,12 +1255,12 @@ version 1.13.16 - Paul Eggert, 1999-12-13.
|
||||
The new --overwrite option enables the old default behavior.
|
||||
|
||||
For regular files, tar implements this change by using the O_EXCL
|
||||
option of `open' to ensure that it creates the file; if this fails, it
|
||||
option of 'open' to ensure that it creates the file; if this fails, it
|
||||
removes the file and tries again. This is similar to the behavior of
|
||||
the --unlink-first option, but it is faster in the common case of
|
||||
extracting a new directory.
|
||||
|
||||
* By default, tar now ignores file names containing a component of `..'
|
||||
* By default, tar now ignores file names containing a component of '..'
|
||||
when extracting, and warns about such file names when creating an archive.
|
||||
To enable the old behavior, use the -P or --absolute-names option.
|
||||
|
||||
@@ -859,20 +1302,20 @@ version 1.13.14 - Paul Eggert, 1999-11-07.
|
||||
version 1.13.13 - Paul Eggert, 1999-10-11.
|
||||
|
||||
* Invalid headers in tar files now elicit errors, not just warnings.
|
||||
* `tar --version' output conforms to the latest GNU coding standards.
|
||||
* If you specify an invalid date, `tar' now substitutes (time_t) -1.
|
||||
* `configure --with-dmalloc' is no longer available.
|
||||
* 'tar --version' output conforms to the latest GNU coding standards.
|
||||
* If you specify an invalid date, 'tar' now substitutes (time_t) -1.
|
||||
* 'configure --with-dmalloc' is no longer available.
|
||||
|
||||
|
||||
version 1.13.12 - Paul Eggert, 1999-09-24.
|
||||
|
||||
* `tar' now supports hard links to symbolic links.
|
||||
* 'tar' now supports hard links to symbolic links.
|
||||
|
||||
* New options --no-same-owner, --no-same-permissions.
|
||||
|
||||
* --total now also outputs a human-readable size, and a throughput value.
|
||||
|
||||
* `tar' now uses two's-complement base-256 when outputting header
|
||||
* 'tar' now uses two's-complement base-256 when outputting header
|
||||
values that are out of the range of the standard unsigned base-8
|
||||
format. This affects archive members with negative or huge time
|
||||
stamps or uids, and archive members 8 GB or larger. The new tar
|
||||
@@ -881,12 +1324,12 @@ version 1.13.12 - Paul Eggert, 1999-09-24.
|
||||
behavior, which uses unportable representations for negative values,
|
||||
and which rejects large files.
|
||||
|
||||
* On 32-bit hosts, `tar' now assumes that an incoming time stamp T in
|
||||
* On 32-bit hosts, 'tar' now assumes that an incoming time stamp T in
|
||||
the range 2**31 <= T < 2**32 represents the negative time (T -
|
||||
2**32). This behavior is nonstandard and is not portable to 64-bit
|
||||
time_t hosts, so `tar' issues a warning.
|
||||
time_t hosts, so 'tar' issues a warning.
|
||||
|
||||
* `tar' no longer gives up extracting immediately upon discovering
|
||||
* 'tar' no longer gives up extracting immediately upon discovering
|
||||
that an archive contains garbage at the end. It attempts to extract
|
||||
as many files as possible from the good data before the garbage.
|
||||
|
||||
@@ -903,40 +1346,40 @@ version 1.13.11 - Paul Eggert, 1999-08-23.
|
||||
* -T /dev/null now matches nothing; previously, it matched anything
|
||||
if no explicit operands were given.
|
||||
|
||||
* The `--' option now works the same as with other GNU utilities;
|
||||
* The '--' option now works the same as with other GNU utilities;
|
||||
it causes later operands to be interpreted as file names, not options,
|
||||
even if they begin with `-'.
|
||||
even if they begin with '-'.
|
||||
|
||||
* For the --newer and --after-date options, the table of time zone
|
||||
abbreviations like `EST' has been updated to match current practice.
|
||||
abbreviations like 'EST' has been updated to match current practice.
|
||||
Also, local time abbreviations are now recognized, even if they are
|
||||
not in tar's hardwired table. Remember, though, that you should use
|
||||
numeric UTC offsets like `-0500' instead of abbreviations like
|
||||
`EST', as abbreviations are not standardized and are ambiguous.
|
||||
numeric UTC offsets like '-0500' instead of abbreviations like
|
||||
'EST', as abbreviations are not standardized and are ambiguous.
|
||||
|
||||
|
||||
version 1.13.10 - Paul Eggert, 1999-08-20.
|
||||
|
||||
* `tar' now uses signed base-64 when outputting header values that are
|
||||
* 'tar' now uses signed base-64 when outputting header values that are
|
||||
out of the range of the standard unsigned base-8 format. [This
|
||||
change was superseded in 1.13.12, described above.]
|
||||
|
||||
|
||||
version 1.13.9 - Paul Eggert, 1999-08-18.
|
||||
|
||||
* `tar' now writes two zero blocks at end-of-archive instead of just one.
|
||||
POSIX.1 requires this, and some other `tar' implementations check for it.
|
||||
* 'tar' now writes two zero blocks at end-of-archive instead of just one.
|
||||
POSIX.1 requires this, and some other 'tar' implementations check for it.
|
||||
|
||||
* `tar' no longer silently accepts a block containing nonzero checksum bytes
|
||||
* 'tar' no longer silently accepts a block containing nonzero checksum bytes
|
||||
as a zero block.
|
||||
|
||||
* `tar' now reads buggy tar files that have a null byte at the start of a
|
||||
* 'tar' now reads buggy tar files that have a null byte at the start of a
|
||||
numeric header field.
|
||||
|
||||
|
||||
version 1.13.8 - Paul Eggert, 1999-08-16.
|
||||
|
||||
* For compatibility with traditional `tar', intermediate directories
|
||||
* For compatibility with traditional 'tar', intermediate directories
|
||||
created automatically by root are no longer given the uid and gid of
|
||||
the original file or directory.
|
||||
|
||||
@@ -945,7 +1388,7 @@ version 1.13.7 - Paul Eggert, 1999-08-14.
|
||||
|
||||
* --listed-incremental and --newer are now incompatible options.
|
||||
|
||||
* When creating an archive, leading `./' is no longer stripped,
|
||||
* When creating an archive, leading './' is no longer stripped,
|
||||
to match traditional tar's behavior (and simplify the documentation).
|
||||
|
||||
* --diff without --absolute-names no longer falls back on absolute names.
|
||||
@@ -1036,7 +1479,7 @@ Creation
|
||||
* Implement --numeric-owner for ignoring symbolic names at create time.
|
||||
* New --owner, --group --mode options, still preliminary.
|
||||
* Recognize creating an archive on /dev/null, so Amanda works faster.
|
||||
* Object to the creation of an empty archive (like in `tar cf FILE').
|
||||
* Object to the creation of an empty archive (like in 'tar cf FILE').
|
||||
* Barely start implementing --posix and POSIXLY_CORRECT.
|
||||
|
||||
Extraction
|
||||
@@ -1115,7 +1558,7 @@ Version 1.10.13 - 1992-01.
|
||||
|
||||
* Now uses GNU standard configure, generated by Autoconf.
|
||||
|
||||
* Long options now use `--'; use of `+' is deprecated and support
|
||||
* Long options now use '--'; use of '+' is deprecated and support
|
||||
for it will eventually be removed.
|
||||
|
||||
* New option --null causes filenames read by -T to be
|
||||
@@ -1144,8 +1587,8 @@ the various tape drives will get used in sequence and then wrap
|
||||
around to the beginning.
|
||||
|
||||
* Remote archive names no longer have to be in /dev: any file with a
|
||||
`:' is interpreted as remote. If new option --force-local is given,
|
||||
then even archive files with a `:' are considered local.
|
||||
':' is interpreted as remote. If new option --force-local is given,
|
||||
then even archive files with a ':' are considered local.
|
||||
|
||||
* New option --atime-preserve restores (if possible) atimes to
|
||||
their original values after dumping the file.
|
||||
@@ -1198,15 +1641,14 @@ Versions 1.07 back to 1.00 by Jay Fenlason.
|
||||
|
||||
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003,
|
||||
2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1994-2001, 2003-2010, 2013-2017 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, or (at your option)
|
||||
any later version.
|
||||
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
|
||||
@@ -1214,9 +1656,7 @@ 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 tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Local variables:
|
||||
mode: outline
|
||||
|
||||
134
README
134
README
@@ -4,31 +4,30 @@ See the end of file for copying conditions.
|
||||
* Introduction
|
||||
|
||||
Please glance through *all* sections of this
|
||||
`README' file before starting configuration. Also make sure you read files
|
||||
`ABOUT-NLS' and `INSTALL' if you are not familiar with them already.
|
||||
'README' file before starting configuration. Also make sure you read files
|
||||
'ABOUT-NLS' and 'INSTALL' if you are not familiar with them already.
|
||||
|
||||
If you got the `tar' distribution in `shar' format, time stamps ought to be
|
||||
properly restored; do not ignore such complaints at `unshar' time.
|
||||
If you got the 'tar' distribution in 'shar' format, time stamps ought to be
|
||||
properly restored; do not ignore such complaints at 'unshar' time.
|
||||
|
||||
GNU `tar' saves many files together into a single tape or disk
|
||||
GNU 'tar' saves many files together into a single tape or disk
|
||||
archive, and can restore individual files from the archive. It includes
|
||||
multivolume support, the ability to archive sparse files, automatic archive
|
||||
compression/decompression, remote archives and special features that allow
|
||||
`tar' to be used for incremental and full backups. This distribution
|
||||
also includes `rmt', the remote tape server. The `mt' tape drive control
|
||||
program is in the GNU `cpio' distribution.
|
||||
'tar' to be used for incremental and full backups. This distribution
|
||||
also includes 'rmt', the remote tape server. The 'mt' tape drive control
|
||||
program is in the GNU 'cpio' distribution.
|
||||
|
||||
GNU `tar' is derived from John Gilmore's public domain `tar'.
|
||||
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.
|
||||
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 'NEWS' for a list of major changes in the current release.
|
||||
See file 'THANKS' for a list of contributors.
|
||||
|
||||
Besides those configure options documented in files `INSTALL' and
|
||||
`ABOUT-NLS', an extra option may be accepted after `./configure':
|
||||
Besides those configure options documented in files 'INSTALL' and
|
||||
'ABOUT-NLS', an extra option may be accepted after './configure':
|
||||
|
||||
* Install
|
||||
|
||||
@@ -40,11 +39,11 @@ values are GNU, V7, OLDGNU, USTAR and POSIX.
|
||||
|
||||
** Selecting the default archive device
|
||||
|
||||
The default archive device is now `stdin' on read and `stdout' on write.
|
||||
The installer can still override this by presetting `DEFAULT_ARCHIVE'
|
||||
in the environment before configuring (the behavior of `-[0-7]' or
|
||||
`-[0-7]lmh' options in `tar' are then derived automatically). Similarly,
|
||||
`DEFAULT_BLOCKING' can be preset to something else than 20.
|
||||
The default archive device is now 'stdin' on read and 'stdout' on write.
|
||||
The installer can still override this by presetting 'DEFAULT_ARCHIVE'
|
||||
in the environment before configuring (the behavior of '-[0-7]' or
|
||||
'-[0-7]lmh' options in 'tar' are then derived automatically). Similarly,
|
||||
'DEFAULT_BLOCKING' can be preset to something else than 20.
|
||||
|
||||
** Selecting full pathname of the "rmt" binary.
|
||||
|
||||
@@ -76,13 +75,13 @@ directory.
|
||||
Use option --enable-backup-scripts to compile and install these
|
||||
scripts.
|
||||
|
||||
** `--disable-largefile' omits support for large files, even if the
|
||||
** '--disable-largefile' omits support for large files, even if the
|
||||
operating system supports large files. Typically, large files are
|
||||
those larger than 2 GB on a 32-bit host.
|
||||
|
||||
* Installation hints
|
||||
|
||||
Here are a few hints which might help installing `tar' on some systems.
|
||||
Here are a few hints which might help installing 'tar' on some systems.
|
||||
|
||||
** gzip and bzip2.
|
||||
|
||||
@@ -103,7 +102,7 @@ then you have encountered a gzip incompatibility that should be fixed
|
||||
in gzip test version 1.3, which as of this writing is available at
|
||||
<ftp://alpha.gnu.org/gnu/gzip/>. You can work around the
|
||||
incompatibility by using a shell command like
|
||||
`gzip -d <file.tar.gz | tar -xzf -'.
|
||||
'gzip -d <file.tar.gz | tar -xzf -'.
|
||||
|
||||
** Solaris issues.
|
||||
|
||||
@@ -118,13 +117,13 @@ understand these headers.
|
||||
|
||||
** Static linking.
|
||||
|
||||
Some platform will, by default, prepare a smaller `tar' executable
|
||||
which depends on shared libraries. Since GNU `tar' may be used for
|
||||
Some platform will, by default, prepare a smaller 'tar' executable
|
||||
which depends on shared libraries. Since GNU 'tar' may be used for
|
||||
system-level backups and disaster recovery, installers might prefer to
|
||||
force static linking, making a bigger `tar' executable maybe, but able to
|
||||
force static linking, making a bigger 'tar' executable maybe, but able to
|
||||
work standalone, in situations where shared libraries are not available.
|
||||
The way to achieve static linking varies between systems. Set LDFLAGS
|
||||
to a value from the table below, before configuration (see `INSTALL').
|
||||
to a value from the table below, before configuration (see 'INSTALL').
|
||||
|
||||
Platform Compiler LDFLAGS
|
||||
|
||||
@@ -137,18 +136,18 @@ to a value from the table below, before configuration (see `INSTALL').
|
||||
Solaris (vendor) -Bstatic
|
||||
SunOS (vendor) -Bstatic
|
||||
|
||||
** Failed tests `ignfail.sh' or `incremen.sh'.
|
||||
** Failed tests 'ignfail.sh' or 'incremen.sh'.
|
||||
|
||||
In an NFS environment, lack of synchronization between machine clocks
|
||||
might create difficulties to any tool comparing dates and file time stamps,
|
||||
like `tar' in incremental dumps. This has been a recurrent problem with
|
||||
like 'tar' in incremental dumps. This has been a recurrent problem with
|
||||
GNU Make for the last few years. We would like a general solution.
|
||||
|
||||
** BSD compatibility matters.
|
||||
|
||||
Set LIBS to `-lbsd' before configuration (see `INSTALL') if the linker
|
||||
complains about `bsd_ioctl' (Slackware). Also set CPPFLAGS to
|
||||
`-I/usr/include/bsd' if <sgtty.h> is not found (Slackware).
|
||||
Set LIBS to '-lbsd' before configuration (see 'INSTALL') if the linker
|
||||
complains about 'bsd_ioctl' (Slackware). Also set CPPFLAGS to
|
||||
'-I/usr/include/bsd' if <sgtty.h> is not found (Slackware).
|
||||
|
||||
** OPENStep 4.2 swap files
|
||||
|
||||
@@ -159,43 +158,43 @@ the simplest workaround is to avoid tarring this file.
|
||||
|
||||
* Special topics
|
||||
|
||||
Here are a few special matters about GNU `tar', not related to build
|
||||
Here are a few special matters about GNU 'tar', not related to build
|
||||
matters. See previous section for such.
|
||||
|
||||
** File attributes.
|
||||
|
||||
About *security*, it is probable that future releases of `tar' will have
|
||||
About *security*, it is probable that future releases of 'tar' will have
|
||||
some behavior changed. There are many pending suggestions to choose from.
|
||||
Today, extracting an archive not being `root', `tar' will restore suid/sgid
|
||||
bits on files but owned by the extracting user. `root' automatically gets
|
||||
a lot of special privileges, `-p' might later become required to get them.
|
||||
Today, extracting an archive not being 'root', 'tar' will restore suid/sgid
|
||||
bits on files but owned by the extracting user. 'root' automatically gets
|
||||
a lot of special privileges, '-p' might later become required to get them.
|
||||
|
||||
GNU `tar' does not properly restore symlink attributes. Various systems
|
||||
GNU 'tar' does not properly restore symlink attributes. Various systems
|
||||
implement flavors of symbolic links showing different behavior and
|
||||
properties. We did not successfully sorted all these out yet. Currently,
|
||||
the `lchown' call will be used if available, but that's all.
|
||||
the 'lchown' call will be used if available, but that's all.
|
||||
|
||||
** POSIX compliance.
|
||||
|
||||
GNU `tar' is able to create archive in the following formats:
|
||||
GNU 'tar' is able to create archive in the following formats:
|
||||
|
||||
*** The format of UNIX version 7
|
||||
*** POSIX.1-1988 format, also known as "ustar format"
|
||||
*** POSIX.1-1988 format, also known as "ustar format"
|
||||
*** POSIX.1-2001 format, also known as "pax format"
|
||||
*** Old GNU format (described below)
|
||||
|
||||
In addition to those, GNU `tar' is also able to read archives
|
||||
produced by `star' archiver.
|
||||
In addition to those, GNU 'tar' is also able to read archives
|
||||
produced by 'star' archiver.
|
||||
|
||||
A so called `Old GNU' format is based on an early draft of the
|
||||
POSIX 1003.1 `ustar' standard which is different from the final
|
||||
A so called 'Old GNU' format is based on an early draft of the
|
||||
POSIX 1003.1 'ustar' standard which is different from the final
|
||||
standard. It defines its extensions (such as incremental backups
|
||||
and handling of the long file names) in a way incompatible with
|
||||
any existing tar archive format, therefore the use of old GNU
|
||||
format is strongly discouraged.
|
||||
format is strongly discouraged.
|
||||
|
||||
Please read the file NEWS for more information about POSIX compliance
|
||||
and new `tar' features.
|
||||
and new 'tar' features.
|
||||
|
||||
* What's next?
|
||||
|
||||
@@ -216,36 +215,39 @@ to the report address; rather take special arrangement with the maintainer.
|
||||
|
||||
Your feedback will help us to make a better and more portable package.
|
||||
Consider documentation errors as bugs, and report them as such. If you
|
||||
develop anything pertaining to `tar' or have suggestions, let us know
|
||||
develop anything pertaining to 'tar' or have suggestions, let us know
|
||||
and share your findings by writing to <bug-tar@gnu.org>.
|
||||
|
||||
|
||||
* Copying
|
||||
|
||||
Copyright (C) 1990, 1991, 1992, 1994, 1997, 1998, 1999, 2000,
|
||||
2001, 2003, 2004, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1990-1992, 1994, 1997-2001, 2003-2004, 2007, 2012-2014,
|
||||
2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
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.
|
||||
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 tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
NOTE ON COPYRIGHT YEARS
|
||||
|
||||
In copyright notices where the copyright holder is the Free Software
|
||||
Foundation, then where a range of years appears, this is an inclusive
|
||||
range that applies to every year in the range. For example: 2005-2008
|
||||
represents the years 2005, 2006, 2007, and 2008.
|
||||
|
||||
Local Variables:
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
version-control: never
|
||||
End:
|
||||
|
||||
|
||||
54
README-alpha
54
README-alpha
@@ -23,53 +23,27 @@ 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.
|
||||
Before building the package, run "bootstrap". It will obtain gnulib
|
||||
and paxutils files from their Git repositories on Savannah. Then, it will
|
||||
fetch the po files from tar page at Translation Project, and, finally, it
|
||||
will start autoconfiguration process. Simply running bootstrap without
|
||||
arguments should do in most cases.
|
||||
|
||||
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.
|
||||
Bootstrap reads its configuration from file bootstrap.conf located on the
|
||||
top of tar source tree. Several options are provided that modify its
|
||||
behavior. Run 'bootstrap --help' for a list.
|
||||
|
||||
|
||||
|
||||
Copyright (C) 2001, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2001, 2003-2005, 2007, 2013-2017 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, or (at your option)
|
||||
any later version.
|
||||
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
|
||||
@@ -77,6 +51,4 @@ 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 tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -6,20 +6,19 @@ this package.
|
||||
You need the following packages to build the Git version of GNU
|
||||
tar. We do not make any efforts to accommodate older versions of
|
||||
these packages, so please make sure that you have the latest stable
|
||||
version.
|
||||
version.
|
||||
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Autoconf <http://www.gnu.org/software/autoconf/>
|
||||
- M4 <http://www.gnu.org/software/m4/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Gnulib <http://www.gnu.org/software/gnulib>
|
||||
- Git <http://git.or.cz>
|
||||
|
||||
* Bootstrapping
|
||||
|
||||
Obviously, if you are reading these notes, you did manage to clone
|
||||
tar from Git. The next step is to get other files needed to build,
|
||||
which are extracted from other source packages:
|
||||
which are extracted from other source packages:
|
||||
|
||||
1. Change to the source tree directory
|
||||
|
||||
@@ -27,39 +26,35 @@ which are extracted from other source packages:
|
||||
|
||||
2. Run
|
||||
|
||||
./bootstrap
|
||||
./bootstrap
|
||||
|
||||
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:
|
||||
|
||||
--gnulib-srcdir=$HOME/gnulib
|
||||
|
||||
Replace `$HOME/gnulib' with the actual directory where the Gnulib
|
||||
sources reside.
|
||||
|
||||
For more information about `bootstrap', run `bootstrap --help'.
|
||||
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.
|
||||
|
||||
|
||||
* Copyright information
|
||||
|
||||
Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
Copyright 2007-2009, 2013-2017 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to anyone to make or distribute verbatim copies
|
||||
of this document as received, in any medium, provided that the
|
||||
copyright notice and this permission notice are preserved,
|
||||
thus giving the recipient permission to redistribute in turn.
|
||||
This file is part of GNU tar.
|
||||
|
||||
Permission is granted to distribute modified versions
|
||||
of this document, or of portions of it,
|
||||
under the above conditions, provided also that they
|
||||
carry prominent notices stating who last changed them.
|
||||
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/>.
|
||||
|
||||
^L
|
||||
Local Variables:
|
||||
@@ -67,5 +62,3 @@ mode: outline
|
||||
paragraph-separate: "[ ^L]*$"
|
||||
version-control: never
|
||||
End:
|
||||
|
||||
|
||||
|
||||
22
THANKS
22
THANKS
@@ -36,6 +36,7 @@ Andrew Torda torda@igc.chem.ethz.ch
|
||||
Andrey A. Chernov ache@astral.msk.su
|
||||
Andy Gay andy@rdl.co.uk
|
||||
Antonio Jose Coutinho ajc@di.uminho.pt
|
||||
Anthony G. Basile blueness@gentoo.org
|
||||
Ariel Faigon ariel@engr.sgi.com
|
||||
Arne Wichmann aw@math.uni-sb.de
|
||||
Arnold Robbins arnold@gnu.org
|
||||
@@ -77,6 +78,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
|
||||
@@ -91,6 +93,7 @@ Christian Kirsch ck@held.mind.de
|
||||
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
|
||||
Christoph Litauer litauer@mailhost.uni-koblenz.de
|
||||
Christophe Colle colle@krtkg1.rug.ac.be
|
||||
Christophe Kalt Christophe.Kalt@kbcfp.com
|
||||
@@ -100,10 +103,12 @@ Claude Scarpelli claude@genethon.fr
|
||||
Claus Heine Claus_Heine@ac2.maus.de
|
||||
Cliff Krumvieda cliff@cs.cornell.edu
|
||||
Clinton Carr clint@netcom.com
|
||||
Connor Behan connor.behan@gmail.com
|
||||
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
|
||||
@@ -111,6 +116,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
|
||||
@@ -118,6 +124,7 @@ Danny R. Johnston danny@cs.weber.edu
|
||||
Dave Barr barr@math.psu.edu
|
||||
Dave Gentzel gentzel@nova.enet.dec.com
|
||||
Dave Gregorich dtg@ipac.caltech.edu
|
||||
David Barri japgolly@gmail.com
|
||||
David Brown davidb@davidb.org
|
||||
David J. MacKenzie djm@uunet.uu.net
|
||||
David Johnson David.W.Johnson@colorado.edu
|
||||
@@ -131,11 +138,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@airbus.com
|
||||
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
|
||||
@@ -168,6 +177,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
|
||||
@@ -198,6 +208,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
|
||||
@@ -236,11 +247,13 @@ 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
|
||||
Jim Meyering meyering@na-net.ornl.gov
|
||||
Jim Murray jjm@jjm.com
|
||||
Jivko Angelov jivko@siteground.com
|
||||
Joachim Holzfuss Joachim.Holzfuss@iap.physik.th-darmstadt.de
|
||||
Joachim Seelig joachim@kruemel.han.de
|
||||
Joe DeBattista joed@itsa.ucsf.edu
|
||||
@@ -296,6 +309,7 @@ Kimmy Posey kimmyd@bnr.ca
|
||||
Koji Kishi kis@rqa.sony.co.jp
|
||||
Konno Hiroharu konno@pac.co.jp
|
||||
Kurt Jaeger pi@lf.net
|
||||
James Antill jantill@redhat.com
|
||||
Larry Creech lcreech@lonestar.rcclub.org
|
||||
Larry Schwimmer rosebud@cyclone.stanford.edu
|
||||
Lasse Collin lasse.collin@tukaani.org
|
||||
@@ -349,6 +363,7 @@ Michael P Urban urban@cobra.jpl.nasa.gov
|
||||
Michael Schmidt michael@muc.de
|
||||
Michael Schwingen m.schwingen@stochastik.rwth-aachen.de
|
||||
Michael Smolsky fnsiguc@astro.weizmann.ac.il
|
||||
Michal Žejdl zejdl@suas.cz
|
||||
Mike Muuss mike@brl.mil
|
||||
Mike Nolan nolan@lpl.arizona.edu
|
||||
Mike Rogers mike@demon.net
|
||||
@@ -357,11 +372,14 @@ Mike Walker M.D.Walker@larc.nasa.gov
|
||||
Milan Hodoscek milan@kihp6.ki.si
|
||||
Minh Tran-Le tranle@intellicorp.com
|
||||
Mitsuaki Masuhara masuhara@mcprv.mec.mei.co.jp
|
||||
Natalie Alifanova na@nxc.no
|
||||
Nate Eldredge nate@cs.hmc.edu
|
||||
Nathan Stratton Treadway nathanst+bugtar@ontko.com
|
||||
Neil Faulks neil@dcs.kcl.ac.uk
|
||||
Neil Jerram nj104@cus.cam.ac.uk
|
||||
Nelson H.F. Beebe beebe@math.utah.edu
|
||||
Nick Barron nikb@cix.compulink.co.uk
|
||||
Nicolas Dudebout nicolas.dudebout@gmail.com
|
||||
Noah Friedman friedman@gnu.org
|
||||
Noel Cragg noel@red-bean.com
|
||||
Norbert Kiesel norbert@rwthi3.informatik.rwth-aachen.de
|
||||
@@ -374,6 +392,7 @@ Oswald P. Backus IV backus@lks.csi.com
|
||||
Pascal Meheut pascal@cnam.cnam.fr
|
||||
Patrick Fulconis fulco@sig.uvsq.fr
|
||||
Patrick Timmons timmons@electech.polymtl.ca
|
||||
Pavel Raiskup praiskup@redhat.com
|
||||
Paul Eggert eggert@twinsun.com
|
||||
Paul Kanz paul@icx.com
|
||||
Paul Mitchell P.Mitchell@surrey.ac.uk
|
||||
@@ -395,6 +414,7 @@ Phil Proudman phil@proudman51.freeserve.co.uk
|
||||
Philippe Defert defert@cern.ch
|
||||
Piercarlo Grandi piercarl@sabi.demon.co.uk
|
||||
Pierce Cantrell cantrell@ee.tamu.edu
|
||||
Piotr Rotter piotr.rotter@active24.pl
|
||||
R. Kent Dybvig dyb@cadence.bloomington.in.us
|
||||
R. Scott Butler butler@prism.es.dupont.com
|
||||
Rainer Orth ro@TechFak.Uni-Bielefeld.DE
|
||||
|
||||
27
TODO
27
TODO
@@ -45,24 +45,23 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2003-2004, 2007, 2013-2014, 2016-2017 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
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.
|
||||
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 tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Local variables:
|
||||
|
||||
48
acinclude.m4
48
acinclude.m4
@@ -1,18 +1,21 @@
|
||||
dnl Special Autoconf macros for GNU Tar -*- autoconf -*-
|
||||
dnl Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
dnl Special Autoconf macros for GNU tar -*- autoconf -*-
|
||||
|
||||
dnl Copyright 2009, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is part of GNU tar.
|
||||
dnl
|
||||
dnl GNU tar is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 3, or (at your option)
|
||||
dnl any later version.
|
||||
dnl the Free Software Foundation; either version 3 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl GNU tar is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License along
|
||||
dnl with GNU tar. If not, see <http://www.gnu.org/licenses/>.
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_DEFUN([TAR_COMPR_PROGRAM],[
|
||||
m4_pushdef([tar_compr_define],translit($1,[a-z+-],[A-ZX_])[_PROGRAM])
|
||||
@@ -24,3 +27,36 @@ AC_DEFUN([TAR_COMPR_PROGRAM],[
|
||||
[tar_compr_var=m4_if($2,,$1,$2)])
|
||||
AC_DEFINE_UNQUOTED(tar_compr_define, "$tar_compr_var",
|
||||
[Define to the program name of ]$1[ compressor program])])
|
||||
|
||||
# Provide <attr/xattr.h>, if necessary
|
||||
|
||||
AC_DEFUN([TAR_HEADERS_ATTR_XATTR_H],
|
||||
[
|
||||
AC_ARG_WITH([xattrs],
|
||||
AS_HELP_STRING([--without-xattrs], [don't use linux extended attributes]),
|
||||
[], [with_xattrs=maybe]
|
||||
)
|
||||
|
||||
# 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])
|
||||
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])
|
||||
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,25 +1,25 @@
|
||||
# Bootstrap configuration for GNU tar.
|
||||
|
||||
# Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2009, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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, or (at your option)
|
||||
# any later version.
|
||||
# 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,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
source_base=gnu
|
||||
gnulib_name=libgnu
|
||||
gnulib_mk=Makefile.am
|
||||
|
||||
# We don't need these modules, even though gnulib-tool mistakenly
|
||||
# includes them because of gettext dependencies.
|
||||
@@ -27,10 +27,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'\\\
|
||||
@@ -68,7 +64,64 @@ fi
|
||||
test -d m4 || mkdir m4
|
||||
test -d $source_base || mkdir $source_base
|
||||
|
||||
cat > ChangeLog <<EOT
|
||||
test -f ChangeLog || cat > ChangeLog <<EOT
|
||||
This file is a placeholder. It will be replaced with the actual ChangeLog
|
||||
by make dist. Run make ChangeLog if you wish to create it earlier.
|
||||
EOT
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
PAXUTILS=paxutils
|
||||
|
||||
# gnulib modules used by this package.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep -h '^[^#]' gnulib.modules $PAXUTILS/gnulib.modules`
|
||||
"
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
if [ -d rmt ]; then
|
||||
:
|
||||
else
|
||||
mkdir rmt
|
||||
fi
|
||||
|
||||
for dir in doc rmt lib tests
|
||||
do
|
||||
copy_files ${PAXUTILS}/$dir $dir
|
||||
done
|
||||
|
||||
copy_files ${PAXUTILS}/paxlib lib pax
|
||||
|
||||
168
configure.ac
168
configure.ac
@@ -1,47 +1,45 @@
|
||||
# Configure template for GNU tar. -*- autoconf -*-
|
||||
|
||||
# Copyright (C) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1991, 1994-2010, 2013-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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, or (at your option)
|
||||
# any later version.
|
||||
# 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,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT([GNU tar], [1.23], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.30], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREREQ([2.63])
|
||||
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-shar std-options silent-rules])
|
||||
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-xz std-options silent-rules])
|
||||
|
||||
# Enable silent rules by default:
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_STDC
|
||||
AC_EXEEXT
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_YACC
|
||||
gl_EARLY
|
||||
AC_CHECK_TOOLS([AR], [ar])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_ISC_POSIX
|
||||
AC_C_INLINE
|
||||
|
||||
AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h memory.h net/errno.h \
|
||||
sgtty.h string.h stropts.h \
|
||||
sys/param.h sys/device.h sys/filio.h sys/gentape.h \
|
||||
sgtty.h string.h \
|
||||
sys/param.h sys/device.h sys/gentape.h \
|
||||
sys/inet.h sys/io/trioctl.h \
|
||||
sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
|
||||
unistd.h locale.h)
|
||||
@@ -51,12 +49,7 @@ AC_CHECK_HEADERS([sys/buf.h], [], [],
|
||||
#include <sys/param.h>
|
||||
#endif])
|
||||
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_MAJOR
|
||||
AC_HEADER_STAT
|
||||
AC_HEADER_STDC
|
||||
|
||||
AC_MSG_CHECKING([for st_fstype string in struct stat])
|
||||
AC_CACHE_VAL(diff_cv_st_fstype_string,
|
||||
@@ -70,11 +63,33 @@ if test $diff_cv_st_fstype_string = yes; then
|
||||
[Define if struct stat has a char st_fstype[] member.])
|
||||
fi
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
# even if we use gnulib's acl.h with integrated m4 file later on (used because
|
||||
# of very useful file_has_acl() function) we need following checks that restrict
|
||||
# tar to use POSIX.1e ACLs only.
|
||||
AC_ARG_WITH([posix-acls],
|
||||
AS_HELP_STRING([--without-posix-acls],
|
||||
[do not use POSIX.1e access control lists]),
|
||||
[],
|
||||
[with_posix_acls=yes])
|
||||
if test "x$with_posix_acls" != "xno"; then
|
||||
AC_CHECK_HEADERS(sys/acl.h,, [with_posix_acls=no])
|
||||
for tar_acl_func in acl_get_file acl_get_fd acl_set_file acl_set_fd \
|
||||
acl_to_text acl_from_text acl_delete_def_file \
|
||||
acl_free; do \
|
||||
test "x$with_posix_acls" = xno && break
|
||||
AC_SEARCH_LIBS([$tar_acl_func], [acl pacl], [], [with_posix_acls=no])
|
||||
done
|
||||
if test "x$with_posix_acls" != xno; then
|
||||
AC_DEFINE(HAVE_POSIX_ACLS,,[Define when we have working POSIX acls])
|
||||
fi
|
||||
else
|
||||
# disable acls in gnulib's checks
|
||||
export enable_acl=no
|
||||
fi
|
||||
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_UID_T
|
||||
AC_CHECK_TYPE(major_t, , AC_DEFINE(major_t, int,
|
||||
[Type of major device numbers.]))
|
||||
@@ -90,13 +105,116 @@ gl_INIT
|
||||
# paxutils modules
|
||||
tar_PAXUTILS
|
||||
|
||||
AC_CHECK_FUNCS(fsync getdtablesize lstat mkfifo readlink symlink setlocale utimes)
|
||||
# gl_GCC_VERSION_IFELSE([major], [minor], [run-if-found], [run-if-not-found])
|
||||
# ------------------------------------------------
|
||||
# If $CPP is gcc-MAJOR.MINOR or newer, then run RUN-IF-FOUND.
|
||||
# Otherwise, run RUN-IF-NOT-FOUND.
|
||||
AC_DEFUN([gl_GCC_VERSION_IFELSE],
|
||||
[AC_PREPROC_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#if ($1) < __GNUC__ || (($1) == __GNUC__ && ($2) <= __GNUC_MINOR__)
|
||||
/* ok */
|
||||
#else
|
||||
# error "your version of gcc is older than $1.$2"
|
||||
#endif
|
||||
]]),
|
||||
], [$3], [$4])
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([gcc-warnings],
|
||||
[AS_HELP_STRING([--enable-gcc-warnings],
|
||||
[turn on many GCC warnings (for developers; best with GNU make)])],
|
||||
[case $enableval in
|
||||
yes|no) ;;
|
||||
*) AC_MSG_ERROR([bad value $enableval for gcc-warnings option]) ;;
|
||||
esac
|
||||
gl_gcc_warnings=$enableval],
|
||||
[gl_gcc_warnings=no
|
||||
if test -d "$srcdir"/.git; then
|
||||
gl_GCC_VERSION_IFELSE([4], [6], [gl_gcc_warnings=yes])
|
||||
fi]
|
||||
)
|
||||
|
||||
if test "$gl_gcc_warnings" = yes; then
|
||||
gl_WARN_ADD([-Werror], [WERROR_CFLAGS])
|
||||
AC_SUBST([WERROR_CFLAGS])
|
||||
|
||||
nw=
|
||||
# This, $nw, is the list of warnings we disable.
|
||||
nw="$nw -Wformat-nonliteral" # warnings in Fedora 17 stdio.h
|
||||
nw="$nw -Wvla" # warnings in gettext.h
|
||||
nw="$nw -Wswitch-default" # Too many warnings for now
|
||||
nw="$nw -Wunsafe-loop-optimizations" # It's OK to omit unsafe optimizations.
|
||||
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 -Wstack-protector"
|
||||
|
||||
gl_MANYWARN_ALL_GCC([ws])
|
||||
gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw])
|
||||
for w in $ws; do
|
||||
gl_WARN_ADD([$w])
|
||||
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.])
|
||||
AH_VERBATIM([FORTIFY_SOURCE],
|
||||
[/* Enable compile-time and run-time bounds-checking, and some warnings,
|
||||
without upsetting glibc 2.15+. */
|
||||
#if !defined _FORTIFY_SOURCE && defined __OPTIMIZE__ && __OPTIMIZE__
|
||||
# define _FORTIFY_SOURCE 2
|
||||
#endif
|
||||
])
|
||||
AC_DEFINE([GNULIB_PORTCHECK], [1], [enable some gnulib portability checks])
|
||||
|
||||
# Use a slightly smaller set of warning options for lib/.
|
||||
# Remove the following and save the result in GNULIB_WARN_CFLAGS.
|
||||
nw=
|
||||
nw="$nw -Wmissing-prototypes"
|
||||
nw="$nw -Wunused-macros"
|
||||
#
|
||||
# These are for argp.
|
||||
nw="$nw -Wmissing-field-initializers"
|
||||
nw="$nw -Wshadow"
|
||||
#
|
||||
gl_MANYWARN_COMPLEMENT([GNULIB_WARN_CFLAGS], [$WARN_CFLAGS], [$nw])
|
||||
|
||||
# This is also for argp.
|
||||
gl_WARN_ADD([-Wno-missing-field-initializers], [GNULIB_WARN_CFLAGS])
|
||||
|
||||
AC_SUBST([GNULIB_WARN_CFLAGS])
|
||||
|
||||
# For gnulib-tests, the set is slightly smaller still.
|
||||
nw=
|
||||
# It's not worth being this picky about test programs.
|
||||
nw="$nw -Wsuggest-attribute=const"
|
||||
gl_MANYWARN_COMPLEMENT([GNULIB_TEST_WARN_CFLAGS],
|
||||
[$GNULIB_WARN_CFLAGS], [$nw])
|
||||
AC_SUBST([GNULIB_TEST_WARN_CFLAGS])
|
||||
fi
|
||||
|
||||
TAR_HEADERS_ATTR_XATTR_H
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
|
||||
|
||||
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
|
||||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||||
AC_CHECK_DECLS([time],,, [#include <time.h>])
|
||||
|
||||
AC_REPLACE_FUNCS(waitpid)
|
||||
|
||||
AC_ARG_VAR([RSH], [Configure absolute path to default remote shell binary])
|
||||
AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
|
||||
[if test -n "$RSH"; then
|
||||
tar_cv_path_RSH=$RSH
|
||||
@@ -157,7 +275,7 @@ if test -z "$DEFAULT_ARCHIVE"; then
|
||||
DEFAULT_ARCHIVE=-
|
||||
else
|
||||
if test -z "`ls $DEFAULT_ARCHIVE 2>/dev/null`"; then
|
||||
AC_MSG_WARN(DEFAULT_ARCHIVE \`$DEFAULT_ARCHIVE' not found on this system)
|
||||
AC_MSG_WARN(DEFAULT_ARCHIVE '$DEFAULT_ARCHIVE' not found on this system)
|
||||
fi
|
||||
# FIXME: Look for DEFTAPE in <sys/mtio.h>.
|
||||
# FIXME: Let DEVICE_PREFIX be configured from the environment.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
%%comments:
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
Copyright 2004, 2013-2014 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.2 or
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
Texts. A copy of the license is included in the file COPYING.
|
||||
Texts. For a copy of the license, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
%%name: tar
|
||||
|
||||
@@ -65,7 +65,7 @@ programs (using pipes); tar can even access remote devices or files
|
||||
%%contributors: Jay Fenlason,
|
||||
Joy Kendall,
|
||||
Francois Pinard <pinard@iro.umontreal.ca>
|
||||
|
||||
|
||||
%%source-tarball: ftp://ftp.gnu.org/pub/gnu/tar/tar-1.15.1.tar.gz
|
||||
%%source-info: http://savannah.gnu.org/projects/tar
|
||||
|
||||
@@ -84,4 +84,3 @@ programs (using pipes); tar can even access remote devices or files
|
||||
%%bug-list: bug-tar@gnu.org bug-tar@gnu.org http://mail.gnu.org/mailman/listinfo/bug-tar
|
||||
|
||||
%%entry-written-by: Sergey Poznyakoff <gray@gnu.org>
|
||||
|
||||
|
||||
2
doc/.gitignore
vendored
2
doc/.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
genfile.texi
|
||||
getdate.texi
|
||||
header.texi
|
||||
manual
|
||||
stamp-vti
|
||||
@@ -24,3 +23,4 @@ tar.toc
|
||||
tar.tp
|
||||
tar.vr
|
||||
version.texi
|
||||
/parse-datetime.texi
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
# Makefile for GNU tar documentation.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2006,
|
||||
# 2007 Free Software Foundation, Inc.
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2006-2007, 2013-2014, 2016-2017
|
||||
# Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software Foundation,
|
||||
## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
# 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/>.
|
||||
|
||||
info_TEXINFOS = tar.texi
|
||||
tar_TEXINFOS = \
|
||||
@@ -24,17 +25,24 @@ tar_TEXINFOS = \
|
||||
fdl.texi\
|
||||
freemanuals.texi\
|
||||
genfile.texi\
|
||||
getdate.texi\
|
||||
header.texi\
|
||||
intern.texi\
|
||||
parse-datetime.texi\
|
||||
recipes.texi\
|
||||
rendition.texi\
|
||||
snapshot.texi\
|
||||
sparse.texi\
|
||||
value.texi
|
||||
EXTRA_DIST = gendocs_template mastermenu.el texify.sed untabify.el
|
||||
|
||||
dist_man_MANS=tar.1 $(RMT_8)
|
||||
if PU_RMT_COND
|
||||
RMT_8=rmt.8
|
||||
endif
|
||||
|
||||
EXTRA_DIST = gendocs_template mastermenu.el texify.sed untabify.el rmt.8
|
||||
|
||||
# The rendering level is anyone of PUBLISH, DISTRIB or PROOF.
|
||||
# Just call `make RENDITION=PROOF [target]' if you want PROOF rendition.
|
||||
# Just call 'make RENDITION=PROOF [target]' if you want PROOF rendition.
|
||||
RENDITION = DISTRIB
|
||||
|
||||
MAKEINFOFLAGS=-D$(RENDITION)
|
||||
@@ -124,7 +132,7 @@ check-unrevised:
|
||||
|
||||
all-check-docs: check-format check-options check-refs check-fixmes check-unrevised
|
||||
|
||||
check-docs:
|
||||
check-docs:
|
||||
$(MAKE) -k all-check-docs
|
||||
|
||||
#
|
||||
@@ -144,4 +152,3 @@ manual:
|
||||
MAKEINFO="$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
TEXI2DVI="$(TEXI2DVI) -t @finalout" \
|
||||
$(GENDOCS) --texi2html tar 'GNU tar manual'
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006-2007, 2014, 2016-2017 Free Software Foundation,
|
||||
@c 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.
|
||||
@@ -16,7 +17,7 @@ dumped directory in special data blocks called @dfn{dumpdirs}.
|
||||
@noindent
|
||||
where @var{C} is one of the @dfn{control codes} described below,
|
||||
@var{filename} is the name of the file @var{C} operates upon, and
|
||||
@samp{\0} represents a nul character (ASCII 0). The white space
|
||||
@samp{\0} represents a nul character (ASCII 0). The white space
|
||||
characters were added for readability, real dumpdirs do not contain
|
||||
them.
|
||||
|
||||
@@ -68,7 +69,7 @@ directory}. For example, consider the following scenario:
|
||||
@enumerate 1
|
||||
@item
|
||||
Previous run dumped a directory @file{foo} which contained the
|
||||
following three directories:
|
||||
following three directories:
|
||||
|
||||
@smallexample
|
||||
a
|
||||
@@ -93,7 +94,7 @@ New incremental dump was made.
|
||||
renaming @file{a} to @file{b} will destroy the existing directory.
|
||||
To correctly process it, @GNUTAR{} needs a temporary directory, so
|
||||
it creates the following dumpdir (newlines have been added for
|
||||
readability):
|
||||
readability):
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -114,7 +115,7 @@ work as usual, and, finally, the last command, @samp{R\0Tfoo/a\0}
|
||||
tells tar to rename the temporary directory to @file{foo/a}.
|
||||
|
||||
The exact placement of a dumpdir in the archive depends on the
|
||||
archive format (@pxref{Formats}):
|
||||
archive format (@pxref{Formats}):
|
||||
|
||||
@itemize
|
||||
@item PAX archives
|
||||
|
||||
111
doc/fdl.texi
111
doc/fdl.texi
@@ -1,13 +1,13 @@
|
||||
@c The GNU Free Documentation License.
|
||||
@center Version 1.3, 3 November 2008
|
||||
|
||||
@node GNU Free Documentation License
|
||||
@appendixsec GNU Free Documentation License
|
||||
|
||||
@cindex FDL, GNU Free Documentation License
|
||||
@center Version 1.2, November 2002
|
||||
@c This file is intended to be included within another document,
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
Copyright @copyright{} 2000-2002, 2007-2008, 2014, 2016-2017 Free
|
||||
Software Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
@@ -93,16 +93,16 @@ An image format is not Transparent if used for any substantial amount
|
||||
of text. A copy that is not ``Transparent'' is called ``Opaque''.
|
||||
|
||||
Examples of suitable formats for Transparent copies include plain
|
||||
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
|
||||
format, @acronym{SGML} or @acronym{XML} using a publicly available
|
||||
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
|
||||
PostScript or @acronym{PDF} designed for human modification. Examples
|
||||
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
|
||||
@acronym{JPG}. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, @acronym{SGML} or
|
||||
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
|
||||
not generally available, and the machine-generated @acronym{HTML},
|
||||
PostScript or @acronym{PDF} produced by some word processors for
|
||||
ASCII without markup, Texinfo input format, La@TeX{} input
|
||||
format, SGML or XML using a publicly available
|
||||
DTD, and standard-conforming simple HTML,
|
||||
PostScript or PDF designed for human modification. Examples
|
||||
of transparent image formats include PNG, XCF and
|
||||
JPG. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, SGML or
|
||||
XML for which the DTD and/or processing tools are
|
||||
not generally available, and the machine-generated HTML,
|
||||
PostScript or PDF produced by some word processors for
|
||||
output purposes only.
|
||||
|
||||
The ``Title Page'' means, for a printed book, the title page itself,
|
||||
@@ -112,6 +112,9 @@ formats which do not have any title page as such, ``Title Page'' means
|
||||
the text near the most prominent appearance of the work's title,
|
||||
preceding the beginning of the body of the text.
|
||||
|
||||
The ``publisher'' means any person or entity that distributes copies
|
||||
of the Document to the public.
|
||||
|
||||
A section ``Entitled XYZ'' means a named subunit of the Document whose
|
||||
title either is precisely XYZ or contains XYZ in parentheses following
|
||||
text that translates XYZ in another language. (Here XYZ stands for a
|
||||
@@ -380,13 +383,30 @@ title.
|
||||
@item
|
||||
TERMINATION
|
||||
|
||||
You may not copy, modify, sublicense, or distribute the Document except
|
||||
as expressly provided for under this License. Any other attempt to
|
||||
copy, modify, sublicense or distribute the Document is void, and will
|
||||
automatically terminate your rights under this License. However,
|
||||
parties who have received copies, or rights, from you under this
|
||||
License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
You may not copy, modify, sublicense, or distribute the Document
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense, or distribute it is void, and
|
||||
will automatically terminate your rights under this License.
|
||||
|
||||
However, if you cease all violation of this License, then your license
|
||||
from a particular copyright holder is reinstated (a) provisionally,
|
||||
unless and until the copyright holder explicitly and finally
|
||||
terminates your license, and (b) permanently, if the copyright holder
|
||||
fails to notify you of the violation by some reasonable means prior to
|
||||
60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, receipt of a copy of some or all of the same material does
|
||||
not give you any rights to use it.
|
||||
|
||||
@item
|
||||
FUTURE REVISIONS OF THIS LICENSE
|
||||
@@ -404,11 +424,46 @@ following the terms and conditions either of that specified version or
|
||||
of any later version that has been published (not as a draft) by the
|
||||
Free Software Foundation. If the Document does not specify a version
|
||||
number of this License, you may choose any version ever published (not
|
||||
as a draft) by the Free Software Foundation.
|
||||
as a draft) by the Free Software Foundation. If the Document
|
||||
specifies that a proxy can decide which future versions of this
|
||||
License can be used, that proxy's public statement of acceptance of a
|
||||
version permanently authorizes you to choose that version for the
|
||||
Document.
|
||||
|
||||
@item
|
||||
RELICENSING
|
||||
|
||||
``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
|
||||
World Wide Web server that publishes copyrightable works and also
|
||||
provides prominent facilities for anybody to edit those works. A
|
||||
public wiki that anybody can edit is an example of such a server. A
|
||||
``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
|
||||
site means any set of copyrightable works thus published on the MMC
|
||||
site.
|
||||
|
||||
``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
|
||||
license published by Creative Commons Corporation, a not-for-profit
|
||||
corporation with a principal place of business in San Francisco,
|
||||
California, as well as future copyleft versions of that license
|
||||
published by that same organization.
|
||||
|
||||
``Incorporate'' means to publish or republish a Document, in whole or
|
||||
in part, as part of another Document.
|
||||
|
||||
An MMC is ``eligible for relicensing'' if it is licensed under this
|
||||
License, and if all works that were first published under this License
|
||||
somewhere other than this MMC, and subsequently incorporated in whole
|
||||
or in part into the MMC, (1) had no cover texts or invariant sections,
|
||||
and (2) were thus incorporated prior to November 1, 2008.
|
||||
|
||||
The operator of an MMC Site may republish an MMC contained in the site
|
||||
under CC-BY-SA on the same site at any time before August 1, 2009,
|
||||
provided the MMC is eligible for relicensing.
|
||||
|
||||
@end enumerate
|
||||
|
||||
@page
|
||||
@appendixsubsec ADDENDUM: How to use this License for your documents
|
||||
@heading ADDENDUM: How to use this License for your documents
|
||||
|
||||
To use this License in a document you have written, include a copy of
|
||||
the License in the document and put the following copyright and
|
||||
@@ -418,7 +473,7 @@ license notices just after the title page:
|
||||
@group
|
||||
Copyright (C) @var{year} @var{your name}.
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2
|
||||
under the terms of the GNU Free Documentation License, Version 1.3
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
|
||||
Texts. A copy of the license is included in the section entitled ``GNU
|
||||
@@ -427,7 +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...Texts.'' line with this:
|
||||
replace the ``with@dots{}Texts.'' line with this:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<p>The manual for %%PACKAGE%% is available in the following formats:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="%%PACKAGE%%.html">HTML
|
||||
<li><a href="%%PACKAGE%%.html">HTML
|
||||
(%%HTML_MONO_SIZE%%K bytes)</a> - entirely on one web page.</li>
|
||||
<li><a href="html_node/index.html">HTML</a> - with one web page per
|
||||
node.</li>
|
||||
@@ -49,7 +49,7 @@
|
||||
chapter.</li>
|
||||
%%ENDIF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.html.gz">HTML compressed
|
||||
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
|
||||
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
|
||||
one web page.</li>
|
||||
<li><a href="%%PACKAGE%%.html_node.tar.gz">HTML compressed
|
||||
(%%HTML_NODE_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
@@ -96,9 +96,9 @@ Return to the <a href="/home.html">GNU Project home page</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Please send FSF & GNU inquiries to
|
||||
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>
|
||||
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
|
||||
@@ -106,7 +106,7 @@ Please send broken links and other corrections (or suggestions) to
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.,
|
||||
Copyright 2004, 2013-2014, 2016-2017 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02111, USA
|
||||
<br />
|
||||
Verbatim copying and distribution of this entire article is
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006, 2014, 2016-2017 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -87,6 +87,8 @@ The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and
|
||||
@code{gname} are null-terminated character strings. All other fields
|
||||
are zero-filled octal numbers in ASCII. Each numeric field of width
|
||||
@var{w} contains @var{w} minus 1 digits, and a null.
|
||||
(In the extended @acronym{GNU} format, the numeric fields can take
|
||||
other forms.)
|
||||
|
||||
The @code{name} field is the file name of the file, with directory names
|
||||
(if any) preceding the file name, separated by slashes.
|
||||
@@ -107,19 +109,17 @@ group permission could be copied from the @emph{other} permission.
|
||||
The @code{uid} and @code{gid} fields are the numeric user and group
|
||||
@acronym{ID} of the file owners, respectively. If the operating system does
|
||||
not support numeric user or group @acronym{ID}s, these fields should
|
||||
be ignored.
|
||||
be ignored.
|
||||
|
||||
The @code{size} field is the size of the file in bytes; linked files
|
||||
are archived with this field specified as zero.
|
||||
are archived with this field specified as zero.
|
||||
|
||||
The @code{mtime} field is the data modification time of the file at
|
||||
the time it was archived. It is the ASCII representation of the octal
|
||||
value of the last time the file's contents were modified, represented
|
||||
as an integer number of
|
||||
The @code{mtime} field represents the data modification time of the file at
|
||||
the time it was archived. It represents the integer number of
|
||||
seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
||||
|
||||
The @code{chksum} field is the ASCII representation of the octal value
|
||||
of the simple sum of all bytes in the header block. Each 8-bit
|
||||
The @code{chksum} field represents
|
||||
the simple sum of all bytes in the header block. Each 8-bit
|
||||
byte in the header is added to an unsigned integer, initialized to
|
||||
zero, the precision of which shall be no less than seventeen bits.
|
||||
When calculating the checksum, the @code{chksum} field is treated as
|
||||
@@ -310,6 +310,18 @@ of an archive should have this type.
|
||||
|
||||
@end table
|
||||
|
||||
For fields containing numbers or timestamps that are out of range for
|
||||
the basic format, the @acronym{GNU} format uses a base-256
|
||||
representation instead of an ASCII octal number. If the leading byte
|
||||
is 0xff (255), all the bytes of the field (including the leading byte)
|
||||
are concatenated in big-endian order, with the result being a negative
|
||||
number expressed in two's complement form. If the leading byte is
|
||||
0x80 (128), the non-leading bytes of the field are concatenated in
|
||||
big-endian order, with the result being a positive number expressed in
|
||||
binary form. Leading bytes other than 0xff, 0x80 and ASCII octal
|
||||
digits are reserved for future use, as are base-256 representations of
|
||||
values that would be in range for the basic format.
|
||||
|
||||
You may have trouble reading a @acronym{GNU} format archive on a
|
||||
non-@acronym{GNU} system if the options @option{--incremental} (@option{-G}),
|
||||
@option{--multi-volume} (@option{-M}), @option{--sparse} (@option{-S}), or @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) were
|
||||
@@ -330,4 +342,3 @@ checksum error.
|
||||
@node Dumpdir
|
||||
@unnumberedsec Dumpdir
|
||||
@include dumpdir.texi
|
||||
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
;; Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
;; Inc.
|
||||
|
||||
;; Author: Sergey Poznyakoff
|
||||
;; Maintainer: bug-tar@gnu.org
|
||||
;; Keywords: maint, tex, docs
|
||||
|
||||
;; This file is part of GNU tar documentation suite
|
||||
;; This file is part of GNU tar.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; 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, or (at your option)
|
||||
;; any later version.
|
||||
;; 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,
|
||||
;; 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, write to the Free Software Foundation,
|
||||
;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file redefines texinfo-master-menu-list so that it takes into
|
||||
;; account included files.
|
||||
|
||||
;; Known bugs: @menu without previous sectioning command will inherit
|
||||
;; Known bugs: @menu without previous sectioning command will inherit
|
||||
;; documentation string from the previous menu. However, since such a
|
||||
;; menu is illegal in a texinfo file, we can live with it.
|
||||
|
||||
(require 'texinfo)
|
||||
(require 'texinfo)
|
||||
(require 'texnfo-upd)
|
||||
|
||||
(defun texinfo-master-menu-list-recursive (title)
|
||||
|
||||
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 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,6 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright (C) 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
@c 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
@c Copyright 1992, 1994-1997, 1999-2004, 2006, 2013-2014, 2016-2017 Free
|
||||
@c 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,6 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2005, 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2005, 2007, 2014, 2016-2017 Free Software Foundation,
|
||||
@c 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,11 +12,11 @@ used to determine which files were modified since the last backup.
|
||||
|
||||
@GNUTAR{} version @value{VERSION} supports three snapshot file
|
||||
formats. The first format, called @dfn{format 0}, is the one used by
|
||||
@GNUTAR{} versions up to 1.15.1. The second format, called @dfn{format
|
||||
1} is an extended version of this format, that contains more metadata
|
||||
and allows for further extensions. It was used by version
|
||||
1.15.1. Starting from version 1.16 and up to @value{VERSION}, the
|
||||
@dfn{format 2} is used.
|
||||
@GNUTAR{} versions up to and including 1.15.1. The second format, called
|
||||
@dfn{format 1} is an extended version of this format, that contains more
|
||||
metadata and allows for further extensions. It was used by alpha release
|
||||
version 1.15.90. For alpha version 1.15.91 and stable releases
|
||||
version 1.16 up through @value{VERSION}, the @dfn{format 2} is used.
|
||||
|
||||
@GNUTAR{} is able to read all three formats, but will create
|
||||
snapshots only in format 2.
|
||||
@@ -33,7 +34,7 @@ metadata descriptions, one per line. Each description has the
|
||||
following format:
|
||||
|
||||
@smallexample
|
||||
@var{nfs}@var{dev} @var{inode} @var{name}
|
||||
[@var{nfs}]@var{dev} @var{inode} @var{name}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
@@ -42,7 +43,10 @@ where:
|
||||
@table @var
|
||||
@item nfs
|
||||
A single plus character (@samp{+}), if this directory is located on
|
||||
an @acronym{NFS}-mounted partition, or a single space otherwise;
|
||||
an @acronym{NFS}-mounted partition, otherwise empty.
|
||||
|
||||
(That is, for non-NFS directories, the first character on the
|
||||
description line contains the start of the @var{dev} field.)
|
||||
|
||||
@item dev
|
||||
Device number of the directory;
|
||||
@@ -91,7 +95,6 @@ as with @samp{format 0}.
|
||||
|
||||
@cindex format 2, snapshot file
|
||||
@cindex snapshot file, format 2
|
||||
@FIXME{}
|
||||
@item
|
||||
@samp{Format 2} snapshot file begins with a format identifier, as described for
|
||||
version 1, e.g.:
|
||||
@@ -105,7 +108,7 @@ records, separated by null (@acronym{ASCII} 0)
|
||||
characters. Thus, in contrast to the previous formats, format 2
|
||||
snapshot is a binary file.
|
||||
|
||||
First two records are decimal numbers, representing the
|
||||
First two records are decimal integers, representing the
|
||||
time of the last backup. First number is the number of seconds, the
|
||||
second one is the number of nanoseconds, since the beginning of the
|
||||
epoch. These are followed by arbitrary number of directory records.
|
||||
@@ -113,17 +116,18 @@ epoch. These are followed by arbitrary number of directory records.
|
||||
Each @dfn{directory record} contains a set of metadata describing a
|
||||
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 number
|
||||
in @acronym{ASCII} notation.
|
||||
part. The @dfn{Number} type in this table stands for a decimal integer
|
||||
in @acronym{ASCII} notation. (Negative values are preceded with a "-"
|
||||
character, while positive values have no leading punctuation.)
|
||||
|
||||
@multitable @columnfractions 0.2 0.2 0.6
|
||||
@multitable @columnfractions 0.25 0.15 0.6
|
||||
@headitem Field @tab Type @tab Description
|
||||
@item nfs @tab Character @tab @samp{1} if the directory is located on
|
||||
an @acronym{NFS}-mounted partition, or @samp{0} otherwise;
|
||||
@item mtime-sec @tab Number @tab Modification time, seconds;
|
||||
@item mtime-nano @tab Number @tab Modification time, nanoseconds;
|
||||
@item dev-no @tab Number @tab Device number;
|
||||
@item i-no @tab Number @tab I-node number;
|
||||
@item timestamp_sec @tab Number @tab Modification time, seconds;
|
||||
@item timestamp_nsec @tab Number @tab Modification time, nanoseconds;
|
||||
@item dev @tab Number @tab Device number;
|
||||
@item ino @tab Number @tab I-node number;
|
||||
@item name @tab String @tab Directory name; in contrast to the
|
||||
previous versions it is not quoted;
|
||||
@item contents @tab Dumpdir @tab Contents of the directory;
|
||||
@@ -134,7 +138,28 @@ previous versions it is not quoted;
|
||||
Dumpdirs stored in snapshot files contain only records of types
|
||||
@samp{Y}, @samp{N} and @samp{D}.
|
||||
|
||||
@cindex snapshot file field ranges
|
||||
@opindex show-snapshot-field-ranges
|
||||
The specific range of values allowed in each of the @dfn{Number} fields
|
||||
depends on the underlying C datatypes as determined when @command{tar}
|
||||
is compiled. To see the specific ranges allowed for a particular
|
||||
@command{tar} binary, you can use the
|
||||
@option{--show-snapshot-field-ranges} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --show-shapshot-field-ranges}
|
||||
This tar's snapshot file field ranges are
|
||||
(field name => [ min, max ]):
|
||||
|
||||
nfs => [ 0, 1 ],
|
||||
timestamp_sec => [ -9223372036854775808, 9223372036854775807 ],
|
||||
timestamp_nsec => [ 0, 999999999 ],
|
||||
dev => [ 0, 18446744073709551615 ],
|
||||
ino => [ 0, 18446744073709551615 ],
|
||||
@end smallexample
|
||||
|
||||
(This example is from a GNU/Linux x86_64 system.)
|
||||
|
||||
@end enumerate
|
||||
|
||||
@c End of snapshot.texi
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006, 2014, 2016-2017 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.
|
||||
|
||||
@@ -232,4 +232,3 @@ into a separate directory. Then, using a simple program it would be
|
||||
possible to expand the file to its original form even without @GNUTAR{}.
|
||||
@xref{Sparse Recovery}, for the detailed information on how to extract
|
||||
sparse members without @GNUTAR{}.
|
||||
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2007, 2014, 2016-2017 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@cindex Device numbers, changing
|
||||
@cindex snapshot files, editing
|
||||
@cindex snapshot files, fixing device numbers
|
||||
Sometimes device numbers can change after upgrading your kernel
|
||||
version or reconfiguring the hardware. Reportedly this is the case with
|
||||
some newer @i{Linux} kernels, when using @acronym{LVM}. In majority of
|
||||
Various situations can cause device numbers to change: upgrading your
|
||||
kernel version, reconfiguring your hardware, loading kernel modules in a
|
||||
different order, using virtual volumes that are assembled dynamically
|
||||
(such as with @acronym{LVM} or @acronym{RAID}), hot-plugging drives
|
||||
(e.g. external USB or Firewire drives), etc. In the majority of
|
||||
cases this change is unnoticed by the users. However, it influences
|
||||
@command{tar} incremental backups: the device number is stored in tar
|
||||
snapshot files (@pxref{Snapshot Files}) and is used to determine whether
|
||||
the file has changed since the last backup. If the device numbers
|
||||
change for some reason, the next backup you run will be a full backup.
|
||||
change for some reason, by default the next backup you run will be a
|
||||
full backup.
|
||||
|
||||
|
||||
@pindex tar-snapshot-edit
|
||||
To minimize the impact in these cases, GNU @command{tar} comes with
|
||||
the @command{tar-snapshot-edit} utility for inspecting and updating
|
||||
device numbers in snapshot files. The utility, written by
|
||||
Dustin J.@: Mitchell, is available from
|
||||
device numbers in snapshot files. (The utility, written by
|
||||
Dustin J.@: Mitchell, is also available from the
|
||||
@uref{http://www.gnu.org/@/software/@/tar/@/utils/@/tar-snapshot-edit.html,
|
||||
@GNUTAR{} home page}.
|
||||
@GNUTAR{} home page}.)
|
||||
|
||||
To obtain the device numbers used in the snapshot file, run
|
||||
To obtain a summary of the device numbers found in the snapshot file, run
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar-snapshot-edit @var{snapfile}}
|
||||
@@ -31,10 +35,19 @@ $ @kbd{tar-snapshot-edit @var{snapfile}}
|
||||
|
||||
@noindent
|
||||
where @var{snapfile} is the name of the snapshot file (you can supply as many
|
||||
files as you wish in a single command line).
|
||||
files as you wish in a single command line). You can then compare the
|
||||
numbers across snapshot files, or against those currently in use on the
|
||||
live filesystem (using @command{ls -l} or @command{stat}).
|
||||
|
||||
To update all occurrences of the given device number in the file, use
|
||||
@option{-r} option. It takes a single argument of the form
|
||||
Assuming the device numbers have indeed changed, it's often possible
|
||||
to simply tell @GNUTAR{} to ignore the device number when processing the
|
||||
incremental snapshot files for these backups, using the
|
||||
@option{--no-check-device} option (@pxref{device numbers}).
|
||||
|
||||
Alternatively, you can use the @command{tar-edit-snapshot} script's
|
||||
@option{-r} option to update all occurrences of the given device
|
||||
number in the snapshot file(s). It takes a single argument
|
||||
of the form
|
||||
@samp{@var{olddev}-@var{newdev}}, where @var{olddev} is the device number
|
||||
used in the snapshot file, and @var{newdev} is the corresponding new device
|
||||
number. Both numbers may be specified in hex (e.g., @samp{0xfe01}),
|
||||
@@ -49,10 +62,30 @@ backup file is obtained by appending @samp{~} to the original file name.
|
||||
|
||||
An example session:
|
||||
@smallexample
|
||||
$ @kbd{tar-snapshot-edit /var/backup/snap.a}
|
||||
file version 2
|
||||
/tmp/snap: Device 0x0306 occurs 634 times.
|
||||
$ @kbd{tar-snapshot-edit -b -r 0x0306-0x4500 /var/backup/snap.a}
|
||||
file version 2
|
||||
@end smallexample
|
||||
$ @kbd{tar-snapshot-edit root_snap.0 boot_snap.0}
|
||||
File: root_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Device 0x0000 occurs 1 times.
|
||||
Device 0x0003 occurs 1 times.
|
||||
Device 0x0005 occurs 1 times.
|
||||
Device 0x0013 occurs 1 times.
|
||||
Device 0x6801 occurs 1 times.
|
||||
Device 0x6803 occurs 6626 times.
|
||||
Device 0xfb00 occurs 1 times.
|
||||
|
||||
File: boot_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Device 0x6801 occurs 3 times.
|
||||
$ @kbd{tar-snapshot-edit -b -r 0x6801-0x6901,0x6803-0x6903 root_snap.0 boot_snap.0}
|
||||
File: root_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Updated 6627 records.
|
||||
|
||||
File: boot_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Updated 3 records.
|
||||
@end smallexample
|
||||
|
||||
2570
doc/tar.texi
2570
doc/tar.texi
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,20 @@
|
||||
# Copyright (C) 2006, 2007 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 the Free Software Foundation; either version 3, 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.
|
||||
#
|
||||
# Copyright 2006-2007, 2013-2014, 2016-2017 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 GNU tar; if not, write to the Free Software
|
||||
# Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
1{s,/\*,@comment ,
|
||||
b
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright (C) 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
@c 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
@c Copyright 1992, 1994-1997, 1999-2006, 2013-2014, 2016-2017 Free
|
||||
@c Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
@@ -18,5 +18,3 @@
|
||||
@end ifclear
|
||||
@xopindex{\option\, summary}
|
||||
@end macro
|
||||
|
||||
|
||||
|
||||
1
gnulib
Submodule
1
gnulib
Submodule
Submodule gnulib added at 91e834891d
@@ -1,24 +1,50 @@
|
||||
# List of gnulib modules needed for GNU tar.
|
||||
# A module name per line. Empty lines and comments are ignored.
|
||||
|
||||
# Copyright 2005-2010, 2012-2014, 2017 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
alloca
|
||||
areadlinkat-with-size
|
||||
argmatch
|
||||
argp
|
||||
argp-version-etc
|
||||
backupfile
|
||||
canonicalize
|
||||
closeout
|
||||
configmake
|
||||
dirname
|
||||
error
|
||||
exclude
|
||||
extern-inline
|
||||
exitfail
|
||||
faccessat
|
||||
fchmodat
|
||||
fchownat
|
||||
fcntl-h
|
||||
fdopendir
|
||||
fdutimensat
|
||||
file-has-acl
|
||||
fileblocks
|
||||
fnmatch-gnu
|
||||
fprintftime
|
||||
fseeko
|
||||
ftruncate
|
||||
fstatat
|
||||
full-write
|
||||
getdate
|
||||
futimens
|
||||
getline
|
||||
getopt-gnu
|
||||
getpagesize
|
||||
@@ -27,20 +53,30 @@ gettime
|
||||
gitlog-to-changelog
|
||||
hash
|
||||
human
|
||||
inttostr
|
||||
inttypes
|
||||
lchown
|
||||
linkat
|
||||
localcharset
|
||||
manywarnings
|
||||
mkdirat
|
||||
mkdtemp
|
||||
mkfifoat
|
||||
modechange
|
||||
obstack
|
||||
openat
|
||||
parse-datetime
|
||||
priv-set
|
||||
progname
|
||||
quote
|
||||
quotearg
|
||||
readlinkat
|
||||
renameat
|
||||
root-uid
|
||||
rpmatch
|
||||
safe-read
|
||||
save-cwd
|
||||
savedir
|
||||
selinux-at
|
||||
setenv
|
||||
snprintf
|
||||
stat-time
|
||||
@@ -49,12 +85,17 @@ stdint
|
||||
stpcpy
|
||||
strdup-posix
|
||||
strerror
|
||||
strtoimax
|
||||
strtol
|
||||
strtoul
|
||||
strtoumax
|
||||
symlinkat
|
||||
timespec
|
||||
timespec-sub
|
||||
unlinkat
|
||||
unlinkdir
|
||||
unlocked-io
|
||||
utimens
|
||||
utimensat
|
||||
version-etc-fsf
|
||||
xalloc
|
||||
xalloc-die
|
||||
|
||||
10
lib/.gitignore
vendored
Normal file
10
lib/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
paxerror.c
|
||||
paxexit-status.c
|
||||
paxexit.c
|
||||
paxlib.h
|
||||
paxnames.c
|
||||
rmt-command.h
|
||||
rmt.h
|
||||
rtapelib.c
|
||||
system-ioctl.h
|
||||
system.h
|
||||
@@ -1,21 +1,22 @@
|
||||
# Makefile for GNU tar library. -*- Makefile -*-
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004,
|
||||
# 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||
# Copyright 1994-1997, 1999-2001, 2003-2007, 2009-2010, 2013-2014,
|
||||
# 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
noinst_LIBRARIES=libtar.a
|
||||
rmt-command.h : Makefile
|
||||
@@ -26,14 +27,35 @@ rmt-command.h : Makefile
|
||||
$(AM_V_at)mv $@-t $@
|
||||
BUILT_SOURCES = rmt-command.h
|
||||
CLEANFILES = rmt-command.h rmt-command.h-t
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/gnu -I../ -I../gnu
|
||||
AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
paxlib.h\
|
||||
rmt.h\
|
||||
stdopen.h\
|
||||
system.h\
|
||||
system-ioctl.h\
|
||||
wordsplit.h\
|
||||
xattr-at.h
|
||||
|
||||
noinst_HEADERS = system.h system-ioctl.h rmt.h paxlib.h stdopen.h
|
||||
libtar_a_SOURCES = \
|
||||
paxerror.c paxexit.c paxlib.h paxnames.c \
|
||||
prepargs.c prepargs.h \
|
||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h
|
||||
system.h system-ioctl.h \
|
||||
wordsplit.c\
|
||||
xattr-at.c
|
||||
|
||||
if !TAR_COND_XATTR_H
|
||||
BUILT_SOURCES += attr/xattr.h
|
||||
attr/xattr.h: attr-xattr.in.h $(top_builddir)/config.status
|
||||
$(AM_V_at)$(MKDIR_P) attr
|
||||
$(AM_V_GEN)rm -f $@-t $@ && \
|
||||
cp $(srcdir)/attr-xattr.in.h attr/xattr.h
|
||||
endif
|
||||
|
||||
MOSTLYCLEANFILES = attr/xattr.h
|
||||
|
||||
EXTRA_DIST = attr-xattr.in.h
|
||||
|
||||
60
lib/attr-xattr.in.h
Normal file
60
lib/attr-xattr.in.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* Replacement <attr/xattr.h> for platforms that lack it.
|
||||
Copyright 2012-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 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 <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef TAR_ATTR_XATTR_H
|
||||
#define TAR_ATTR_XATTR_H
|
||||
#include <errno.h>
|
||||
#ifndef ENOATTR
|
||||
# define ENOATTR ENODATA /* No such attribute */
|
||||
#endif
|
||||
|
||||
/* setting */
|
||||
static inline 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)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline 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)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline 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)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
|
||||
/* listing */
|
||||
static inline 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)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline ssize_t flistxattr (int filedes, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
/* Parse arguments from a string and prepend them to an argv.
|
||||
Copyright 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA. */
|
||||
|
||||
/* Written by Paul Eggert <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>
|
||||
|
||||
/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
|
||||
as an argument to <ctype.h> macros like "isspace". */
|
||||
#ifdef STDC_HEADERS
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# define IN_CTYPE_DOMAIN(c) ((c) <= 0177)
|
||||
#endif
|
||||
|
||||
#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
|
||||
|
||||
/* 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,6 +1,7 @@
|
||||
/* stdopen.c - ensure that the three standard file descriptors are in use
|
||||
|
||||
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2005, 2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -13,8 +14,7 @@
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert and Jim Meyering. */
|
||||
|
||||
|
||||
1629
lib/wordsplit.c
Normal file
1629
lib/wordsplit.c
Normal file
File diff suppressed because it is too large
Load Diff
168
lib/wordsplit.h
Normal file
168
lib/wordsplit.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/* wordsplit - a word splitter
|
||||
Copyright (C) 2009-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Sergey Poznyakoff
|
||||
*/
|
||||
|
||||
#ifndef __WORDSPLIT_H
|
||||
#define __WORDSPLIT_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
|
||||
# define __WORDSPLIT_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
|
||||
#else
|
||||
# define __WORDSPLIT_ATTRIBUTE_FORMAT(spec) /* empty */
|
||||
#endif
|
||||
|
||||
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);
|
||||
void (*ws_error) (const char *, ...)
|
||||
__WORDSPLIT_ATTRIBUTE_FORMAT ((__printf__, 1, 2));
|
||||
void (*ws_debug) (const char *, ...)
|
||||
__WORDSPLIT_ATTRIBUTE_FORMAT ((__printf__, 1, 2));
|
||||
|
||||
const char **ws_env;
|
||||
const char *(*ws_getvar) (const char *, size_t, void *);
|
||||
void *ws_closure;
|
||||
|
||||
const char *ws_input;
|
||||
size_t ws_len;
|
||||
size_t ws_endp;
|
||||
int ws_errno;
|
||||
struct wordsplit_node *ws_head, *ws_tail;
|
||||
};
|
||||
|
||||
/* Wordsplit flags. Only 2 bits of a 32-bit word remain unused.
|
||||
It is getting crowded... */
|
||||
/* 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.
|
||||
(These are not counted in the returned ws_wordc.) */
|
||||
#define WRDSF_DOOFFS 0x00000002
|
||||
/* Don't do command substitution. Reserved for future use. */
|
||||
#define WRDSF_NOCMD 0x00000004
|
||||
/* The parameter p resulted from a previous call to
|
||||
wordsplit(), and wordsplit_free() was not called. Reuse the
|
||||
allocated storage. */
|
||||
#define WRDSF_REUSE 0x00000008
|
||||
/* Print errors */
|
||||
#define WRDSF_SHOWERR 0x00000010
|
||||
/* Consider it an error if an undefined shell variable
|
||||
is expanded. */
|
||||
#define WRDSF_UNDEF 0x00000020
|
||||
|
||||
/* Don't do variable expansion. */
|
||||
#define WRDSF_NOVAR 0x00000040
|
||||
/* Abort on ENOMEM error */
|
||||
#define WRDSF_ENOMEMABRT 0x00000080
|
||||
/* Trim off any leading and trailind whitespace */
|
||||
#define WRDSF_WS 0x00000100
|
||||
/* Handle single quotes */
|
||||
#define WRDSF_SQUOTE 0x00000200
|
||||
/* Handle double quotes */
|
||||
#define WRDSF_DQUOTE 0x00000400
|
||||
/* Handle quotes and escape directives */
|
||||
#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE)
|
||||
/* Replace each input sequence of repeated delimiters with a single
|
||||
delimiter */
|
||||
#define WRDSF_SQUEEZE_DELIMS 0x00000800
|
||||
/* Return delimiters */
|
||||
#define WRDSF_RETURN_DELIMS 0x00001000
|
||||
/* Treat sed expressions as words */
|
||||
#define WRDSF_SED_EXPR 0x00002000
|
||||
/* ws_delim field is initialized */
|
||||
#define WRDSF_DELIM 0x00004000
|
||||
/* ws_comment field is initialized */
|
||||
#define WRDSF_COMMENT 0x00008000
|
||||
/* ws_alloc_die field is initialized */
|
||||
#define WRDSF_ALLOC_DIE 0x00010000
|
||||
/* ws_error field is initialized */
|
||||
#define WRDSF_ERROR 0x00020000
|
||||
/* ws_debug field is initialized */
|
||||
#define WRDSF_DEBUG 0x00040000
|
||||
/* ws_env field is initialized */
|
||||
#define WRDSF_ENV 0x00080000
|
||||
/* ws_getvar field is initialized */
|
||||
#define WRDSF_GETVAR 0x00100000
|
||||
/* enable debugging */
|
||||
#define WRDSF_SHOWDBG 0x00200000
|
||||
/* 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 */
|
||||
#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
|
||||
|
||||
#define WRDSF_DEFFLAGS \
|
||||
(WRDSF_NOVAR | WRDSF_NOCMD | \
|
||||
WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES)
|
||||
|
||||
#define WRDSE_EOF 0
|
||||
#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
|
||||
|
||||
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_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);
|
||||
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);
|
||||
|
||||
|
||||
#endif
|
||||
114
lib/xattr-at.c
Normal file
114
lib/xattr-at.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/* openat-style fd-relative functions for operating with extended file
|
||||
attributes.
|
||||
|
||||
Copyright 2012-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 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 <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "xattr-at.h"
|
||||
#include "openat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
#include "save-cwd.h"
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
|
||||
/* setxattrat */
|
||||
#define AT_FUNC_NAME setxattrat
|
||||
#define AT_FUNC_F1 setxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, const void *value \
|
||||
, size_t size, int flags
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size, flags
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* lsetxattrat */
|
||||
#define AT_FUNC_NAME lsetxattrat
|
||||
#define AT_FUNC_F1 lsetxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, const void *value \
|
||||
, size_t size, int flags
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size, flags
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* getxattrat */
|
||||
#define AT_FUNC_NAME getxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 getxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, void *value \
|
||||
, size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* lgetxattrat */
|
||||
#define AT_FUNC_NAME lgetxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 lgetxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, void *value \
|
||||
, size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* listxattrat */
|
||||
#define AT_FUNC_NAME listxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 listxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , char *list , size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , list , size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* llistxattrat */
|
||||
#define AT_FUNC_NAME llistxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 llistxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , char *list , size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , list , size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#endif /* HAVE_XATTRS */
|
||||
74
lib/xattr-at.h
Normal file
74
lib/xattr-at.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* Prototypes for openat-style fd-relative functions for operating with
|
||||
extended file attributes.
|
||||
|
||||
Copyright 2012-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 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 <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef XATTRS_AT_H
|
||||
#define XATTRS_AT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(HAVE_SYS_XATTR_H)
|
||||
# include <sys/xattr.h>
|
||||
#elif defined(HAVE_ATTR_XATTR_H)
|
||||
# include <attr/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifndef ENOATTR
|
||||
# define ENOATTR ENODATA /* No such attribute */
|
||||
#endif
|
||||
|
||||
/* These are the dir-fd-relative variants of the functions without the
|
||||
"at" suffix. For example, setxattrat (AT_FDCWD, path, name, value, size,
|
||||
flags &c) is usually equivalent to setxattr (file, name, value, size,
|
||||
flags). For more info use the setxattr(2), getxattr(2) or listxattr(2)
|
||||
manpages. */
|
||||
|
||||
/* dir-fd-relative setxattr. Operation sets the VALUE of the extended
|
||||
attribute identified by NAME and associated with the given PATH in the
|
||||
filesystem relatively to directory identified by DIR_FD. See the
|
||||
setxattr(2) manpage for the description of all parameters. */
|
||||
int setxattrat (int dir_fd, const char *path, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
|
||||
/* dir-fd-relative lsetxattr. This function is just like setxattrat,
|
||||
except when DIR_FD and FILE specify a symlink: lsetxattrat operates on the
|
||||
symlink, while the setxattrat operates on the referent of the symlink. */
|
||||
int lsetxattrat (int dir_fd, const char *path, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
|
||||
/* dir-fd-relative getxattr. Operation gets the VALUE of the extended
|
||||
attribute idenfified by NAME and associated with the given PATH in the
|
||||
filesystem relatively to directory identified by DIR_FD. For more info
|
||||
about all parameters see the getxattr(2) manpage. */
|
||||
ssize_t getxattrat (int dir_fd, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
|
||||
/* dir-fd-relative lgetxattr. This function is just like getxattrat,
|
||||
except when DIR_FD and FILE specify a symlink: lgetxattrat operates on the
|
||||
symlink, while the getxattrat operates on the referent of the symlink. */
|
||||
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
|
||||
more info see the listxattr(2) manpage. */
|
||||
ssize_t listxattrat (int dir_fd, const char *path, char *list, size_t size);
|
||||
|
||||
/* dir-fd-relative llistxattr. This function is just like listxattrat,
|
||||
except when DIR_FD and FILE specify a symlink: llistxattr operates on the
|
||||
symlink, while the listxattrat operates on the referent of the symlink. */
|
||||
ssize_t llistxattrat (int dir_fd, const char *path, char *list, size_t size);
|
||||
|
||||
#endif /* XATTRS_AT_H */
|
||||
1
paxutils
Submodule
1
paxutils
Submodule
Submodule paxutils added at d03eab65d3
2
po/.gitignore
vendored
2
po/.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
/Makevars.template~
|
||||
/Makefile.in.in~
|
||||
*.gmo
|
||||
*.mo
|
||||
*.po
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# List of files which contain translatable strings.
|
||||
|
||||
# Copyright (C) 1996, 1999, 2000, 2003, 2004, 2005, 2007 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright 1996, 1999-2000, 2003-2005, 2007, 2013-2014, 2016-2017 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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, or (at your option)
|
||||
# any later version.
|
||||
# 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,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Library files
|
||||
gnu/argmatch.c
|
||||
@@ -37,7 +37,6 @@ gnu/version-etc.c
|
||||
gnu/xalloc-die.c
|
||||
|
||||
lib/paxerror.c
|
||||
lib/paxexit.c
|
||||
lib/paxnames.c
|
||||
lib/rtapelib.c
|
||||
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
# Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
# Make GNU tar scripts.
|
||||
|
||||
## 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.
|
||||
# Copyright 2004, 2006-2007, 2013-2014, 2016-2017 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
## 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.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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/>.
|
||||
|
||||
BACKUP_LIBEXEC_SCRIPTS_LIST=backup.sh dump-remind
|
||||
BACKUP_SBIN_SCRIPTS_LIST=backup restore
|
||||
|
||||
@@ -65,9 +65,9 @@ XLIST=exclude_files
|
||||
SLEEP_TIME=15
|
||||
|
||||
# Script to be run when it's time to insert a new tape in for the next
|
||||
# volume. Administrators may want to tailor this script for their site.
|
||||
# volume. Administrators may want to tailor this script for their site.
|
||||
# If this variable isn't set, tar will use some default behavior which is
|
||||
# probably defined in the manual.
|
||||
# probably defined in the manual.
|
||||
#DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind'
|
||||
|
||||
# Message to display on the terminal while waiting for dump time. Usually
|
||||
@@ -75,26 +75,27 @@ SLEEP_TIME=15
|
||||
# entertaining than this. The awk script here saves some redundant
|
||||
# repetition, but is not really all that desirable.
|
||||
SLEEP_MESSAGE="`awk '
|
||||
BEGIN {
|
||||
BEGIN {
|
||||
for (i = 0; i < 30; i++)
|
||||
print \" \" \
|
||||
\"D O N O T T O U C H T H I S T E R M I N A L !!!!!\"
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright (C) 2004, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2004, 2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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/>.
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright (C) 2004, 2005, 2006 Free Software Foundation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013 Free Software Foundation
|
||||
|
||||
# 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 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
@@ -72,8 +73,9 @@ do
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l?*) DUMP_LEVEL=`expr $option : '-l\(.*\)'`;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
prev=--level
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
@@ -81,14 +83,13 @@ do
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
-v*) VERBOSE=`expr $option : '-v\(.*\)'`;;
|
||||
--t=*|--ti=*|--tim=*|--time=*)
|
||||
TIME=$optarg
|
||||
;;
|
||||
-t) prev=--t;;
|
||||
-t*) TIME=`expr $option : "-t\(.*\)"`;;
|
||||
--t|--ti|--tim|--time)
|
||||
prev=$option
|
||||
-t?*) TIME=`expr $option : '-t\(.*\)'`;;
|
||||
-t|--t|--ti|--tim|--time)
|
||||
prev=--time
|
||||
;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "backup (@PACKAGE_NAME@) @VERSION@"
|
||||
@@ -149,12 +150,15 @@ 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
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# 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"
|
||||
@@ -187,10 +191,10 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
"--label='`print_level` backup of ${fs} on ${remotehost} at ${NOW}'" \
|
||||
-C ${fs} .
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# '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
|
||||
@@ -237,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,21 +1,23 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013-2014, 2016-2017 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 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PROGNAME=`basename $0`
|
||||
CONFIGPATH="$SYSCONFDIR/backup"
|
||||
@@ -48,7 +50,7 @@ MT_REWIND=mt_rewind
|
||||
MT_OFFLINE=mt_offline
|
||||
MT_STATUS=mt_status
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
# Insure 'mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
@@ -211,8 +213,8 @@ init_backup() {
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
# Set logfile name
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-0''
|
||||
# They go in the directory `@sysconfdir@/log'.
|
||||
# Logfile name should be in the form 'log-1993-03-18-level-0'
|
||||
# They go in the directory '@sysconfdir@/log'.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="${LOGPATH}/log-`now`-level-${DUMP_LEVEL}"
|
||||
@@ -305,12 +307,14 @@ backup_host() {
|
||||
if [ "z${localhost}" != "z$rhost" ] ; then
|
||||
$RSH "$rhost" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" $@
|
||||
else
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# Using 'sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
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
|
||||
}
|
||||
|
||||
@@ -339,9 +343,9 @@ remote_run() {
|
||||
|
||||
license() {
|
||||
cat - <<EOF
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
This is free software. You may redistribute copies of it under the terms of
|
||||
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
|
||||
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -2,14 +2,31 @@
|
||||
# This file is included in the GNU tar distribution as an example. It is
|
||||
# not used by default unless the proper line is uncommented in backup-specs.
|
||||
# System administrators will probably want to customize this and
|
||||
# backup-specs for their site.
|
||||
# backup-specs for their site.
|
||||
#
|
||||
# This script should be run by tar with --info-script (-F) to inform
|
||||
# interested parties that a tape for the next volume of the backup needs to
|
||||
# be put in the tape drive.
|
||||
#
|
||||
# be put in the tape drive.
|
||||
|
||||
# Include location of `sendmail' and GNU finger.
|
||||
# Copyright 2004-2005, 2010, 2012-2014, 2016-2017 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 location of 'sendmail' and GNU finger.
|
||||
PATH="/usr/lib:/usr/local/gnubin:${PATH}"
|
||||
export PATH
|
||||
|
||||
@@ -25,9 +42,9 @@ MT_OFFLINE
|
||||
# which users are logged into consoles (and thus in the office and capable
|
||||
# of changing tapes).
|
||||
#
|
||||
# Certain users (like `root') aren't real users, and shouldn't be notified.
|
||||
# Neither should `zippy', `elvis', etc. (on the GNU machines) since they're
|
||||
# just test accounts.
|
||||
# Certain users (like 'root') aren't real users, and shouldn't be notified.
|
||||
# Neither should 'zippy', 'elvis', etc. (on the GNU machines) since they're
|
||||
# just test accounts.
|
||||
recipients="`
|
||||
finger .clients 2> /dev/null \
|
||||
| sed -ne '
|
||||
@@ -69,8 +86,8 @@ Cc: ${ADMINISTRATOR}
|
||||
Subject: Backup needs new tape for volume ${TAR_VOLUME}
|
||||
Reply-To: ${ADMINISTRATOR}
|
||||
|
||||
This is an automated report from the backup script running on
|
||||
`hostname`.
|
||||
This is an automated report from the backup script running on
|
||||
`hostname`.
|
||||
|
||||
Volume ${TAR_VOLUME} of the backup needs to be put in the tape drive.
|
||||
Usually whoever prepared the backup leaves labeled tapes on top of the
|
||||
@@ -92,8 +109,8 @@ Cc: ${ADMINISTRATOR}
|
||||
Subject: Volume ${TAR_VOLUME} for backup has been added
|
||||
Reply-To: ${ADMINISTRATOR}
|
||||
|
||||
This is an automated report from the backup script running on
|
||||
`hostname`.
|
||||
This is an automated report from the backup script running on
|
||||
`hostname`.
|
||||
|
||||
The backup has been continued, so for now no further attention is required.
|
||||
__EOF__
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright (C) 2004, 2006 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Restore backups.
|
||||
|
||||
# Copyright 2004, 2006, 2013-2014, 2016-2017 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 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
@@ -60,8 +62,9 @@ do
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l?*) DUMP_LEVEL=`expr $option : '-l\(.*\)'`;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
prev=--level
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
@@ -69,7 +72,7 @@ do
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
-v*) VERBOSE=`expr $option : '-v\(.*\)'`;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "restore (@PACKAGE_NAME@) @VERSION@"
|
||||
license
|
||||
|
||||
@@ -1,31 +1,67 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Display and edit the 'dev' field in tar's snapshots
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Copyright 2007, 2011, 2013-2014, 2016-2017 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, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
#
|
||||
# Author: Dustin J. Mitchell <dustin@zmanda.com>
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# tar-snapshot-edit
|
||||
#
|
||||
# This script is capable of replacing values in the 'dev' field of an
|
||||
# incremental backup 'snapshot' file. This is useful when the device
|
||||
# used to store files in a tar archive changes, without the files
|
||||
# themselves changing. This may happen when, for example, a device
|
||||
# driver changes major or minor numbers.
|
||||
#
|
||||
# It can also run a check on all the field values found in the
|
||||
# snapshot file, printing out a detailed message when it finds values
|
||||
# that would cause an "Unexpected field value in snapshot file",
|
||||
# "Numerical result out of range", or "Invalid argument" error
|
||||
# if tar were run using that snapshot file as input. (See the
|
||||
# comments included in the definition of the check_field_values
|
||||
# routine for more detailed information regarding these checks.)
|
||||
#
|
||||
#
|
||||
#
|
||||
# Author: Dustin J. Mitchell <dustin@zmanda.com>
|
||||
#
|
||||
# Modified Aug 25, 2011 by Nathan Stratton Treadway <nathanst AT ontko.com>:
|
||||
# * update Perl syntax to work correctly with more recent versions of
|
||||
# Perl. (The original code worked with in the v5.8 timeframe but
|
||||
# not with Perl v5.10.1 and later.)
|
||||
# * added a "-c" option to check the snapshot file for invalid field values.
|
||||
# * handle NFS indicator character ("+") in version 0 and 1 files
|
||||
# * preserve the original header/version line when editing version 1
|
||||
# or 2 files.
|
||||
# * tweak output formatting
|
||||
#
|
||||
# Modified March 13, 2013 by Nathan Stratton Treadway <nathanst AT ontko.com>:
|
||||
# * configure field ranges used for -c option based on the system
|
||||
# architecture (in response to the December 2012 update to GNU tar
|
||||
# enabling support for systems with signed dev_t values).
|
||||
# * when printing the list of device ids found in the snapshot file
|
||||
# (when run in the default mode), print the raw device id values
|
||||
# instead of the hex-string version in those cases where they
|
||||
# can't be converted successfully.
|
||||
|
||||
use Getopt::Std;
|
||||
use Config;
|
||||
|
||||
my %snapshot_field_ranges; # used in check_field_values function
|
||||
|
||||
## reading
|
||||
|
||||
@@ -41,14 +77,15 @@ sub read_incr_db ($) {
|
||||
$file_version = 0;
|
||||
}
|
||||
|
||||
print "file version $file_version\n";
|
||||
print "\nFile: $filename\n";
|
||||
print " Detected snapshot file version: $file_version\n\n";
|
||||
|
||||
if ($file_version == 0) {
|
||||
return read_incr_db_0($file, $header_str);
|
||||
} elsif ($file_version == 1) {
|
||||
return read_incr_db_1($file);
|
||||
return read_incr_db_1($file, $header_str);
|
||||
} elsif ($file_version == 2) {
|
||||
return read_incr_db_2($file);
|
||||
return read_incr_db_2($file, $header_str);
|
||||
} else {
|
||||
die "Unrecognized snapshot version in header '$header_str'";
|
||||
}
|
||||
@@ -62,48 +99,66 @@ sub read_incr_db_0 ($$) {
|
||||
chop $hdr_timestamp_sec;
|
||||
my $hdr_timestamp_nsec = ''; # not present in file format 0
|
||||
|
||||
my $nfs;
|
||||
my @dirs;
|
||||
|
||||
while (<$file>) {
|
||||
/^([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
/^(\+?)([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
|
||||
push @dirs, { dev=>$1,
|
||||
ino=>$2,
|
||||
name=>$3 };
|
||||
if ( $1 eq "+" ) {
|
||||
$nfs="1";
|
||||
} else {
|
||||
$nfs="0";
|
||||
}
|
||||
push @dirs, { nfs=>$nfs,
|
||||
dev=>$2,
|
||||
ino=>$3,
|
||||
name=>$4 };
|
||||
}
|
||||
|
||||
close($file);
|
||||
|
||||
# file version, timestamp, timestamp, dir list
|
||||
return [ 0, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs ];
|
||||
# file version, timestamp, timestamp, dir list, file header line
|
||||
return [ 0, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs, ""];
|
||||
}
|
||||
|
||||
sub read_incr_db_1 ($) {
|
||||
sub read_incr_db_1 ($$) {
|
||||
my $file = shift;
|
||||
my $header_str = shift;
|
||||
|
||||
|
||||
my $timestamp = <$file>; # "sec nsec"
|
||||
my ($hdr_timestamp_sec, $hdr_timestamp_nsec) = ($timestamp =~ /([0-9]*) ([0-9]*)/);
|
||||
|
||||
my $nfs;
|
||||
my @dirs;
|
||||
|
||||
while (<$file>) {
|
||||
/^([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
/^(\+?)([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
|
||||
push @dirs, { timestamp_sec=>$1,
|
||||
timestamp_nsec=>$2,
|
||||
dev=>$3,
|
||||
ino=>$4,
|
||||
name=>$5 };
|
||||
if ( $1 eq "+" ) {
|
||||
$nfs="1";
|
||||
} else {
|
||||
$nfs="0";
|
||||
}
|
||||
|
||||
push @dirs, { nfs=>$nfs,
|
||||
timestamp_sec=>$2,
|
||||
timestamp_nsec=>$3,
|
||||
dev=>$4,
|
||||
ino=>$5,
|
||||
name=>$6 };
|
||||
}
|
||||
|
||||
close($file);
|
||||
|
||||
# file version, timestamp, timestamp, dir list
|
||||
return [ 1, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs ];
|
||||
# file version, timestamp, timestamp, dir list, file header line
|
||||
return [ 1, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs, $header_str ];
|
||||
}
|
||||
|
||||
sub read_incr_db_2 ($) {
|
||||
sub read_incr_db_2 ($$) {
|
||||
my $file = shift;
|
||||
my $header_str = shift;
|
||||
|
||||
$/="\0"; # $INPUT_RECORD_SEPARATOR
|
||||
my $hdr_timestamp_sec = <$file>;
|
||||
@@ -150,40 +205,257 @@ sub read_incr_db_2 ($) {
|
||||
close($file);
|
||||
$/ = "\n"; # reset to normal
|
||||
|
||||
# file version, timestamp, timestamp, dir list
|
||||
return [ 2, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs ];
|
||||
# file version, timestamp, timestamp, dir list, file header line
|
||||
return [ 2, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs, $header_str];
|
||||
}
|
||||
|
||||
## display
|
||||
|
||||
sub show_device_counts ($$) {
|
||||
sub show_device_counts ($) {
|
||||
my $info = shift;
|
||||
my $filename = shift;
|
||||
my %devices;
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
my $dev = ${%$dir}{'dev'};
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
my $dev = $dir->{'dev'};
|
||||
$devices{$dev}++;
|
||||
}
|
||||
|
||||
foreach $dev (sort keys %devices) {
|
||||
printf "$filename: Device 0x%04x occurs $devices{$dev} times.\n", $dev;
|
||||
my $devstr;
|
||||
foreach $dev (sort {$a <=> $b} keys %devices) {
|
||||
$devstr = sprintf ("0x%04x", $dev);
|
||||
if ( $dev > 0xffffffff or $dev < 0 or hex($devstr) != $dev ) {
|
||||
# sprintf "%x" will not return a useful value for device ids
|
||||
# that are negative or which overflow the integer size on this
|
||||
# instance of Perl, so we convert the hex string back to a
|
||||
# number, and if it doesn't (numerically) equal the original
|
||||
# device id value, we know the hex conversion hasn't worked.
|
||||
#
|
||||
# Unfortunately, since we're running in "-w" mode, Perl will
|
||||
# also print a warning message if the hex() routine is called
|
||||
# on anything larger than "0xffffffff", even in 64-bit Perl
|
||||
# where such values are actually supported... so we have to
|
||||
# avoid calling hex() at all if the device id is too large or
|
||||
# negative. (If it's negative, the conversion to an unsigned
|
||||
# integer for the "%x" specifier will mean the result will
|
||||
# always trigger hex()'s warning on a 64-bit machine.)
|
||||
#
|
||||
# These situations don't seem to occur very often, so for now
|
||||
# when they do occur, we simply print the original text value
|
||||
# that was read from the snapshot file; it will look a bit
|
||||
# funny next to the values that do print in hex, but that's
|
||||
# preferable to printing values that aren't actually correct.
|
||||
$devstr = $dev;
|
||||
}
|
||||
printf " Device %s occurs $devices{$dev} times.\n", $devstr;
|
||||
}
|
||||
}
|
||||
|
||||
## check field values
|
||||
|
||||
# initializes the global %snapshot_field_ranges hash, based on the "-a"
|
||||
# command-line option if given, otherwise based on the "archname" of
|
||||
# the current system.
|
||||
#
|
||||
# Each value in the hash is a two-element array containing the minimum
|
||||
# and maximum allowed values, respectively, for that field in the snapshot
|
||||
# file. GNU tar's allowed values for each architecture are determined
|
||||
# in the incremen.c source file, where the TYPE_MIN and TYPE_MAX
|
||||
# pre-processor expressions are used to determine the range that can be
|
||||
# expressed by the C data type used for each field; the values in the
|
||||
# array defined below should match those calculations. (For tar v1.27
|
||||
# and later, the valid ranges for a particular tar binary can easily
|
||||
# be determined using the "tar --show-snapshot-field-ranges" command.)
|
||||
|
||||
sub choose_architecture ($) {
|
||||
my $opt_a = shift;
|
||||
|
||||
my $arch = $opt_a ? $opt_a : $Config{'archname'};
|
||||
|
||||
# These ranges apply to Linux 2.4/2.6 on iX86 systems, but are used
|
||||
# by default on unrecognized/unsupported systems, too.
|
||||
%iX86_linux_field_ranges = (
|
||||
timestamp_sec => [ -2147483648, 2147483647 ], # min/max of time_t
|
||||
timestamp_nsec => [ 0, 999999999 ], # 0 to BILLION-1
|
||||
nfs => [ 0, 1 ],
|
||||
dev => [ 0, 18446744073709551615 ], # min/max of dev_t
|
||||
ino => [ 0, 4294967295 ], # min/max of ino_t
|
||||
);
|
||||
|
||||
|
||||
if ( $arch =~ m/^i[\dxX]86-linux/i ) {
|
||||
%snapshot_field_ranges = %iX86_linux_field_ranges;
|
||||
print "Checking snapshot field values using \"iX86-linux\" ranges.\n\n";
|
||||
} elsif ( $arch =~ m/^x86_64-linux/i ) {
|
||||
%snapshot_field_ranges = (
|
||||
timestamp_sec => [ -9223372036854775808, 9223372036854775807 ],
|
||||
timestamp_nsec => [ 0, 999999999 ],
|
||||
nfs => [ 0, 1 ],
|
||||
dev => [ 0, 18446744073709551615 ],
|
||||
ino => [ 0, 18446744073709551615 ],
|
||||
);
|
||||
print "Checking snapshot field values using \"x86_64-linux\" ranges.\n\n";
|
||||
} elsif ( $arch =~ m/^IA64.ARCHREV_0/i ) {
|
||||
# HP/UX running on Itanium/ia64 architecture
|
||||
%snapshot_field_ranges = (
|
||||
timestamp_sec => [ -2147483648, 2147483647 ],
|
||||
timestamp_nsec => [ 0, 999999999 ],
|
||||
nfs => [ 0, 1 ],
|
||||
dev => [ -2147483648, 2147483647 ],
|
||||
ino => [ 0, 4294967295 ],
|
||||
);
|
||||
print "Checking snapshot field values using \"IA64.ARCHREV_0\" (HP/UX) ranges.\n\n";
|
||||
} else {
|
||||
%snapshot_field_ranges = %iX86_linux_field_ranges;
|
||||
print "Unrecognized architecture \"$arch\"; defaulting to \"iX86-linux\".\n";
|
||||
print "(Use -a option to override.)\n" unless $opt_a;
|
||||
print "\n";
|
||||
}
|
||||
|
||||
if ( ref(1) ne "" ) {
|
||||
print "(\"bignum\" mode is in effect; skipping 64-bit-integer check.)\n\n"
|
||||
} else {
|
||||
# find the largest max value in the current set of ranges
|
||||
my $maxmax = 0;
|
||||
for $v (values %snapshot_field_ranges ) {
|
||||
$maxmax = $v->[1] if ($v->[1] > $maxmax);
|
||||
}
|
||||
|
||||
# "~0" translates into a platform-native integer with all bits turned
|
||||
# on -- that is, the largest value that can be represented as
|
||||
# an integer. We print a warning if our $maxmax value is greater
|
||||
# than that largest integer, since in that case Perl will switch
|
||||
# to using floats for those large max values. The wording of
|
||||
# the message assumes that the only way this situation can exist
|
||||
# is that the platform uses 32-bit integers but some of the
|
||||
# snapshot-file fields have 64-bit values.
|
||||
if ( ~0 < $maxmax ) {
|
||||
print <<EOF
|
||||
Note: this version of Perl uses 32-bit integers, which means that it
|
||||
will switch to using floating-point numbers when checking the ranges
|
||||
for 64-bit snapshot-file fields. This normally will work fine, but
|
||||
might fail to detect cases where the value in the input field value is
|
||||
only slightly out of range. (For example, a "9223372036854775808"
|
||||
might not be recognized as being larger than 9223372036854775807.)
|
||||
If you suspect you are experiencing this problem, you can try running
|
||||
the program using the "-Mbignum" option, as in
|
||||
\$ perl $0 -Mbignum -c [FILES]
|
||||
(but doing so will make the program run *much* slower).
|
||||
|
||||
EOF
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
# returns a warning message if $field_value isn't a valid string
|
||||
# representation of an integer, or if the resulting integer is out of range
|
||||
# defined by the two-element array retrieved using up the $field_name key in
|
||||
# the global %snapshot_field_ranges hash.
|
||||
sub validate_integer_field ($$) {
|
||||
my $field_value = shift;
|
||||
my $field_name = shift;
|
||||
|
||||
my ($min, $max) = @{$snapshot_field_ranges{$field_name}};
|
||||
|
||||
my $msg = "";
|
||||
|
||||
if ( not $field_value =~ /^-?\d+$/ ) {
|
||||
$msg = " $field_name value contains invalid characters: \"$field_value\"\n";
|
||||
} else {
|
||||
if ( $field_value < $min ) {
|
||||
$msg = " $field_name value too low: \"$field_value\" < $min \n";
|
||||
} elsif ( $field_value > $max ) {
|
||||
$msg = " $field_name value too high: \"$field_value\" > $max \n";
|
||||
}
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
|
||||
# This routine loops through each directory entry in the $info data
|
||||
# structure and prints a warning message if tar would abort with an
|
||||
# "Unexpected field value in snapshot file", "Numerical result out of
|
||||
# range", or "Invalid argument" error upon reading this snapshot file.
|
||||
#
|
||||
# (Note that the "Unexpected field value in snapshot file" error message
|
||||
# was introduced along with the change to snapshot file format "2",
|
||||
# starting with tar v1.16 [or, more precisely, v1.15.91], while the
|
||||
# other two were introduced in v1.27.)
|
||||
#
|
||||
# The checks here are intended to match those found in the incremen.c
|
||||
# source file. See the choose_architecture() function (above) for more
|
||||
# information on how to configure the range of values considered valid
|
||||
# by this script.
|
||||
#
|
||||
# (Note: the checks here are taken from the code that processes
|
||||
# version 2 snapshot files, but to keep things simple we apply those
|
||||
# same checks to files having earlier versions -- but only for
|
||||
# the fields that actually exist in those input files.)
|
||||
|
||||
sub check_field_values ($) {
|
||||
my $info = shift;
|
||||
|
||||
my $msg;
|
||||
my $error_found = 0;
|
||||
|
||||
print " Checking field values in snapshot file...\n";
|
||||
|
||||
$snapver = $info->[0];
|
||||
|
||||
$msg = "";
|
||||
$msg .= validate_integer_field($info->[1], 'timestamp_sec');
|
||||
if ($snapver >= 1) {
|
||||
$msg .= validate_integer_field($info->[2], 'timestamp_nsec');
|
||||
}
|
||||
if ( $msg ne "" ) {
|
||||
$error_found = 1;
|
||||
print "\n shapshot file header:\n";
|
||||
print $msg;
|
||||
}
|
||||
|
||||
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
|
||||
$msg = "";
|
||||
|
||||
$msg .= validate_integer_field($dir->{'nfs'}, 'nfs');
|
||||
if ($snapver >= 1) {
|
||||
$msg .= validate_integer_field($dir->{'timestamp_sec'}, 'timestamp_sec');
|
||||
$msg .= validate_integer_field($dir->{'timestamp_nsec'}, 'timestamp_nsec');
|
||||
}
|
||||
$msg .= validate_integer_field($dir->{'dev'}, 'dev');
|
||||
$msg .= validate_integer_field($dir->{'ino'}, 'ino');
|
||||
|
||||
if ( $msg ne "" ) {
|
||||
$error_found = 1;
|
||||
print "\n directory: $dir->{'name'}\n";
|
||||
print $msg;
|
||||
}
|
||||
}
|
||||
|
||||
print "\n Snapshot field value check complete" ,
|
||||
$error_found ? "" : ", no errors found" ,
|
||||
".\n";
|
||||
}
|
||||
|
||||
## editing
|
||||
|
||||
sub replace_device_number ($@) {
|
||||
my $info = shift(@_);
|
||||
my @repl = @_;
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
foreach $x (@repl) {
|
||||
if (${%$dir}{'dev'} eq $$x[0]) {
|
||||
${%$dir}{'dev'} = $$x[1];
|
||||
last;
|
||||
}
|
||||
my $count = 0;
|
||||
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
foreach $x (@repl) {
|
||||
if ($dir->{'dev'} eq $$x[0]) {
|
||||
$dir->{'dev'} = $$x[1];
|
||||
$count++;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
print " Updated $count records.\n"
|
||||
}
|
||||
|
||||
## writing
|
||||
@@ -211,14 +483,17 @@ sub write_incr_db ($$) {
|
||||
sub write_incr_db_0 ($$) {
|
||||
my $info = shift;
|
||||
my $file = shift;
|
||||
|
||||
|
||||
my $timestamp_sec = $info->[1];
|
||||
print $file "$timestamp_sec\n";
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
print $file "${%$dir}{'dev'} ";
|
||||
print $file "${%$dir}{'ino'} ";
|
||||
print $file "${%$dir}{'name'}\n";
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
if ($dir->{'nfs'}) {
|
||||
print $file '+'
|
||||
}
|
||||
print $file "$dir->{'dev'} ";
|
||||
print $file "$dir->{'ino'} ";
|
||||
print $file "$dir->{'name'}\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,19 +501,22 @@ sub write_incr_db_0 ($$) {
|
||||
sub write_incr_db_1 ($$) {
|
||||
my $info = shift;
|
||||
my $file = shift;
|
||||
|
||||
print $file "GNU tar-1.15-1\n";
|
||||
|
||||
print $file $info->[4];
|
||||
|
||||
my $timestamp_sec = $info->[1];
|
||||
my $timestamp_nsec = $info->[2];
|
||||
print $file "$timestamp_sec $timestamp_nsec\n";
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
print $file "${%$dir}{'timestamp_sec'} ";
|
||||
print $file "${%$dir}{'timestamp_nsec'} ";
|
||||
print $file "${%$dir}{'dev'} ";
|
||||
print $file "${%$dir}{'ino'} ";
|
||||
print $file "${%$dir}{'name'}\n";
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
if ($dir->{'nfs'}) {
|
||||
print $file '+'
|
||||
}
|
||||
print $file "$dir->{'timestamp_sec'} ";
|
||||
print $file "$dir->{'timestamp_nsec'} ";
|
||||
print $file "$dir->{'dev'} ";
|
||||
print $file "$dir->{'ino'} ";
|
||||
print $file "$dir->{'name'}\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,22 +524,22 @@ sub write_incr_db_1 ($$) {
|
||||
sub write_incr_db_2 ($$) {
|
||||
my $info = shift;
|
||||
my $file = shift;
|
||||
|
||||
print $file "GNU tar-1.16-2\n";
|
||||
|
||||
print $file $info->[4];
|
||||
|
||||
my $timestamp_sec = $info->[1];
|
||||
my $timestamp_nsec = $info->[2];
|
||||
print $file $timestamp_sec . "\0";
|
||||
print $file $timestamp_nsec . "\0";
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
print $file ${%$dir}{'nfs'} . "\0";
|
||||
print $file ${%$dir}{'timestamp_sec'} . "\0";
|
||||
print $file ${%$dir}{'timestamp_nsec'} . "\0";
|
||||
print $file ${%$dir}{'dev'} . "\0";
|
||||
print $file ${%$dir}{'ino'} . "\0";
|
||||
print $file ${%$dir}{'name'} . "\0";
|
||||
foreach my $dirent (@{${%$dir}{'dirents'}}) {
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
print $file $dir->{'nfs'} . "\0";
|
||||
print $file $dir->{'timestamp_sec'} . "\0";
|
||||
print $file $dir->{'timestamp_nsec'} . "\0";
|
||||
print $file $dir->{'dev'} . "\0";
|
||||
print $file $dir->{'ino'} . "\0";
|
||||
print $file $dir->{'name'} . "\0";
|
||||
foreach my $dirent (@{$dir->{'dirents'}}) {
|
||||
print $file $dirent . "\0";
|
||||
}
|
||||
print $file "\0";
|
||||
@@ -271,9 +549,10 @@ sub write_incr_db_2 ($$) {
|
||||
## main
|
||||
|
||||
sub main {
|
||||
our ($opt_b, $opt_r, $opt_h);
|
||||
getopts('br:h');
|
||||
HELP_MESSAGE() if ($opt_h || $#ARGV == -1 || ($opt_b && !$opt_r));
|
||||
our ($opt_b, $opt_r, $opt_h, $opt_c, $opt_a);
|
||||
getopts('br:hca:');
|
||||
HELP_MESSAGE() if ($opt_h || $#ARGV == -1 || ($opt_b && !$opt_r) ||
|
||||
($opt_a && !$opt_c) || ($opt_r && $opt_c) );
|
||||
|
||||
my @repl;
|
||||
if ($opt_r) {
|
||||
@@ -283,31 +562,61 @@ sub main {
|
||||
}
|
||||
}
|
||||
|
||||
choose_architecture($opt_a) if ($opt_c);
|
||||
|
||||
foreach my $snapfile (@ARGV) {
|
||||
my $info = read_incr_db($snapfile);
|
||||
if ($opt_r ) {
|
||||
if ($opt_r) {
|
||||
if ($opt_b) {
|
||||
rename($snapfile, $snapfile . "~") || die "Could not rename '$snapfile' to backup";
|
||||
}
|
||||
|
||||
replace_device_number($info, @repl);
|
||||
write_incr_db($info, $snapfile);
|
||||
} elsif ($opt_c) {
|
||||
check_field_values($info);
|
||||
} else {
|
||||
show_device_counts($info, $snapfile);
|
||||
show_device_counts($info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub HELP_MESSAGE {
|
||||
print "Usage: tar-snapshot-edit.pl [-r 'DEV1-DEV2[,DEV3-DEV4...]' [-b]] SNAPFILE [SNAPFILE [..]]\n";
|
||||
print "\n";
|
||||
print " Without -r, summarize the 'device' values in each SNAPFILE.\n";
|
||||
print "\n";
|
||||
print " With -r, replace occurrences of DEV1 with DEV2 in each SNAPFILE.\n";
|
||||
print " DEV1 and DEV2 may be specified in hex (e.g., 0xfe01), decimal (e.g.,\n";
|
||||
print " 65025), or MAJ:MIN (e.g., 254:1). To replace multiple occurrences,\n";
|
||||
print " separate them with commas. If -b is also specified, backup\n";
|
||||
print " files (ending with '~') will be created.\n";
|
||||
print <<EOF;
|
||||
|
||||
Usage:
|
||||
tar-snapshot-edit SNAPFILE [SNAPFILE [...]]
|
||||
tar-snapshot-edit -r 'DEV1-DEV2[,DEV3-DEV4...]' [-b] SNAPFILE [SNAPFILE [...]]
|
||||
tar-snapshot-edit -c [-aARCH] SNAPFILE [SNAPFILE [...]]
|
||||
|
||||
With no options specified: print a summary of the 'device' values
|
||||
found in each SNAPFILE.
|
||||
|
||||
With -r: replace occurrences of DEV1 with DEV2 in each SNAPFILE.
|
||||
DEV1 and DEV2 may be specified in hex (e.g., 0xfe01), decimal (e.g.,
|
||||
65025), or MAJ:MIN (e.g., 254:1). To replace multiple occurrences,
|
||||
separate them with commas. If -b is also specified, backup files
|
||||
(ending with '~') will be created.
|
||||
|
||||
With -c: Check the field values in each SNAPFILE and print warning
|
||||
messages if any invalid values are found. (An invalid value is one
|
||||
that would cause \"tar\" to abort with an error message such as
|
||||
Unexpected field value in snapshot file
|
||||
Numerical result out of range
|
||||
or
|
||||
Invalid argument
|
||||
as it processed the snapshot file.)
|
||||
|
||||
Normally the program automatically chooses the valid ranges for
|
||||
the fields based on the current system's architecture, but the
|
||||
-a option can be used to override the selection, e.g. in order
|
||||
to validate a snapshot file generated on a some other system.
|
||||
(Currently only three architectures are supported, "iX86-linux",
|
||||
"x86_64-linux", and "IA64.ARCHREV_0" [HP/UX running on Itanium/ia64],
|
||||
and if the current system isn't recognized, then the iX86-linux
|
||||
values are used by default.)
|
||||
|
||||
EOF
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
# concatenates a GNU tar multi-volume archive into a single tar archive.
|
||||
# Author: Bruno Haible <bruno@clisp.org>, Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
# Copyright 2004-2005, 2010, 2013-2014, 2016-2017 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# dump_type FILE [N]
|
||||
# Print type character from block N (default 0) of tar archive FILE
|
||||
dump_type() {
|
||||
@@ -35,8 +53,7 @@ do
|
||||
fi
|
||||
if [ "$T" = "M" ]; then
|
||||
SKIP=$(($SKIP + 1))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
dd skip=$SKIP if="$f"
|
||||
dd skip=$SKIP if="$f"
|
||||
done
|
||||
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
/* xsparse - expands compressed sparse file images extracted from GNU tar
|
||||
archives.
|
||||
|
||||
Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2006-2007, 2010, 2013-2014, 2016-2017 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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/>.
|
||||
|
||||
Written by Sergey Poznyakoff */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
@@ -39,7 +42,7 @@
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
off_t numbytes;
|
||||
};
|
||||
|
||||
char *progname;
|
||||
@@ -129,12 +132,12 @@ get_var (FILE *fp, char **name, char **value)
|
||||
static char *buffer;
|
||||
static size_t bufsize = OFF_T_STRSIZE_BOUND;
|
||||
char *p, *q;
|
||||
|
||||
|
||||
buffer = emalloc (bufsize);
|
||||
do
|
||||
{
|
||||
size_t len, s;
|
||||
|
||||
|
||||
if (!fgets (buffer, bufsize, fp))
|
||||
return 0;
|
||||
len = strlen (buffer);
|
||||
@@ -163,7 +166,7 @@ get_var (FILE *fp, char **name, char **value)
|
||||
p += 11;
|
||||
q = strchr (p, '=');
|
||||
if (!q)
|
||||
die (1, "malformed header: expected `=' not found");
|
||||
die (1, "malformed header: expected '=' not found");
|
||||
*q++ = 0;
|
||||
q[strlen (q) - 1] = 0;
|
||||
*name = p;
|
||||
@@ -186,14 +189,14 @@ read_xheader (char *name)
|
||||
|
||||
if (verbose)
|
||||
printf ("Reading extended header file\n");
|
||||
|
||||
|
||||
while (get_var (fp, &kw, &val))
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Found variable GNU.sparse.%s = %s\n", kw, val);
|
||||
|
||||
|
||||
if (expect && strcmp (kw, expect))
|
||||
die (1, "bad keyword sequence: expected `%s' but found `%s'",
|
||||
die (1, "bad keyword sequence: expected '%s' but found '%s'",
|
||||
expect, kw);
|
||||
expect = NULL;
|
||||
if (strcmp (kw, "name") == 0)
|
||||
@@ -226,7 +229,7 @@ read_xheader (char *name)
|
||||
}
|
||||
else if (strcmp (kw, "numbytes") == 0)
|
||||
{
|
||||
sparse_map[i++].numbytes = string_to_size (val, NULL);
|
||||
sparse_map[i++].numbytes = string_to_off (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "map") == 0)
|
||||
{
|
||||
@@ -234,13 +237,13 @@ read_xheader (char *name)
|
||||
{
|
||||
sparse_map[i].offset = string_to_off (val, &val);
|
||||
if (*val != ',')
|
||||
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
|
||||
die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
|
||||
*val);
|
||||
sparse_map[i].numbytes = string_to_size (val+1, &val);
|
||||
sparse_map[i].numbytes = string_to_off (val+1, &val);
|
||||
if (*val != ',')
|
||||
{
|
||||
if (!(*val == 0 && i == sparse_map_size-1))
|
||||
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
|
||||
die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
|
||||
*val);
|
||||
}
|
||||
else
|
||||
@@ -251,7 +254,7 @@ read_xheader (char *name)
|
||||
}
|
||||
}
|
||||
if (expect)
|
||||
die (1, "bad keyword sequence: expected `%s' not found", expect);
|
||||
die (1, "bad keyword sequence: expected '%s' not found", expect);
|
||||
if (version_major == 0 && sparse_map_size == 0)
|
||||
die (1, "size of the sparse map unknown");
|
||||
if (i != sparse_map_size)
|
||||
@@ -267,7 +270,7 @@ read_map (FILE *ifp)
|
||||
|
||||
if (verbose)
|
||||
printf ("Reading v.1.0 sparse map\n");
|
||||
|
||||
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map_size = string_to_size (nbuf, NULL);
|
||||
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
|
||||
@@ -277,31 +280,34 @@ read_map (FILE *ifp)
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map[i].offset = string_to_off (nbuf, NULL);
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map[i].numbytes = string_to_size (nbuf, NULL);
|
||||
sparse_map[i].numbytes = string_to_off (nbuf, NULL);
|
||||
}
|
||||
|
||||
fseeko (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
|
||||
SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
expand_sparse (FILE *sfp, int ofd)
|
||||
{
|
||||
size_t i;
|
||||
size_t maxbytes = 0;
|
||||
off_t max_numbytes = 0;
|
||||
size_t maxbytes;
|
||||
char *buffer;
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
if (maxbytes < sparse_map[i].numbytes)
|
||||
maxbytes = sparse_map[i].numbytes;
|
||||
|
||||
if (max_numbytes < sparse_map[i].numbytes)
|
||||
max_numbytes = sparse_map[i].numbytes;
|
||||
|
||||
maxbytes = max_numbytes < SIZE_MAX ? max_numbytes : SIZE_MAX;
|
||||
|
||||
for (buffer = malloc (maxbytes); !buffer; maxbytes /= 2)
|
||||
if (maxbytes == 0)
|
||||
die (1, "not enough memory");
|
||||
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
{
|
||||
size_t size = sparse_map[i].numbytes;
|
||||
off_t size = sparse_map[i].numbytes;
|
||||
|
||||
if (size == 0)
|
||||
ftruncate (ofd, sparse_map[i].offset);
|
||||
@@ -342,13 +348,13 @@ guess_outname (char *name)
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
|
||||
|
||||
if (name[0] == '.' && name[1] == '/')
|
||||
name += 2;
|
||||
|
||||
p = name + strlen (name) - 1;
|
||||
s = NULL;
|
||||
|
||||
|
||||
for (; p > name && *p != '/'; p--)
|
||||
;
|
||||
if (*p == '/')
|
||||
@@ -358,7 +364,7 @@ guess_outname (char *name)
|
||||
for (p--; p > name && *p != '/'; p--)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
if (*p != '/')
|
||||
{
|
||||
if (s)
|
||||
@@ -389,7 +395,7 @@ main (int argc, char **argv)
|
||||
FILE *ifp;
|
||||
struct stat st;
|
||||
int ofd;
|
||||
|
||||
|
||||
progname = argv[0];
|
||||
while ((c = getopt (argc, argv, "hnvx:")) != EOF)
|
||||
{
|
||||
@@ -408,7 +414,7 @@ main (int argc, char **argv)
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
exit (1);
|
||||
}
|
||||
@@ -429,30 +435,30 @@ main (int argc, char **argv)
|
||||
|
||||
if (stat (inname, &st))
|
||||
die (1, "cannot stat %s (%d)", inname, errno);
|
||||
|
||||
|
||||
ifp = fopen (inname, "r");
|
||||
if (ifp == NULL)
|
||||
die (1, "cannot open file %s (%d)", inname, errno);
|
||||
|
||||
|
||||
if (!xheader_file || version_major == 1)
|
||||
read_map (ifp);
|
||||
|
||||
if (!outname)
|
||||
guess_outname (inname);
|
||||
|
||||
|
||||
ofd = open (outname, O_RDWR|O_CREAT|O_TRUNC, st.st_mode);
|
||||
if (ofd == -1)
|
||||
die (1, "cannot open file %s (%d)", outname, errno);
|
||||
|
||||
if (verbose)
|
||||
printf ("Expanding file `%s' to `%s'\n", inname, outname);
|
||||
printf ("Expanding file '%s' to '%s'\n", inname, outname);
|
||||
|
||||
if (dry_run)
|
||||
{
|
||||
printf ("Finished dry run\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
expand_sparse (ifp, ofd);
|
||||
|
||||
fclose (ifp);
|
||||
@@ -460,7 +466,7 @@ main (int argc, char **argv)
|
||||
|
||||
if (verbose)
|
||||
printf ("Done\n");
|
||||
|
||||
|
||||
if (outsize)
|
||||
{
|
||||
if (stat (outname, &st))
|
||||
@@ -468,7 +474,6 @@ main (int argc, char **argv)
|
||||
if (st.st_size != outsize)
|
||||
die (1, "expanded file has wrong size");
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
# Makefile for GNU tar sources.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2006,
|
||||
# 2007, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 1994-1997, 1999-2001, 2003, 2006-2007, 2009, 2013-2014,
|
||||
# 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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/>.
|
||||
|
||||
bin_PROGRAMS = tar
|
||||
|
||||
noinst_HEADERS = arith.h common.h tar.h
|
||||
noinst_HEADERS = arith.h common.h tar.h xattrs.h
|
||||
tar_SOURCES = \
|
||||
buffer.c\
|
||||
checkpoint.c\
|
||||
@@ -28,10 +28,12 @@ tar_SOURCES = \
|
||||
create.c\
|
||||
delete.c\
|
||||
exit.c\
|
||||
exclist.c\
|
||||
extract.c\
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
list.c\
|
||||
map.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
sparse.c\
|
||||
@@ -42,10 +44,12 @@ tar_SOURCES = \
|
||||
unlink.c\
|
||||
update.c\
|
||||
utf8.c\
|
||||
warning.c
|
||||
warning.c\
|
||||
xattrs.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
|
||||
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 = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
|
||||
18
src/arith.h
18
src/arith.h
@@ -1,19 +1,21 @@
|
||||
/* Long integers, for GNU tar.
|
||||
Copyright 1999, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1999, 2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
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,
|
||||
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, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Handle large integers for calculating big tape lengths and the
|
||||
like. In practice, double precision does for now. On the vast
|
||||
@@ -22,6 +24,6 @@
|
||||
blocked in 1 kB boundaries. We'll need arbitrary precision
|
||||
arithmetic anyway once we get into the 2**64 range, so there's no
|
||||
point doing anything fancy before then. */
|
||||
|
||||
|
||||
#define TARLONG_FORMAT "%.0f"
|
||||
typedef double tarlong;
|
||||
|
||||
712
src/buffer.c
712
src/buffer.c
File diff suppressed because it is too large
Load Diff
344
src/checkpoint.c
344
src/checkpoint.c
@@ -1,22 +1,28 @@
|
||||
/* Checkpoint management for tar.
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
Copyright 2007, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
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 <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include "fprintftime.h"
|
||||
|
||||
enum checkpoint_opcode
|
||||
{
|
||||
@@ -25,7 +31,8 @@ enum checkpoint_opcode
|
||||
cop_echo,
|
||||
cop_ttyout,
|
||||
cop_sleep,
|
||||
cop_exec
|
||||
cop_exec,
|
||||
cop_totals
|
||||
};
|
||||
|
||||
struct checkpoint_action
|
||||
@@ -77,7 +84,7 @@ void
|
||||
checkpoint_compile_action (const char *str)
|
||||
{
|
||||
struct checkpoint_action *act;
|
||||
|
||||
|
||||
if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
|
||||
alloc_action (cop_dot);
|
||||
else if (strcmp (str, "bell") == 0)
|
||||
@@ -108,87 +115,232 @@ checkpoint_compile_action (const char *str)
|
||||
act = alloc_action (cop_sleep);
|
||||
act->v.time = n;
|
||||
}
|
||||
else if (strcmp (str, "totals") == 0)
|
||||
alloc_action (cop_totals);
|
||||
else
|
||||
FATAL_ERROR ((0, 0, _("%s: unknown checkpoint action"), str));
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_finish_compile ()
|
||||
checkpoint_finish_compile (void)
|
||||
{
|
||||
if (checkpoint_option)
|
||||
{
|
||||
if (!checkpoint_action)
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
checkpoint_compile_action ("echo");
|
||||
}
|
||||
else if (checkpoint_action)
|
||||
/* Otherwise, set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
}
|
||||
|
||||
char *
|
||||
expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
|
||||
{
|
||||
const char *opstr = do_write ? gettext ("write") : gettext ("read");
|
||||
size_t opstrlen = strlen (opstr);
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char *cps = STRINGIFY_BIGINT (cpn, uintbuf);
|
||||
size_t cpslen = strlen (cps);
|
||||
const char *ip;
|
||||
char *op;
|
||||
char *output;
|
||||
size_t outlen = strlen (input); /* Initial guess */
|
||||
static const char *checkpoint_total_format[] = {
|
||||
"R",
|
||||
"W",
|
||||
"D"
|
||||
};
|
||||
|
||||
/* Fix the initial length guess */
|
||||
for (ip = input; (ip = strchr (ip, '%')) != NULL; )
|
||||
static long
|
||||
getwidth (FILE *fp)
|
||||
{
|
||||
char const *columns;
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize ws;
|
||||
if (ioctl (fileno (fp), TIOCGWINSZ, &ws) == 0 && 0 < ws.ws_col)
|
||||
return ws.ws_col;
|
||||
#endif
|
||||
|
||||
columns = getenv ("COLUMNS");
|
||||
if (columns)
|
||||
{
|
||||
switch (ip[1])
|
||||
{
|
||||
case 'u':
|
||||
outlen += cpslen - 2;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
outlen += opstrlen - 2;
|
||||
}
|
||||
ip++;
|
||||
long int col = strtol (columns, NULL, 10);
|
||||
if (0 < col)
|
||||
return col;
|
||||
}
|
||||
|
||||
output = xmalloc (outlen + 1);
|
||||
for (ip = input, op = output; *ip; )
|
||||
return 80;
|
||||
}
|
||||
|
||||
static char *
|
||||
getarg (const char *input, const char ** endp, char **argbuf, size_t *arglen)
|
||||
{
|
||||
if (input[0] == '{')
|
||||
{
|
||||
char *p = strchr (input + 1, '}');
|
||||
if (p)
|
||||
{
|
||||
size_t n = p - input;
|
||||
if (n > *arglen)
|
||||
{
|
||||
*arglen = n;
|
||||
*argbuf = xrealloc (*argbuf, *arglen);
|
||||
}
|
||||
n--;
|
||||
memcpy (*argbuf, input + 1, n);
|
||||
(*argbuf)[n] = 0;
|
||||
*endp = p + 1;
|
||||
return *argbuf;
|
||||
}
|
||||
}
|
||||
|
||||
*endp = input;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tty_cleanup;
|
||||
|
||||
static const char *def_format =
|
||||
"%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r";
|
||||
|
||||
static int
|
||||
format_checkpoint_string (FILE *fp, size_t len,
|
||||
const char *input, bool do_write,
|
||||
unsigned cpn)
|
||||
{
|
||||
const char *opstr = do_write ? gettext ("write") : gettext ("read");
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char *cps = STRINGIFY_BIGINT (cpn, uintbuf);
|
||||
const char *ip;
|
||||
|
||||
static char *argbuf = NULL;
|
||||
static size_t arglen = 0;
|
||||
char *arg = NULL;
|
||||
|
||||
if (!input)
|
||||
{
|
||||
if (do_write)
|
||||
/* TRANSLATORS: This is a "checkpoint of write operation",
|
||||
*not* "Writing a checkpoint".
|
||||
E.g. in Spanish "Punto de comprobaci@'on de escritura",
|
||||
*not* "Escribiendo un punto de comprobaci@'on" */
|
||||
input = gettext ("Write checkpoint %u");
|
||||
else
|
||||
/* TRANSLATORS: This is a "checkpoint of read operation",
|
||||
*not* "Reading a checkpoint".
|
||||
E.g. in Spanish "Punto de comprobaci@'on de lectura",
|
||||
*not* "Leyendo un punto de comprobaci@'on" */
|
||||
input = gettext ("Read checkpoint %u");
|
||||
}
|
||||
|
||||
for (ip = input; *ip; ip++)
|
||||
{
|
||||
if (*ip == '%')
|
||||
{
|
||||
switch (*++ip)
|
||||
if (*++ip == '{')
|
||||
{
|
||||
arg = getarg (ip, &ip, &argbuf, &arglen);
|
||||
if (!arg)
|
||||
{
|
||||
fputc ('%', fp);
|
||||
fputc (*ip, fp);
|
||||
len += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (*ip)
|
||||
{
|
||||
case 'c':
|
||||
len += format_checkpoint_string (fp, len, def_format, do_write,
|
||||
cpn);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
op = stpcpy (op, cps);
|
||||
fputs (cps, fp);
|
||||
len += strlen (cps);
|
||||
break;
|
||||
|
||||
|
||||
case 's':
|
||||
op = stpcpy (op, opstr);
|
||||
fputs (opstr, fp);
|
||||
len += strlen (opstr);
|
||||
break;
|
||||
|
||||
|
||||
case 'd':
|
||||
len += fprintf (fp, "%.0f", compute_duration ());
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
{
|
||||
const char **fmt = checkpoint_total_format, *fmtbuf[3];
|
||||
struct wordsplit ws;
|
||||
compute_duration ();
|
||||
|
||||
if (arg)
|
||||
{
|
||||
ws.ws_delim = ",";
|
||||
if (wordsplit (arg, &ws, WRDSF_NOVAR | WRDSF_NOCMD |
|
||||
WRDSF_QUOTE | WRDSF_DELIM))
|
||||
ERROR ((0, 0, _("cannot split string '%s': %s"),
|
||||
arg, wordsplit_strerror (&ws)));
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ws.ws_wordc; i++)
|
||||
fmtbuf[i] = ws.ws_wordv[i];
|
||||
for (; i < 3; i++)
|
||||
fmtbuf[i] = NULL;
|
||||
fmt = fmtbuf;
|
||||
}
|
||||
}
|
||||
len += format_total_stats (fp, fmt, ',', 0);
|
||||
if (arg)
|
||||
wordsplit_free (&ws);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
{
|
||||
struct timeval tv;
|
||||
struct tm *tm;
|
||||
const char *fmt = arg ? arg : "%c";
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
tm = localtime (&tv.tv_sec);
|
||||
len += fprintftime (fp, fmt, tm, 0, tv.tv_usec * 1000);
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
{
|
||||
long w = arg ? strtol (arg, NULL, 10) : getwidth (fp);
|
||||
for (; w > len; len++)
|
||||
fputc (' ', fp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*op++ = '%';
|
||||
*op++ = *ip;
|
||||
fputc ('%', fp);
|
||||
fputc (*ip, fp);
|
||||
len += 2;
|
||||
break;
|
||||
}
|
||||
ip++;
|
||||
arg = NULL;
|
||||
}
|
||||
else
|
||||
*op++ = *ip++;
|
||||
{
|
||||
fputc (*ip, fp);
|
||||
if (*ip == '\r')
|
||||
{
|
||||
len = 0;
|
||||
tty_cleanup = 1;
|
||||
}
|
||||
else
|
||||
len++;
|
||||
}
|
||||
}
|
||||
*op = 0;
|
||||
return output;
|
||||
fflush (fp);
|
||||
return len;
|
||||
}
|
||||
|
||||
static FILE *tty = NULL;
|
||||
|
||||
static void
|
||||
run_checkpoint_actions (bool do_write)
|
||||
{
|
||||
struct checkpoint_action *p;
|
||||
FILE *tty = NULL;
|
||||
|
||||
|
||||
for (p = checkpoint_action; p; p = p->next)
|
||||
{
|
||||
switch (p->opcode)
|
||||
@@ -207,58 +359,64 @@ run_checkpoint_actions (bool do_write)
|
||||
fflush (tty);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case cop_echo:
|
||||
{
|
||||
char *tmp;
|
||||
const char *str = p->v.command;
|
||||
if (!str)
|
||||
{
|
||||
if (do_write)
|
||||
/* TRANSLATORS: This is a ``checkpoint of write operation'',
|
||||
*not* ``Writing a checkpoint''.
|
||||
E.g. in Spanish ``Punto de comprobaci@'on de escritura'',
|
||||
*not* ``Escribiendo un punto de comprobaci@'on'' */
|
||||
str = gettext ("Write checkpoint %u");
|
||||
else
|
||||
/* TRANSLATORS: This is a ``checkpoint of read operation'',
|
||||
*not* ``Reading a checkpoint''.
|
||||
E.g. in Spanish ``Punto de comprobaci@'on de lectura'',
|
||||
*not* ``Leyendo un punto de comprobaci@'on'' */
|
||||
str = gettext ("Read checkpoint %u");
|
||||
}
|
||||
tmp = expand_checkpoint_string (str, do_write, checkpoint);
|
||||
WARN ((0, 0, "%s", tmp));
|
||||
free (tmp);
|
||||
int n = fprintf (stderr, "%s: ", program_name);
|
||||
format_checkpoint_string (stderr, n, p->v.command, do_write,
|
||||
checkpoint);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case cop_ttyout:
|
||||
if (!tty)
|
||||
tty = fopen ("/dev/tty", "w");
|
||||
if (tty)
|
||||
{
|
||||
char *tmp = expand_checkpoint_string (p->v.command, do_write,
|
||||
checkpoint);
|
||||
fprintf (tty, "%s", tmp);
|
||||
fflush (tty);
|
||||
free (tmp);
|
||||
}
|
||||
format_checkpoint_string (tty, 0, p->v.command, do_write,
|
||||
checkpoint);
|
||||
break;
|
||||
|
||||
|
||||
case cop_sleep:
|
||||
sleep (p->v.time);
|
||||
break;
|
||||
|
||||
|
||||
case cop_exec:
|
||||
sys_exec_checkpoint_script (p->v.command,
|
||||
archive_name_cursor[0],
|
||||
checkpoint);
|
||||
break;
|
||||
|
||||
case cop_totals:
|
||||
compute_duration ();
|
||||
print_total_stats ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_flush_actions (void)
|
||||
{
|
||||
struct checkpoint_action *p;
|
||||
|
||||
for (p = checkpoint_action; p; p = p->next)
|
||||
{
|
||||
switch (p->opcode)
|
||||
{
|
||||
case cop_ttyout:
|
||||
if (tty && tty_cleanup)
|
||||
{
|
||||
long w = getwidth (tty);
|
||||
while (w--)
|
||||
fputc (' ', tty);
|
||||
fputc ('\r', tty);
|
||||
fflush (tty);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* nothing */;
|
||||
}
|
||||
}
|
||||
if (tty)
|
||||
fclose (tty);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -266,5 +424,15 @@ checkpoint_run (bool do_write)
|
||||
{
|
||||
if (checkpoint_option && !(++checkpoint % checkpoint_option))
|
||||
run_checkpoint_actions (do_write);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_finish (void)
|
||||
{
|
||||
if (checkpoint_option)
|
||||
{
|
||||
checkpoint_flush_actions ();
|
||||
if (tty)
|
||||
fclose (tty);
|
||||
}
|
||||
}
|
||||
|
||||
360
src/common.h
360
src/common.h
@@ -1,22 +1,22 @@
|
||||
/* Common declarations for the tar program.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
|
||||
Inc.
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2010, 2012-2017 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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/>. */
|
||||
|
||||
/* Declare the GNU tar archive format. */
|
||||
#include "tar.h"
|
||||
@@ -44,6 +44,12 @@
|
||||
# define GLOBAL extern
|
||||
#endif
|
||||
|
||||
#if 7 <= __GNUC__
|
||||
# define FALLTHROUGH __attribute__ ((__fallthrough__))
|
||||
#else
|
||||
# define FALLTHROUGH ((void) 0)
|
||||
#endif
|
||||
|
||||
#define TAREXIT_SUCCESS PAXEXIT_SUCCESS
|
||||
#define TAREXIT_DIFFERS PAXEXIT_DIFFERS
|
||||
#define TAREXIT_FAILURE PAXEXIT_FAILURE
|
||||
@@ -70,6 +76,11 @@
|
||||
#define LG_8 3
|
||||
#define LG_64 6
|
||||
#define LG_256 8
|
||||
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef COMMON_INLINE
|
||||
# define COMMON_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
/* Information gleaned from the command line. */
|
||||
|
||||
@@ -105,6 +116,8 @@ GLOBAL bool absolute_names_option;
|
||||
|
||||
/* Display file times in UTC */
|
||||
GLOBAL bool utc_option;
|
||||
/* Output file timestamps to the full resolution */
|
||||
GLOBAL bool full_time_option;
|
||||
|
||||
/* This variable tells how to interpret newer_mtime_option, below. If zero,
|
||||
files get archived if their mtime is not less than newer_mtime_option.
|
||||
@@ -136,9 +149,6 @@ GLOBAL const char *use_compress_program_option;
|
||||
GLOBAL bool dereference_option;
|
||||
GLOBAL bool hard_dereference_option;
|
||||
|
||||
/* Print a message if not all links are dumped */
|
||||
GLOBAL int check_links_option;
|
||||
|
||||
/* Patterns that match file names to be excluded. */
|
||||
GLOBAL struct exclude *excluded;
|
||||
|
||||
@@ -156,7 +166,8 @@ enum exclusion_tag_type
|
||||
};
|
||||
|
||||
/* Specified value to be put into tar file in place of stat () results, or
|
||||
just -1 if such an override should not take place. */
|
||||
just null and -1 if such an override should not take place. */
|
||||
GLOBAL char const *group_name_option;
|
||||
GLOBAL gid_t group_option;
|
||||
|
||||
GLOBAL bool ignore_failed_read_option;
|
||||
@@ -180,10 +191,13 @@ enum old_files
|
||||
OVERWRITE_OLD_FILES, /* --overwrite */
|
||||
UNLINK_FIRST_OLD_FILES, /* --unlink-first */
|
||||
KEEP_OLD_FILES, /* --keep-old-files */
|
||||
SKIP_OLD_FILES, /* --skip-old-files */
|
||||
KEEP_NEWER_FILES /* --keep-newer-files */
|
||||
};
|
||||
GLOBAL enum old_files old_files_option;
|
||||
|
||||
GLOBAL bool keep_directory_symlink_option;
|
||||
|
||||
/* Specified file name for incremental list. */
|
||||
GLOBAL const char *listed_incremental_option;
|
||||
/* Incremental dump level */
|
||||
@@ -203,13 +217,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. */
|
||||
@@ -227,8 +248,13 @@ GLOBAL bool numeric_owner_option;
|
||||
|
||||
GLOBAL bool one_file_system_option;
|
||||
|
||||
/* Create a top-level directory for extracting based on the archive name. */
|
||||
GLOBAL bool one_top_level_option;
|
||||
GLOBAL char *one_top_level_dir;
|
||||
|
||||
/* Specified value to be put into tar file in place of stat () results, or
|
||||
just -1 if such an override should not take place. */
|
||||
just null and -1 if such an override should not take place. */
|
||||
GLOBAL char const *owner_name_option;
|
||||
GLOBAL uid_t owner_option;
|
||||
|
||||
GLOBAL bool recursive_unlink_option;
|
||||
@@ -237,9 +263,6 @@ GLOBAL bool read_full_records_option;
|
||||
|
||||
GLOBAL bool remove_files_option;
|
||||
|
||||
/* Specified rmt command. */
|
||||
GLOBAL const char *rmt_command_option;
|
||||
|
||||
/* Specified remote shell command. */
|
||||
GLOBAL const char *rsh_command_option;
|
||||
|
||||
@@ -251,6 +274,15 @@ GLOBAL int same_owner_option;
|
||||
/* If positive, preserve permissions when extracting. */
|
||||
GLOBAL int same_permissions_option;
|
||||
|
||||
/* If positive, save the SELinux context. */
|
||||
GLOBAL int selinux_context_option;
|
||||
|
||||
/* If positive, save the ACLs. */
|
||||
GLOBAL int acls_option;
|
||||
|
||||
/* If positive, save the user and root xattrs. */
|
||||
GLOBAL int xattrs_option;
|
||||
|
||||
/* When set, strip the given number of file name components from the file name
|
||||
before extracting */
|
||||
GLOBAL size_t strip_name_components;
|
||||
@@ -261,6 +293,15 @@ 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;
|
||||
|
||||
GLOBAL bool starting_file_option;
|
||||
|
||||
/* Specified maximum byte length of each tape volume (multiple of 1024). */
|
||||
@@ -311,11 +352,10 @@ GLOBAL struct timespec last_stat_time; /* when the statistics was last
|
||||
|
||||
GLOBAL struct tar_stat_info current_stat_info;
|
||||
|
||||
/* List of tape drive names, number of such tape drives, allocated number,
|
||||
/* List of tape drive names, number of such tape drives,
|
||||
and current cursor in list. */
|
||||
GLOBAL const char **archive_name_array;
|
||||
GLOBAL size_t archive_names;
|
||||
GLOBAL size_t allocated_archive_names;
|
||||
GLOBAL const char **archive_name_cursor;
|
||||
|
||||
/* Output index file name. */
|
||||
@@ -335,12 +375,12 @@ struct name
|
||||
int matching_flags; /* wildcard flags if name is a pattern */
|
||||
bool cmdline; /* true if this name was given in the
|
||||
command line */
|
||||
|
||||
|
||||
int change_dir; /* Number of the directory to change to.
|
||||
Set with the -C option. */
|
||||
uintmax_t found_count; /* number of times a matching file has
|
||||
been found */
|
||||
|
||||
|
||||
/* The following members are used for incremental dumps only,
|
||||
if this struct name represents a directory;
|
||||
see incremen.c */
|
||||
@@ -355,6 +395,11 @@ struct name
|
||||
GLOBAL dev_t ar_dev;
|
||||
GLOBAL ino_t ar_ino;
|
||||
|
||||
/* Flags for reading, searching, and fstatatting files. */
|
||||
GLOBAL int open_read_flags;
|
||||
GLOBAL int open_searchdir_flags;
|
||||
GLOBAL int fstatat_flags;
|
||||
|
||||
GLOBAL int seek_option;
|
||||
GLOBAL bool seekable_archive;
|
||||
|
||||
@@ -363,6 +408,8 @@ GLOBAL dev_t root_device;
|
||||
/* Unquote filenames */
|
||||
GLOBAL bool unquote_option;
|
||||
|
||||
GLOBAL int savedir_sort_order;
|
||||
|
||||
/* Show file or archive names after transformation.
|
||||
In particular, when creating archive in verbose mode, list member names
|
||||
as stored in the archive */
|
||||
@@ -373,10 +420,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. */
|
||||
|
||||
@@ -408,7 +451,7 @@ size_t available_space_after (union block *pointer);
|
||||
off_t current_block_ordinal (void);
|
||||
void close_archive (void);
|
||||
void closeout_volume_number (void);
|
||||
void compute_duration (void);
|
||||
double compute_duration (void);
|
||||
union block *find_next_block (void);
|
||||
void flush_read (void);
|
||||
void flush_write (void);
|
||||
@@ -425,13 +468,23 @@ void archive_read_error (void);
|
||||
off_t seek_archive (off_t size);
|
||||
void set_start_time (void);
|
||||
|
||||
void mv_begin (struct tar_stat_info *st);
|
||||
#define TF_READ 0
|
||||
#define TF_WRITE 1
|
||||
#define TF_DELETED 2
|
||||
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);
|
||||
|
||||
void mv_begin_read (struct tar_stat_info *st);
|
||||
void mv_end (void);
|
||||
void mv_total_size (off_t size);
|
||||
void mv_size_left (off_t size);
|
||||
|
||||
void buffer_write_global_xheader (void);
|
||||
|
||||
const char *first_decompress_program (int *pstate);
|
||||
const char *next_decompress_program (int *pstate);
|
||||
|
||||
/* Module create.c. */
|
||||
|
||||
enum dump_status
|
||||
@@ -443,13 +496,14 @@ enum dump_status
|
||||
};
|
||||
|
||||
void add_exclusion_tag (const char *name, enum exclusion_tag_type type,
|
||||
bool (*)(const char*));
|
||||
bool cachedir_file_p (const char *name);
|
||||
bool (*predicate) (int));
|
||||
bool cachedir_file_p (int fd);
|
||||
char *get_directory_entries (struct tar_stat_info *st);
|
||||
|
||||
bool file_dumpable_p (struct tar_stat_info *st);
|
||||
void create_archive (void);
|
||||
void pad_archive (off_t size_left);
|
||||
void dump_file (const char *st, bool top_level, dev_t parent_device);
|
||||
void dump_file (struct tar_stat_info *parent, char const *name,
|
||||
char const *fullname);
|
||||
union block *start_header (struct tar_stat_info *st);
|
||||
void finish_header (struct tar_stat_info *st, union block *header,
|
||||
off_t block_ordinal);
|
||||
@@ -459,33 +513,18 @@ union block * write_extended (bool global, struct tar_stat_info *st,
|
||||
union block *start_private_header (const char *name, size_t size, time_t t);
|
||||
void write_eot (void);
|
||||
void check_links (void);
|
||||
int subfile_open (struct tar_stat_info const *dir, char const *file, int flags);
|
||||
void restore_parent_fd (struct tar_stat_info const *st);
|
||||
void exclusion_tag_warning (const char *dirname, const char *tagname,
|
||||
const char *message);
|
||||
enum exclusion_tag_type check_exclusion_tags (const char *dirname,
|
||||
enum exclusion_tag_type check_exclusion_tags (struct tar_stat_info const *st,
|
||||
const char **tag_file_name);
|
||||
|
||||
#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
|
||||
#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
|
||||
#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
|
||||
#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
|
||||
#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
|
||||
#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where))
|
||||
#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
|
||||
#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
|
||||
#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
|
||||
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
|
||||
bool gid_to_chars (gid_t gid, char *buf, size_t size);
|
||||
bool major_to_chars (major_t m, char *buf, size_t size);
|
||||
bool minor_to_chars (minor_t m, char *buf, size_t size);
|
||||
bool mode_to_chars (mode_t m, char *buf, size_t size);
|
||||
#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
|
||||
#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
|
||||
|
||||
bool off_to_chars (off_t off, char *buf, size_t size);
|
||||
bool size_to_chars (size_t v, char *buf, size_t size);
|
||||
bool time_to_chars (time_t t, char *buf, size_t size);
|
||||
bool uid_to_chars (uid_t uid, char *buf, size_t size);
|
||||
bool uintmax_to_chars (uintmax_t v, char *buf, size_t size);
|
||||
void string_to_chars (char const *s, char *buf, size_t size);
|
||||
|
||||
/* Module diffarch.c. */
|
||||
|
||||
@@ -502,23 +541,15 @@ 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);
|
||||
|
||||
/* Module incremen.c. */
|
||||
typedef struct dumpdir *dumpdir_t;
|
||||
typedef struct dumpdir_iter *dumpdir_iter_t;
|
||||
|
||||
dumpdir_t dumpdir_create0 (const char *contents, const char *cmask);
|
||||
dumpdir_t dumpdir_create (const char *contents);
|
||||
void dumpdir_free (dumpdir_t);
|
||||
char *dumpdir_locate (dumpdir_t dump, const char *name);
|
||||
char *dumpdir_next (dumpdir_iter_t itr);
|
||||
char *dumpdir_first (dumpdir_t dump, int all, dumpdir_iter_t *pitr);
|
||||
|
||||
struct directory *scan_directory (char *dir, dev_t device, bool cmdline);
|
||||
void name_fill_directory (struct name *name, dev_t device, bool cmdline);
|
||||
struct directory *scan_directory (struct tar_stat_info *st);
|
||||
const char *directory_contents (struct directory *dir);
|
||||
const char *safe_directory_contents (struct directory *dir);
|
||||
|
||||
@@ -527,14 +558,16 @@ void rebase_directory (struct directory *dir,
|
||||
const char *repl, size_t rlen);
|
||||
|
||||
void append_incremental_renames (struct directory *dir);
|
||||
void show_snapshot_field_ranges (void);
|
||||
void read_directory_file (void);
|
||||
void write_directory_file (void);
|
||||
void purge_directory (char const *directory_name);
|
||||
void list_dumpdir (char *buffer, size_t size);
|
||||
void update_parent_directory (const char *name);
|
||||
void update_parent_directory (struct tar_stat_info *st);
|
||||
|
||||
size_t dumpdir_size (const char *p);
|
||||
bool is_dumpdir (struct tar_stat_info *stat_info);
|
||||
void clear_directory_table (void);
|
||||
|
||||
/* Module list.c. */
|
||||
|
||||
@@ -566,27 +599,13 @@ extern size_t recent_long_link_blocks;
|
||||
|
||||
void decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
enum archive_format *format_pointer, int do_user_group);
|
||||
void transform_stat_info (int typeflag, struct tar_stat_info *stat_info);
|
||||
char const *tartime (struct timespec t, bool full_time);
|
||||
|
||||
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
|
||||
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
|
||||
#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
|
||||
#define MODE_FROM_HEADER(where, hbits) \
|
||||
mode_from_header (where, sizeof (where), hbits)
|
||||
#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
|
||||
#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where))
|
||||
#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
|
||||
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
|
||||
#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
|
||||
|
||||
gid_t gid_from_header (const char *buf, size_t size);
|
||||
major_t major_from_header (const char *buf, size_t size);
|
||||
minor_t minor_from_header (const char *buf, size_t size);
|
||||
mode_t mode_from_header (const char *buf, size_t size, unsigned *hbits);
|
||||
off_t off_from_header (const char *buf, size_t size);
|
||||
size_t size_from_header (const char *buf, size_t size);
|
||||
time_t time_from_header (const char *buf, size_t size);
|
||||
uid_t uid_from_header (const char *buf, size_t size);
|
||||
uintmax_t uintmax_from_header (const char *buf, size_t size);
|
||||
|
||||
void list_archive (void);
|
||||
@@ -604,24 +623,64 @@ void skip_member (void);
|
||||
|
||||
/* Module misc.c. */
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
char const *quote_n_colon (int n, char const *arg);
|
||||
void assign_string (char **dest, const char *src);
|
||||
char *quote_copy_string (const char *str);
|
||||
int unquote_string (char *str);
|
||||
char *zap_slashes (char *name);
|
||||
char *normalize_filename (const char *name);
|
||||
char *normalize_filename (int cdidx, const char *name);
|
||||
void normalize_filename_x (char *name);
|
||||
void replace_prefix (char **pname, const char *samp, size_t slen,
|
||||
const char *repl, size_t rlen);
|
||||
char *tar_savedir (const char *name, int must_exist);
|
||||
|
||||
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);
|
||||
|
||||
const char *tar_dirname (void);
|
||||
|
||||
/* Represent N using a signed integer I such that (uintmax_t) I == N.
|
||||
With a good optimizing compiler, this is equivalent to (intmax_t) i
|
||||
and requires zero machine instructions. */
|
||||
#if ! (UINTMAX_MAX / 2 <= INTMAX_MAX)
|
||||
# error "represent_uintmax returns intmax_t to represent uintmax_t"
|
||||
#endif
|
||||
COMMON_INLINE intmax_t
|
||||
represent_uintmax (uintmax_t n)
|
||||
{
|
||||
if (n <= INTMAX_MAX)
|
||||
return n;
|
||||
else
|
||||
{
|
||||
/* Avoid signed integer overflow on picky platforms. */
|
||||
intmax_t nd = n - INTMAX_MIN;
|
||||
return nd + INTMAX_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
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 };
|
||||
struct timespec decode_timespec (char const *, char **, bool);
|
||||
|
||||
/* Return true if T does not represent an out-of-range or invalid value. */
|
||||
COMMON_INLINE bool
|
||||
valid_timespec (struct timespec t)
|
||||
{
|
||||
return 0 <= t.tv_nsec;
|
||||
}
|
||||
|
||||
bool must_be_dot_or_slash (char const *);
|
||||
|
||||
enum remove_option
|
||||
{
|
||||
@@ -641,8 +700,13 @@ int remove_any_file (const char *file_name, enum remove_option option);
|
||||
bool maybe_backup_file (const char *file_name, bool this_is_the_archive);
|
||||
void undo_last_backup (void);
|
||||
|
||||
int deref_stat (bool deref, char const *name, struct stat *buf);
|
||||
int deref_stat (char const *name, struct stat *buf);
|
||||
|
||||
size_t blocking_read (int fd, void *buf, size_t count);
|
||||
size_t blocking_write (int fd, void const *buf, size_t count);
|
||||
|
||||
extern int chdir_current;
|
||||
extern int chdir_fd;
|
||||
int chdir_arg (char const *dir);
|
||||
void chdir_do (int dir);
|
||||
int chdir_count (void);
|
||||
@@ -656,8 +720,6 @@ void seek_diag_details (char const *name, off_t offset);
|
||||
void stat_diag (char const *name);
|
||||
void file_removed_diag (const char *name, bool top_level,
|
||||
void (*diagfn) (char const *name));
|
||||
void dir_removed_diag (char const *name, bool top_level,
|
||||
void (*diagfn) (char const *name));
|
||||
void write_error_details (char const *name, size_t status, size_t size);
|
||||
void write_fatal (char const *name) __attribute__ ((noreturn));
|
||||
void write_fatal_details (char const *name, ssize_t status, size_t size)
|
||||
@@ -667,11 +729,12 @@ pid_t xfork (void);
|
||||
void xpipe (int fd[2]);
|
||||
|
||||
void *page_aligned_alloc (void **ptr, size_t size);
|
||||
int set_file_atime (int fd, char const *file,
|
||||
struct timespec const timespec[2]);
|
||||
int set_file_atime (int fd, int parentfd, char const *file,
|
||||
struct timespec atime);
|
||||
|
||||
/* Module names.c. */
|
||||
|
||||
extern size_t name_count;
|
||||
extern struct name *gnu_list_name;
|
||||
|
||||
void gid_to_gname (gid_t gid, char **gname);
|
||||
@@ -680,8 +743,8 @@ 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);
|
||||
bool name_more_files (void);
|
||||
void name_add_name (const char *name);
|
||||
void name_term (void);
|
||||
const char *name_next (int change_dirs);
|
||||
void name_gather (void);
|
||||
@@ -690,35 +753,35 @@ struct name *addname (char const *string, int change_dir,
|
||||
void remname (struct name *name);
|
||||
bool name_match (const char *name);
|
||||
void names_notfound (void);
|
||||
void label_notfound (void);
|
||||
void collect_and_sort_names (void);
|
||||
struct name *name_scan (const char *name);
|
||||
struct name const *name_from_list (void);
|
||||
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);
|
||||
|
||||
bool excluded_name (char const *name);
|
||||
|
||||
void add_avoided_name (char const *name);
|
||||
bool is_avoided_name (char const *name);
|
||||
bool is_individual_file (char const *name);
|
||||
|
||||
bool contains_dot_dot (char const *name);
|
||||
|
||||
#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);
|
||||
|
||||
int confirm (const char *message_action, const char *name);
|
||||
void request_stdin (const char *option);
|
||||
|
||||
void tar_stat_init (struct tar_stat_info *st);
|
||||
bool tar_stat_close (struct tar_stat_info *st);
|
||||
void tar_stat_destroy (struct tar_stat_info *st);
|
||||
void usage (int) __attribute__ ((noreturn));
|
||||
int tar_timespec_cmp (struct timespec a, struct timespec b);
|
||||
@@ -726,20 +789,44 @@ 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);
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
void more_options (int argc, char **argv, struct option_locus *loc);
|
||||
|
||||
/* Module update.c. */
|
||||
|
||||
extern char *output_start;
|
||||
|
||||
void update_archive (void);
|
||||
|
||||
/* Module attrs.c. */
|
||||
#include "xattrs.h"
|
||||
|
||||
/* Module xheader.c. */
|
||||
|
||||
void xheader_init (struct xheader *xhdr);
|
||||
void xheader_decode (struct tar_stat_info *stat);
|
||||
void xheader_decode_global (struct xheader *xhdr);
|
||||
void xheader_store (char const *keyword, struct tar_stat_info *st,
|
||||
void const *data);
|
||||
void xheader_read (struct xheader *xhdr, union block *header, size_t size);
|
||||
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_finish (struct xheader *hdr);
|
||||
@@ -753,6 +840,12 @@ bool xheader_string_end (struct xheader *xhdr, char const *keyword);
|
||||
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);
|
||||
|
||||
/* Module system.c */
|
||||
|
||||
@@ -777,7 +870,8 @@ void sys_exec_checkpoint_script (const char *script_name,
|
||||
int checkpoint_number);
|
||||
|
||||
/* Module compare.c */
|
||||
void report_difference (struct tar_stat_info *st, const char *message, ...);
|
||||
void report_difference (struct tar_stat_info *st, const char *message, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
/* Module sparse.c */
|
||||
bool sparse_member_p (struct tar_stat_info *st);
|
||||
@@ -800,17 +894,20 @@ bool utf8_convert (bool to_utf, char const *input, char **output);
|
||||
|
||||
void set_transform_expr (const char *expr);
|
||||
bool transform_name (char **pinput, int type);
|
||||
bool transform_member_name (char **pinput, int type);
|
||||
bool transform_name_fp (char **pinput, int type,
|
||||
char *(*fun)(char *, void *), void *);
|
||||
bool transform_program_p (void);
|
||||
|
||||
/* Module suffix.c */
|
||||
void set_comression_program_by_suffix (const char *name, const char *defprog);
|
||||
void set_compression_program_by_suffix (const char *name, const char *defprog);
|
||||
char *strip_compression_suffix (const char *name);
|
||||
|
||||
/* Module checkpoint.c */
|
||||
void checkpoint_compile_action (const char *str);
|
||||
void checkpoint_finish_compile (void);
|
||||
void checkpoint_run (bool do_write);
|
||||
void checkpoint_finish (void);
|
||||
void checkpoint_flush_actions (void);
|
||||
|
||||
/* Module warning.c */
|
||||
#define WARN_ALONE_ZERO_BLOCK 0x00000001
|
||||
@@ -832,20 +929,28 @@ void checkpoint_run (bool do_write);
|
||||
#define WARN_UNKNOWN_CAST 0x00010000
|
||||
#define WARN_UNKNOWN_KEYWORD 0x00020000
|
||||
#define WARN_XDEV 0x00040000
|
||||
#define WARN_DECOMPRESS_PROGRAM 0x00080000
|
||||
#define WARN_EXISTING_FILE 0x00100000
|
||||
#define WARN_XATTR_WRITE 0x00200000
|
||||
#define WARN_RECORD_SIZE 0x00400000
|
||||
#define WARN_FAILED_READ 0x00800000
|
||||
|
||||
/* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default
|
||||
in verbose mode */
|
||||
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY)
|
||||
#define WARN_ALL (0xffffffff & ~WARN_VERBOSE_WARNINGS)
|
||||
/* 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)
|
||||
|
||||
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)
|
||||
|
||||
@@ -857,3 +962,22 @@ void finish_deferred_unlinks (void);
|
||||
/* Module exit.c */
|
||||
extern void (*fatal_exit_hook) (void);
|
||||
|
||||
/* Module exclist.c */
|
||||
#define EXCL_DEFAULT 0x00
|
||||
#define EXCL_RECURSIVE 0x01
|
||||
#define EXCL_NON_RECURSIVE 0x02
|
||||
|
||||
void excfile_add (const char *name, int flags);
|
||||
void info_attach_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
|
||||
|
||||
157
src/compare.c
157
src/compare.c
@@ -1,23 +1,24 @@
|
||||
/* Diff files from a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2007,
|
||||
2009-2010, 2012-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1987-04-30.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 John Gilmore, on 1987-04-30. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
@@ -50,6 +51,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
|
||||
@@ -59,7 +62,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);
|
||||
@@ -80,7 +83,7 @@ process_noop (size_t size __attribute__ ((unused)),
|
||||
static int
|
||||
process_rawdata (size_t bytes, char *buffer)
|
||||
{
|
||||
size_t status = safe_read (diff_handle, diff_buffer, bytes);
|
||||
size_t status = blocking_read (diff_handle, diff_buffer, bytes);
|
||||
|
||||
if (status != bytes)
|
||||
{
|
||||
@@ -122,7 +125,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
|
||||
size_t data_size;
|
||||
off_t size = st->stat.st_size;
|
||||
|
||||
mv_begin (st);
|
||||
mv_begin_read (st);
|
||||
while (size)
|
||||
{
|
||||
data_block = find_next_block ();
|
||||
@@ -151,7 +154,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
|
||||
static int
|
||||
get_stat_data (char const *file_name, struct stat *stat_data)
|
||||
{
|
||||
int status = deref_stat (dereference_option, file_name, stat_data);
|
||||
int status = deref_stat (file_name, stat_data);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
@@ -217,12 +220,7 @@ diff_file (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
int atime_flag =
|
||||
(atime_preserve_option == system_atime_preserve
|
||||
? O_NOATIME
|
||||
: 0);
|
||||
|
||||
diff_handle = open (file_name, O_RDONLY | O_BINARY | atime_flag);
|
||||
diff_handle = openat (chdir_fd, file_name, open_read_flags);
|
||||
|
||||
if (diff_handle < 0)
|
||||
{
|
||||
@@ -239,12 +237,12 @@ diff_file (void)
|
||||
else
|
||||
read_and_process (¤t_stat_info, process_rawdata);
|
||||
|
||||
if (atime_preserve_option == replace_atime_preserve)
|
||||
if (atime_preserve_option == replace_atime_preserve
|
||||
&& stat_data.st_size != 0)
|
||||
{
|
||||
struct timespec ts[2];
|
||||
ts[0] = get_stat_atime (&stat_data);
|
||||
ts[1] = get_stat_mtime (&stat_data);
|
||||
if (set_file_atime (diff_handle, file_name, ts) != 0)
|
||||
struct timespec atime = get_stat_atime (&stat_data);
|
||||
if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
|
||||
!= 0)
|
||||
utime_error (file_name);
|
||||
}
|
||||
|
||||
@@ -267,17 +265,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 = readlink (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)
|
||||
{
|
||||
@@ -288,8 +289,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
|
||||
|
||||
@@ -331,7 +335,7 @@ static int
|
||||
dumpdir_cmp (const char *a, const char *b)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
|
||||
while (*a)
|
||||
switch (*a)
|
||||
{
|
||||
@@ -345,7 +349,7 @@ dumpdir_cmp (const char *a, const char *b)
|
||||
a += len;
|
||||
b += len;
|
||||
break;
|
||||
|
||||
|
||||
case 'D':
|
||||
if (strcmp(a, b))
|
||||
return 1;
|
||||
@@ -353,7 +357,7 @@ dumpdir_cmp (const char *a, const char *b)
|
||||
a += len;
|
||||
b += len;
|
||||
break;
|
||||
|
||||
|
||||
case 'R':
|
||||
case 'T':
|
||||
case 'X':
|
||||
@@ -363,32 +367,38 @@ dumpdir_cmp (const char *a, const char *b)
|
||||
}
|
||||
|
||||
static void
|
||||
diff_dumpdir (void)
|
||||
diff_dumpdir (struct tar_stat_info *dir)
|
||||
{
|
||||
const char *dumpdir_buffer;
|
||||
dev_t dev = 0;
|
||||
struct stat stat_data;
|
||||
|
||||
if (deref_stat (true, current_stat_info.file_name, &stat_data))
|
||||
if (dir->fd == 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
stat_warn (current_stat_info.file_name);
|
||||
void (*diag) (char const *) = NULL;
|
||||
int fd = subfile_open (dir->parent, dir->orig_file_name, open_read_flags);
|
||||
if (fd < 0)
|
||||
diag = open_diag;
|
||||
else if (fstat (fd, &dir->stat))
|
||||
{
|
||||
diag = stat_diag;
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
stat_error (current_stat_info.file_name);
|
||||
dir->fd = fd;
|
||||
if (diag)
|
||||
{
|
||||
file_removed_diag (dir->orig_file_name, false, diag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
dev = stat_data.st_dev;
|
||||
|
||||
dumpdir_buffer = directory_contents
|
||||
(scan_directory (current_stat_info.file_name, dev, false));
|
||||
dumpdir_buffer = directory_contents (scan_directory (dir));
|
||||
|
||||
if (dumpdir_buffer)
|
||||
{
|
||||
if (dumpdir_cmp (current_stat_info.dumpdir, dumpdir_buffer))
|
||||
report_difference (¤t_stat_info, _("Contents differ"));
|
||||
if (dumpdir_cmp (dir->dumpdir, dumpdir_buffer))
|
||||
report_difference (dir, _("Contents differ"));
|
||||
}
|
||||
else
|
||||
read_and_process (¤t_stat_info, process_noop);
|
||||
read_and_process (dir, process_noop);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -415,14 +425,17 @@ diff_multivol (void)
|
||||
}
|
||||
|
||||
offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
|
||||
if (stat_data.st_size != current_stat_info.stat.st_size + offset)
|
||||
if (offset < 0
|
||||
|| INT_ADD_OVERFLOW (current_stat_info.stat.st_size, offset)
|
||||
|| stat_data.st_size != current_stat_info.stat.st_size + offset)
|
||||
{
|
||||
report_difference (¤t_stat_info, _("Size differs"));
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
|
||||
|
||||
fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
@@ -436,10 +449,9 @@ diff_multivol (void)
|
||||
{
|
||||
seek_error_details (current_stat_info.file_name, offset);
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
read_and_process (¤t_stat_info, process_rawdata);
|
||||
else
|
||||
read_and_process (¤t_stat_info, process_rawdata);
|
||||
|
||||
status = close (fd);
|
||||
if (status != 0)
|
||||
@@ -452,7 +464,6 @@ diff_archive (void)
|
||||
{
|
||||
|
||||
set_next_block_after (current_header);
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
|
||||
|
||||
/* Print the block from current_header and current_stat_info. */
|
||||
|
||||
@@ -466,11 +477,10 @@ diff_archive (void)
|
||||
switch (current_header->header.typeflag)
|
||||
{
|
||||
default:
|
||||
ERROR ((0, 0, _("%s: Unknown file type `%c', diffed as normal file"),
|
||||
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:
|
||||
@@ -503,7 +513,7 @@ diff_archive (void)
|
||||
case GNUTYPE_DUMPDIR:
|
||||
case DIRTYPE:
|
||||
if (is_dumpdir (¤t_stat_info))
|
||||
diff_dumpdir ();
|
||||
diff_dumpdir (¤t_stat_info);
|
||||
diff_dir ();
|
||||
break;
|
||||
|
||||
@@ -518,13 +528,24 @@ diff_archive (void)
|
||||
void
|
||||
verify_volume (void)
|
||||
{
|
||||
int may_fail = 0;
|
||||
if (removed_prefixes_p ())
|
||||
{
|
||||
WARN((0, 0,
|
||||
_("Archive contains file names with leading prefixes removed.")));
|
||||
WARN((0, 0,
|
||||
_("Verification may fail to locate original files.")));
|
||||
may_fail = 1;
|
||||
}
|
||||
if (transform_program_p ())
|
||||
{
|
||||
WARN((0, 0,
|
||||
_("Archive contains transformed file names.")));
|
||||
may_fail = 1;
|
||||
}
|
||||
if (may_fail)
|
||||
WARN((0, 0,
|
||||
_("Verification may fail to locate original files.")));
|
||||
|
||||
clear_directory_table ();
|
||||
|
||||
if (!diff_buffer)
|
||||
diff_init ();
|
||||
@@ -578,8 +599,8 @@ verify_volume (void)
|
||||
flush_read ();
|
||||
while (1)
|
||||
{
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
read_header_auto);
|
||||
|
||||
if (status == HEADER_FAILURE)
|
||||
@@ -609,7 +630,7 @@ verify_volume (void)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
if (status == HEADER_ZERO_BLOCK)
|
||||
break;
|
||||
@@ -617,8 +638,10 @@ verify_volume (void)
|
||||
(0, 0, _("A lone zero block at %s"),
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
|
||||
diff_archive ();
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(tar.h)
|
||||
PROGS="tar"
|
||||
AC_SUBST(PROGS)dnl
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_GCC_TRADITIONAL
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_YACC
|
||||
AC_AIX
|
||||
AC_MINIX
|
||||
AC_ISC_POSIX
|
||||
AC_CONST
|
||||
AC_RETSIGTYPE
|
||||
AC_SIZE_T
|
||||
AC_MAJOR_HEADER
|
||||
AC_DIR_HEADER
|
||||
# The 3-argument open happens to go along with the O_* defines,
|
||||
# which are easier to check for.
|
||||
AC_HEADER_CHECK(fcntl.h, open_header=fcntl.h, open_header=sys/file.h)
|
||||
AC_COMPILE_CHECK(3-argument open,
|
||||
[#include <$open_header>], [int x = O_RDONLY;], , AC_DEFINE(EMUL_OPEN3))
|
||||
AC_REMOTE_TAPE
|
||||
AC_RSH
|
||||
AC_STDC_HEADERS
|
||||
AC_UNISTD_H
|
||||
echo checking for getgrgid declaration
|
||||
AC_HEADER_EGREP(getgrgid, grp.h, AC_DEFINE(HAVE_GETGRGID))
|
||||
echo checking for getpwuid declaration
|
||||
AC_HEADER_EGREP(getpwuid, pwd.h, AC_DEFINE(HAVE_GETPWUID))
|
||||
AC_HAVE_HEADERS(string.h limits.h)
|
||||
echo checking default archive
|
||||
# This might guess wrong, but it's not very important.
|
||||
for dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2
|
||||
do
|
||||
if test -n "`ls /dev/$dev 2>/dev/null`"; then
|
||||
DEF_AR_FILE=/dev/$dev
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$DEF_AR_FILE"; then
|
||||
DEF_AR_FILE=-
|
||||
fi
|
||||
|
||||
AC_SUBST(DEF_AR_FILE)dnl
|
||||
AC_HAVE_FUNCS(strstr valloc mkdir mknod rename ftruncate ftime getcwd)
|
||||
AC_VPRINTF
|
||||
AC_ALLOCA
|
||||
echo checking for BSD
|
||||
( test -f /vmunix || test -f /sdmach || test -f /../../mach ) && AC_DEFINE(BSD42)
|
||||
echo checking for HP-UX
|
||||
test "`(uname -s) 2> /dev/null`" = 'HP-UX' && MALLOC=malloc.o
|
||||
AC_SUBST(MALLOC)
|
||||
AC_XENIX_DIR
|
||||
AC_HAVE_LIBRARY(socket, [LIBS="$LIBS -lsocket"])
|
||||
AC_HAVE_LIBRARY(nsl, [LIBS="$LIBS -lnsl"])
|
||||
AC_OUTPUT(Makefile)
|
||||
682
src/create.c
682
src/create.c
File diff suppressed because it is too large
Load Diff
42
src/delete.c
42
src/delete.c
@@ -1,21 +1,22 @@
|
||||
/* Delete entries from a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001, 2003, 2004,
|
||||
2005, 2006, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992, 1994, 1996-1997, 2000-2001, 2003-2006, 2010,
|
||||
2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 <system-ioctl.h>
|
||||
@@ -186,8 +187,7 @@ delete_archive_members (void)
|
||||
skip_member ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
logical_status = status;
|
||||
break;
|
||||
@@ -198,7 +198,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;
|
||||
@@ -209,14 +209,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;
|
||||
|
||||
@@ -262,7 +260,7 @@ delete_archive_members (void)
|
||||
|
||||
if (current_block == record_end)
|
||||
flush_archive ();
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
|
||||
xheader_decode (¤t_stat_info);
|
||||
@@ -296,7 +294,7 @@ delete_archive_members (void)
|
||||
set_next_block_after (current_header);
|
||||
blocks_to_skip = (current_stat_info.stat.st_size
|
||||
+ BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
|
||||
|
||||
while (record_end - current_block <= blocks_to_skip)
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
|
||||
329
src/exclist.c
Normal file
329
src/exclist.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/* Per-directory exclusion files for tar.
|
||||
|
||||
Copyright 2014, 2016-2017 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 <quotearg.h>
|
||||
#include <fnmatch.h>
|
||||
#include <wordsplit.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef void (*add_fn) (struct exclude *, char const *, int, void *);
|
||||
|
||||
struct vcs_ignore_file
|
||||
{
|
||||
char const *filename;
|
||||
int flags;
|
||||
add_fn addfn;
|
||||
void *(*initfn) (void *);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static struct vcs_ignore_file *get_vcs_ignore_file (const char *name);
|
||||
|
||||
struct excfile
|
||||
{
|
||||
struct excfile *next;
|
||||
int flags;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
static struct excfile *excfile_head, *excfile_tail;
|
||||
|
||||
void
|
||||
excfile_add (const char *name, int flags)
|
||||
{
|
||||
struct excfile *p = xmalloc (sizeof (*p) + strlen (name));
|
||||
p->next = NULL;
|
||||
p->flags = flags;
|
||||
strcpy (p->name, name);
|
||||
if (excfile_tail)
|
||||
excfile_tail->next = p;
|
||||
else
|
||||
excfile_head = p;
|
||||
excfile_tail = p;
|
||||
}
|
||||
|
||||
struct exclist
|
||||
{
|
||||
struct exclist *next, *prev;
|
||||
int flags;
|
||||
struct exclude *excluded;
|
||||
};
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
if (faccessat (dir ? dir->fd : chdir_fd, file->name, F_OK, 0) == 0)
|
||||
{
|
||||
FILE *fp;
|
||||
struct exclude *ex = NULL;
|
||||
int fd = subfile_open (dir, file->name, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
open_error (file->name);
|
||||
continue;
|
||||
}
|
||||
fp = fdopen (fd, "r");
|
||||
if (!fp)
|
||||
{
|
||||
ERROR ((0, errno, _("%s: fdopen failed"), file->name));
|
||||
close (fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ex)
|
||||
ex = new_exclude ();
|
||||
|
||||
vcsfile = get_vcs_ignore_file (file->name);
|
||||
|
||||
if (vcsfile->initfn)
|
||||
vcsfile->data = vcsfile->initfn (vcsfile->data);
|
||||
|
||||
if (add_exclude_fp (vcsfile->addfn, ex, fp,
|
||||
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
|
||||
? file->flags : vcsfile->flags;
|
||||
ent->prev = tail;
|
||||
ent->next = NULL;
|
||||
|
||||
if (tail)
|
||||
tail->next = ent;
|
||||
else
|
||||
head = ent;
|
||||
tail = ent;
|
||||
}
|
||||
}
|
||||
dir->exclude_list = head;
|
||||
}
|
||||
|
||||
void
|
||||
info_free_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
struct exclist *ep = dir->exclude_list;
|
||||
|
||||
while (ep)
|
||||
{
|
||||
struct exclist *next = ep->next;
|
||||
free_exclude (ep->excluded);
|
||||
free (ep);
|
||||
ep = next;
|
||||
}
|
||||
|
||||
dir->exclude_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return nonzero if file NAME is excluded. */
|
||||
bool
|
||||
excluded_name (char const *name, struct tar_stat_info *st)
|
||||
{
|
||||
struct exclist *ep;
|
||||
const char *rname = NULL;
|
||||
char *bname = NULL;
|
||||
bool result;
|
||||
int nr = 0;
|
||||
|
||||
name += FILE_SYSTEM_PREFIX_LEN (name);
|
||||
|
||||
/* Try global exclusion list first */
|
||||
if (excluded_file_name (excluded, name))
|
||||
return true;
|
||||
|
||||
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)
|
||||
{
|
||||
if (ep->flags & nr)
|
||||
continue;
|
||||
if ((result = excluded_file_name (ep->excluded, name)))
|
||||
break;
|
||||
|
||||
if (!rname)
|
||||
{
|
||||
rname = name;
|
||||
/* Skip leading ./ */
|
||||
while (*rname == '.' && ISSLASH (rname[1]))
|
||||
rname += 2;
|
||||
}
|
||||
if ((result = excluded_file_name (ep->excluded, rname)))
|
||||
break;
|
||||
|
||||
if (!bname)
|
||||
bname = base_name (name);
|
||||
if ((result = excluded_file_name (ep->excluded, bname)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (bname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
cvs_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
{
|
||||
struct wordsplit ws;
|
||||
size_t i;
|
||||
|
||||
if (wordsplit (pattern, &ws,
|
||||
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS))
|
||||
return;
|
||||
for (i = 0; i < ws.ws_wordc; i++)
|
||||
add_exclude (ex, ws.ws_wordv[i], options);
|
||||
wordsplit_free (&ws);
|
||||
}
|
||||
|
||||
static void
|
||||
git_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
{
|
||||
while (isspace (*pattern))
|
||||
++pattern;
|
||||
if (*pattern == 0 || *pattern == '#')
|
||||
return;
|
||||
if (*pattern == '\\' && pattern[1] == '#')
|
||||
++pattern;
|
||||
add_exclude (ex, pattern, options);
|
||||
}
|
||||
|
||||
static void
|
||||
bzr_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
{
|
||||
while (isspace (*pattern))
|
||||
++pattern;
|
||||
if (*pattern == 0 || *pattern == '#')
|
||||
return;
|
||||
if (*pattern == '!')
|
||||
{
|
||||
if (*++pattern == '!')
|
||||
++pattern;
|
||||
else
|
||||
options |= EXCLUDE_INCLUDE;
|
||||
}
|
||||
/* FIXME: According to the docs, globbing patterns are rsync-style,
|
||||
and regexps are perl-style. */
|
||||
if (strncmp (pattern, "RE:", 3) == 0)
|
||||
{
|
||||
pattern += 3;
|
||||
options &= ~EXCLUDE_WILDCARDS;
|
||||
options |= EXCLUDE_REGEX;
|
||||
}
|
||||
add_exclude (ex, pattern, options);
|
||||
}
|
||||
|
||||
static void *
|
||||
hg_initfn (void *data)
|
||||
{
|
||||
static int 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 == '#')
|
||||
return;
|
||||
if (strncmp (pattern, "syntax:", 7) == 0)
|
||||
{
|
||||
for (pattern += 7; isspace (*pattern); ++pattern)
|
||||
;
|
||||
if (strcmp (pattern, "regexp") == 0)
|
||||
/* FIXME: Regexps must be perl-style */
|
||||
*hgopt = EXCLUDE_REGEX;
|
||||
else if (strcmp (pattern, "glob") == 0)
|
||||
*hgopt = EXCLUDE_WILDCARDS;
|
||||
/* Ignore unknown syntax */
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen(pattern);
|
||||
if (pattern[len-1] == '/')
|
||||
{
|
||||
char *p;
|
||||
|
||||
--len;
|
||||
p = xmalloc (len+1);
|
||||
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);
|
||||
}
|
||||
|
||||
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 },
|
||||
{ NULL, 0, git_addfn, NULL, NULL }
|
||||
};
|
||||
|
||||
static struct vcs_ignore_file *
|
||||
get_vcs_ignore_file (const char *name)
|
||||
{
|
||||
struct vcs_ignore_file *p;
|
||||
|
||||
for (p = vcs_ignore_files; p->filename; p++)
|
||||
if (strcmp (p->filename, name) == 0)
|
||||
break;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
exclude_vcs_ignores (void)
|
||||
{
|
||||
struct vcs_ignore_file *p;
|
||||
|
||||
for (p = vcs_ignore_files; p->filename; p++)
|
||||
excfile_add (p->filename, EXCL_DEFAULT);
|
||||
}
|
||||
28
src/exit.c
28
src/exit.c
@@ -1,19 +1,21 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
/* Exit from GNU tar.
|
||||
|
||||
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.
|
||||
Copyright 2009, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
This file is part of GNU tar.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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"
|
||||
|
||||
1301
src/extract.c
1301
src/extract.c
File diff suppressed because it is too large
Load Diff
710
src/incremen.c
710
src/incremen.c
File diff suppressed because it is too large
Load Diff
447
src/list.c
447
src/list.c
@@ -1,23 +1,24 @@
|
||||
/* List a tar archive, with support routines for reading a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2017 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-08-26.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 John Gilmore, on 1985-08-26. */
|
||||
|
||||
#include <system.h>
|
||||
#include <inttostr.h>
|
||||
@@ -25,18 +26,30 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
union block *current_header; /* points to current archive header */
|
||||
enum archive_format current_format; /* recognized format */
|
||||
union block *recent_long_name; /* recent long name header and contents */
|
||||
union block *recent_long_link; /* likewise, for long link */
|
||||
size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
|
||||
size_t recent_long_link_blocks; /* likewise, for long link */
|
||||
union block *recent_global_header; /* Recent global header block */
|
||||
static union block *recent_global_header; /* Recent global header block */
|
||||
|
||||
static uintmax_t from_header (const char *, size_t, const char *,
|
||||
uintmax_t, uintmax_t, bool, bool);
|
||||
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
|
||||
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
|
||||
#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
|
||||
#define MODE_FROM_HEADER(where, hbits) \
|
||||
mode_from_header (where, sizeof (where), hbits)
|
||||
#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
|
||||
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
|
||||
|
||||
static gid_t gid_from_header (const char *buf, size_t size);
|
||||
static major_t major_from_header (const char *buf, size_t size);
|
||||
static minor_t minor_from_header (const char *buf, size_t size);
|
||||
static mode_t mode_from_header (const char *buf, size_t size, bool *hbits);
|
||||
static time_t time_from_header (const char *buf, size_t size);
|
||||
static uid_t uid_from_header (const char *buf, size_t size);
|
||||
static intmax_t from_header (const char *, size_t, const char *,
|
||||
intmax_t, uintmax_t, bool, bool);
|
||||
|
||||
/* Base 64 digits; see Internet RFC 2045 Table 1. */
|
||||
static char const base_64_digits[64] =
|
||||
@@ -61,6 +74,95 @@ base64_init (void)
|
||||
base64_map[(int) base_64_digits[i]] = i;
|
||||
}
|
||||
|
||||
static char *
|
||||
decode_xform (char *file_name, void *data)
|
||||
{
|
||||
int type = *(int*)data;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case XFORM_SYMLINK:
|
||||
/* FIXME: It is not quite clear how and to which extent are the symbolic
|
||||
links subject to filename transformation. In the absence of another
|
||||
solution, symbolic links are exempt from component stripping and
|
||||
name suffix normalization, but subject to filename transformation
|
||||
proper. */
|
||||
return file_name;
|
||||
|
||||
case XFORM_LINK:
|
||||
file_name = safer_name_suffix (file_name, true, absolute_names_option);
|
||||
break;
|
||||
|
||||
case XFORM_REGFILE:
|
||||
file_name = safer_name_suffix (file_name, false, absolute_names_option);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strip_name_components)
|
||||
{
|
||||
size_t prefix_len = stripped_prefix_len (file_name,
|
||||
strip_name_components);
|
||||
if (prefix_len == (size_t) -1)
|
||||
prefix_len = strlen (file_name);
|
||||
file_name += prefix_len;
|
||||
}
|
||||
return file_name;
|
||||
}
|
||||
|
||||
static bool
|
||||
transform_member_name (char **pinput, int type)
|
||||
{
|
||||
return transform_name_fp (pinput, type, decode_xform, &type);
|
||||
}
|
||||
|
||||
static void
|
||||
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)
|
||||
{
|
||||
int pos = strlen (one_top_level_dir);
|
||||
if (strncmp (p, one_top_level_dir, pos) == 0)
|
||||
{
|
||||
if (ISSLASH (p[pos]) || p[pos] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
*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);
|
||||
}
|
||||
|
||||
void
|
||||
transform_stat_info (int typeflag, struct tar_stat_info *stat_info)
|
||||
{
|
||||
if (typeflag == GNUTYPE_VOLHDR)
|
||||
/* Name transformations don't apply to volume headers. */
|
||||
return;
|
||||
|
||||
transform_member_name (&stat_info->file_name, XFORM_REGFILE);
|
||||
switch (typeflag)
|
||||
{
|
||||
case SYMTYPE:
|
||||
transform_member_name (&stat_info->link_name, XFORM_SYMLINK);
|
||||
break;
|
||||
|
||||
case LNKTYPE:
|
||||
transform_member_name (&stat_info->link_name, XFORM_LINK);
|
||||
}
|
||||
|
||||
if (one_top_level_option)
|
||||
enforce_one_top_level (¤t_stat_info.file_name);
|
||||
}
|
||||
|
||||
/* Main loop for reading an archive. */
|
||||
void
|
||||
read_and (void (*do_something) (void))
|
||||
@@ -78,7 +180,7 @@ read_and (void (*do_something) (void))
|
||||
prev_status = status;
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
switch (status)
|
||||
{
|
||||
@@ -90,9 +192,10 @@ read_and (void (*do_something) (void))
|
||||
|
||||
/* Valid header. We should decode next field (mode) first.
|
||||
Ensure incoming names are null terminated. */
|
||||
|
||||
decode_header (current_header, ¤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
|
||||
@@ -102,7 +205,8 @@ read_and (void (*do_something) (void))
|
||||
mtime.tv_nsec = 0,
|
||||
current_stat_info.mtime = mtime,
|
||||
OLDER_TAR_STAT_TIME (current_stat_info, m)))
|
||||
|| excluded_name (current_stat_info.file_name))
|
||||
|| excluded_name (current_stat_info.file_name,
|
||||
current_stat_info.parent))
|
||||
{
|
||||
switch (current_header->header.typeflag)
|
||||
{
|
||||
@@ -114,15 +218,15 @@ 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:
|
||||
decode_header (current_header,
|
||||
¤t_stat_info, ¤t_format, 0);
|
||||
skip_member ();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
transform_stat_info (current_header->header.typeflag,
|
||||
¤t_stat_info);
|
||||
(*do_something) ();
|
||||
continue;
|
||||
|
||||
@@ -140,7 +244,7 @@ read_and (void (*do_something) (void))
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
if (status == HEADER_ZERO_BLOCK)
|
||||
break;
|
||||
@@ -169,8 +273,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)
|
||||
@@ -210,8 +313,6 @@ list_archive (void)
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
|
||||
/* Print the header block. */
|
||||
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, 0);
|
||||
if (verbose_option)
|
||||
print_header (¤t_stat_info, current_header, block_ordinal);
|
||||
|
||||
@@ -245,7 +346,7 @@ tar_checksum (union block *header, bool silent)
|
||||
int unsigned_sum = 0; /* the POSIX one :-) */
|
||||
int signed_sum = 0; /* the Sun one :-( */
|
||||
int recorded_sum;
|
||||
uintmax_t parsed_sum;
|
||||
int parsed_sum;
|
||||
char *p;
|
||||
|
||||
p = header->buffer;
|
||||
@@ -270,9 +371,8 @@ tar_checksum (union block *header, bool silent)
|
||||
|
||||
parsed_sum = from_header (header->header.chksum,
|
||||
sizeof header->header.chksum, 0,
|
||||
(uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (int), true, silent);
|
||||
if (parsed_sum == (uintmax_t) -1)
|
||||
0, INT_MAX, true, silent);
|
||||
if (parsed_sum < 0)
|
||||
return HEADER_FAILURE;
|
||||
|
||||
recorded_sum = parsed_sum;
|
||||
@@ -335,7 +435,11 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
if (header->header.typeflag == LNKTYPE)
|
||||
info->stat.st_size = 0; /* links 0 size on tape */
|
||||
else
|
||||
info->stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
{
|
||||
info->stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
if (info->stat.st_size < 0)
|
||||
return HEADER_FAILURE;
|
||||
}
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK
|
||||
@@ -361,15 +465,13 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME)
|
||||
{
|
||||
if (next_long_name)
|
||||
free (next_long_name);
|
||||
free (next_long_name);
|
||||
next_long_name = header_copy;
|
||||
next_long_name_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next_long_link)
|
||||
free (next_long_link);
|
||||
free (next_long_link);
|
||||
next_long_link = header_copy;
|
||||
next_long_link_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
@@ -428,8 +530,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
struct posix_header const *h = &header->header;
|
||||
char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
|
||||
|
||||
if (recent_long_name)
|
||||
free (recent_long_name);
|
||||
free (recent_long_name);
|
||||
|
||||
if (next_long_name)
|
||||
{
|
||||
@@ -460,8 +561,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
assign_string (&info->file_name, name);
|
||||
info->had_trailing_slash = strip_trailing_slashes (info->file_name);
|
||||
|
||||
if (recent_long_link)
|
||||
free (recent_long_link);
|
||||
free (recent_long_link);
|
||||
|
||||
if (next_long_link)
|
||||
{
|
||||
@@ -484,47 +584,6 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
decode_xform (char *file_name, void *data)
|
||||
{
|
||||
int type = *(int*)data;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case XFORM_SYMLINK:
|
||||
/* FIXME: It is not quite clear how and to which extent are the symbolic
|
||||
links subject to filename transformation. In the absence of another
|
||||
solution, symbolic links are exempt from component stripping and
|
||||
name suffix normalization, but subject to filename transformation
|
||||
proper. */
|
||||
return file_name;
|
||||
|
||||
case XFORM_LINK:
|
||||
file_name = safer_name_suffix (file_name, true, absolute_names_option);
|
||||
break;
|
||||
|
||||
case XFORM_REGFILE:
|
||||
file_name = safer_name_suffix (file_name, false, absolute_names_option);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strip_name_components)
|
||||
{
|
||||
size_t prefix_len = stripped_prefix_len (file_name,
|
||||
strip_name_components);
|
||||
if (prefix_len == (size_t) -1)
|
||||
prefix_len = strlen (file_name);
|
||||
file_name += prefix_len;
|
||||
}
|
||||
return file_name;
|
||||
}
|
||||
|
||||
bool
|
||||
transform_member_name (char **pinput, int type)
|
||||
{
|
||||
return transform_name_fp (pinput, type, decode_xform, &type);
|
||||
}
|
||||
|
||||
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
|
||||
|
||||
/* Decode things from a file HEADER block into STAT_INFO, also setting
|
||||
@@ -545,9 +604,9 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
enum archive_format *format_pointer, int do_user_group)
|
||||
{
|
||||
enum archive_format format;
|
||||
unsigned hbits; /* high bits of the file mode. */
|
||||
bool hbits;
|
||||
mode_t mode = MODE_FROM_HEADER (header->header.mode, &hbits);
|
||||
|
||||
|
||||
if (strcmp (header->header.magic, TMAGIC) == 0)
|
||||
{
|
||||
if (header->star_header.prefix[130] == 0
|
||||
@@ -561,7 +620,9 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
else
|
||||
format = USTAR_FORMAT;
|
||||
}
|
||||
else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
|
||||
else if (strcmp (header->buffer + offsetof (struct posix_header, magic),
|
||||
OLDGNU_MAGIC)
|
||||
== 0)
|
||||
format = hbits ? OLDGNU_FORMAT : GNU_FORMAT;
|
||||
else
|
||||
format = V7_FORMAT;
|
||||
@@ -575,6 +636,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
assign_string (&stat_info->gname,
|
||||
header->header.gname[0] ? header->header.gname : NULL);
|
||||
|
||||
xheader_xattr_init (stat_info);
|
||||
|
||||
if (format == OLDGNU_FORMAT && incremental_option)
|
||||
{
|
||||
stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
|
||||
@@ -627,7 +690,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))
|
||||
@@ -644,34 +706,34 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
|| stat_info->dumpdir)
|
||||
stat_info->is_dumpdir = true;
|
||||
}
|
||||
|
||||
transform_member_name (&stat_info->file_name, XFORM_REGFILE);
|
||||
switch (header->header.typeflag)
|
||||
{
|
||||
case SYMTYPE:
|
||||
transform_member_name (&stat_info->link_name, XFORM_SYMLINK);
|
||||
break;
|
||||
|
||||
case LNKTYPE:
|
||||
transform_member_name (&stat_info->link_name, XFORM_LINK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert buffer at WHERE0 of size DIGS from external format to
|
||||
uintmax_t. DIGS must be positive. If TYPE is nonnull, the data
|
||||
are of type TYPE. The buffer must represent a value in the range
|
||||
-MINUS_MINVAL through MAXVAL. If OCTAL_ONLY, allow only octal
|
||||
intmax_t. DIGS must be positive. If TYPE is nonnull, the data are
|
||||
of type TYPE. The buffer must represent a value in the range
|
||||
MINVAL through MAXVAL; if the mathematically correct result V would
|
||||
be greater than INTMAX_MAX, return a negative integer V such that
|
||||
(uintmax_t) V yields the correct result. If OCTAL_ONLY, allow only octal
|
||||
numbers instead of the other GNU extensions. Return -1 on error,
|
||||
diagnosing the error if TYPE is nonnull and if !SILENT. */
|
||||
static uintmax_t
|
||||
#if ! (INTMAX_MAX <= UINTMAX_MAX && - (INTMAX_MIN + 1) <= UINTMAX_MAX)
|
||||
# error "from_header internally represents intmax_t as uintmax_t + sign"
|
||||
#endif
|
||||
#if ! (UINTMAX_MAX / 2 <= INTMAX_MAX)
|
||||
# error "from_header returns intmax_t to represent uintmax_t"
|
||||
#endif
|
||||
static intmax_t
|
||||
from_header (char const *where0, size_t digs, char const *type,
|
||||
uintmax_t minus_minval, uintmax_t maxval,
|
||||
intmax_t minval, uintmax_t maxval,
|
||||
bool octal_only, bool silent)
|
||||
{
|
||||
uintmax_t value;
|
||||
uintmax_t uminval = minval;
|
||||
uintmax_t minus_minval = - uminval;
|
||||
char const *where = where0;
|
||||
char const *lim = where + digs;
|
||||
int negative = 0;
|
||||
bool negative = false;
|
||||
|
||||
/* Accommodate buggy tar of unknown vintage, which outputs leading
|
||||
NUL if the previous field overflows. */
|
||||
@@ -690,7 +752,7 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
type));
|
||||
return -1;
|
||||
}
|
||||
if (!ISSPACE ((unsigned char) *where))
|
||||
if (!isspace ((unsigned char) *where))
|
||||
break;
|
||||
where++;
|
||||
}
|
||||
@@ -699,14 +761,14 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
if (ISODIGIT (*where))
|
||||
{
|
||||
char const *where1 = where;
|
||||
uintmax_t overflow = 0;
|
||||
bool overflow = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
value += *where++ - '0';
|
||||
if (where == lim || ! ISODIGIT (*where))
|
||||
break;
|
||||
overflow |= value ^ (value << LG_8 >> LG_8);
|
||||
overflow |= value != (value << LG_8 >> LG_8);
|
||||
value <<= LG_8;
|
||||
}
|
||||
|
||||
@@ -730,7 +792,7 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
if (where == lim || ! ISODIGIT (*where))
|
||||
break;
|
||||
digit = *where - '0';
|
||||
overflow |= value ^ (value << LG_8 >> LG_8);
|
||||
overflow |= value != (value << LG_8 >> LG_8);
|
||||
value <<= LG_8;
|
||||
}
|
||||
value++;
|
||||
@@ -743,7 +805,7 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
/* TRANSLATORS: Second %s is a type name (gid_t,uid_t,etc.) */
|
||||
_("Archive octal value %.*s is out of %s range; assuming two's complement"),
|
||||
(int) (where - where1), where1, type));
|
||||
negative = 1;
|
||||
negative = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,12 +885,12 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
negative = signbit;
|
||||
negative = signbit != 0;
|
||||
if (negative)
|
||||
value = -value;
|
||||
}
|
||||
|
||||
if (where != lim && *where && !ISSPACE ((unsigned char) *where))
|
||||
if (where != lim && *where && !isspace ((unsigned char) *where))
|
||||
{
|
||||
if (type)
|
||||
{
|
||||
@@ -843,7 +905,7 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
|
||||
while (where0 != lim && ! lim[-1])
|
||||
lim--;
|
||||
quotearg_buffer (buf, sizeof buf, where0, lim - where, o);
|
||||
quotearg_buffer (buf, sizeof buf, where0, lim - where0, o);
|
||||
if (!silent)
|
||||
ERROR ((0, 0,
|
||||
/* TRANSLATORS: Second %s is a type name (gid_t,uid_t,etc.) */
|
||||
@@ -855,7 +917,7 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
}
|
||||
|
||||
if (value <= (negative ? minus_minval : maxval))
|
||||
return negative ? -value : value;
|
||||
return represent_uintmax (negative ? -value : value);
|
||||
|
||||
if (type && !silent)
|
||||
{
|
||||
@@ -877,39 +939,38 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
gid_t
|
||||
static gid_t
|
||||
gid_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "gid_t",
|
||||
- (uintmax_t) TYPE_MINIMUM (gid_t),
|
||||
(uintmax_t) TYPE_MAXIMUM (gid_t),
|
||||
TYPE_MINIMUM (gid_t), TYPE_MAXIMUM (gid_t),
|
||||
false, false);
|
||||
}
|
||||
|
||||
major_t
|
||||
static major_t
|
||||
major_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "major_t",
|
||||
- (uintmax_t) TYPE_MINIMUM (major_t),
|
||||
(uintmax_t) TYPE_MAXIMUM (major_t), false, false);
|
||||
TYPE_MINIMUM (major_t), TYPE_MAXIMUM (major_t),
|
||||
false, false);
|
||||
}
|
||||
|
||||
minor_t
|
||||
static minor_t
|
||||
minor_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "minor_t",
|
||||
- (uintmax_t) TYPE_MINIMUM (minor_t),
|
||||
(uintmax_t) TYPE_MAXIMUM (minor_t), false, false);
|
||||
TYPE_MINIMUM (minor_t), TYPE_MAXIMUM (minor_t),
|
||||
false, false);
|
||||
}
|
||||
|
||||
/* Convert P to the file mode, as understood by tar.
|
||||
Store unrecognized mode bits (from 10th up) in HBITS. */
|
||||
mode_t
|
||||
mode_from_header (const char *p, size_t s, unsigned *hbits)
|
||||
Set *HBITS if there are any unrecognized bits. */
|
||||
static mode_t
|
||||
mode_from_header (const char *p, size_t s, bool *hbits)
|
||||
{
|
||||
unsigned u = from_header (p, s, "mode_t",
|
||||
- (uintmax_t) TYPE_MINIMUM (mode_t),
|
||||
TYPE_MAXIMUM (uintmax_t), false, false);
|
||||
intmax_t u = from_header (p, s, "mode_t",
|
||||
INTMAX_MIN, UINTMAX_MAX,
|
||||
false, false);
|
||||
mode_t mode = ((u & TSUID ? S_ISUID : 0)
|
||||
| (u & TSGID ? S_ISGID : 0)
|
||||
| (u & TSVTX ? S_ISVTX : 0)
|
||||
@@ -922,7 +983,7 @@ mode_from_header (const char *p, size_t s, unsigned *hbits)
|
||||
| (u & TOREAD ? S_IROTH : 0)
|
||||
| (u & TOWRITE ? S_IWOTH : 0)
|
||||
| (u & TOEXEC ? S_IXOTH : 0));
|
||||
*hbits = mode ^ u;
|
||||
*hbits = (u & ~07777) != 0;
|
||||
return mode;
|
||||
}
|
||||
|
||||
@@ -931,38 +992,31 @@ off_from_header (const char *p, size_t s)
|
||||
{
|
||||
/* Negative offsets are not allowed in tar files, so invoke
|
||||
from_header with minimum value 0, not TYPE_MINIMUM (off_t). */
|
||||
return from_header (p, s, "off_t", (uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (off_t), false, false);
|
||||
return from_header (p, s, "off_t",
|
||||
0, TYPE_MAXIMUM (off_t),
|
||||
false, false);
|
||||
}
|
||||
|
||||
size_t
|
||||
size_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "size_t", (uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (size_t), false, false);
|
||||
}
|
||||
|
||||
time_t
|
||||
static time_t
|
||||
time_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "time_t",
|
||||
- (uintmax_t) TYPE_MINIMUM (time_t),
|
||||
(uintmax_t) TYPE_MAXIMUM (time_t), false, false);
|
||||
TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t),
|
||||
false, false);
|
||||
}
|
||||
|
||||
uid_t
|
||||
static uid_t
|
||||
uid_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "uid_t",
|
||||
- (uintmax_t) TYPE_MINIMUM (uid_t),
|
||||
(uintmax_t) TYPE_MAXIMUM (uid_t), false, false);
|
||||
TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t),
|
||||
false, false);
|
||||
}
|
||||
|
||||
uintmax_t
|
||||
uintmax_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "uintmax_t", (uintmax_t) 0,
|
||||
TYPE_MAXIMUM (uintmax_t), false, false);
|
||||
return from_header (p, s, "uintmax_t", 0, UINTMAX_MAX, false, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1052,13 +1106,14 @@ static void
|
||||
simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
off_t block_ordinal)
|
||||
{
|
||||
char modes[11];
|
||||
char modes[12];
|
||||
char const *time_stamp;
|
||||
int time_stamp_len;
|
||||
char *temp_name;
|
||||
|
||||
/* These hold formatted ints. */
|
||||
char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
|
||||
char uform[max (INT_BUFSIZE_BOUND (intmax_t), UINTMAX_STRSIZE_BOUND)];
|
||||
char gform[sizeof uform];
|
||||
char *user, *group;
|
||||
char size[2 * UINTMAX_STRSIZE_BOUND];
|
||||
/* holds formatted size or major,minor */
|
||||
@@ -1085,7 +1140,10 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
if (verbose_option <= 1)
|
||||
{
|
||||
/* Just the fax, mam. */
|
||||
fprintf (stdlis, "%s\n", quotearg (temp_name));
|
||||
fputs (quotearg (temp_name), stdlis);
|
||||
if (show_transformed_names_option && st->had_trailing_slash)
|
||||
fputc ('/', stdlis);
|
||||
fputc ('\n', stdlis);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1112,9 +1170,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
case GNUTYPE_SPARSE:
|
||||
case REGTYPE:
|
||||
case AREGTYPE:
|
||||
modes[0] = '-';
|
||||
if (temp_name[strlen (temp_name) - 1] == '/')
|
||||
modes[0] = 'd';
|
||||
modes[0] = st->had_trailing_slash ? 'd' : '-';
|
||||
break;
|
||||
case LNKTYPE:
|
||||
modes[0] = 'h';
|
||||
@@ -1144,9 +1200,12 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
|
||||
pax_decode_mode (st->stat.st_mode, modes + 1);
|
||||
|
||||
/* extended attributes: GNU `ls -l'-like preview */
|
||||
xattrs_print_char (st, modes + 10);
|
||||
|
||||
/* Time stamp. */
|
||||
|
||||
time_stamp = tartime (st->mtime, false);
|
||||
time_stamp = tartime (st->mtime, full_time_option);
|
||||
time_stamp_len = strlen (time_stamp);
|
||||
if (datewidth < time_stamp_len)
|
||||
datewidth = time_stamp_len;
|
||||
@@ -1159,24 +1218,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,
|
||||
(uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (uintmax_t),
|
||||
false, false);
|
||||
if (u != -1)
|
||||
user = STRINGIFY_BIGINT (u, uform);
|
||||
else
|
||||
{
|
||||
sprintf (uform, "%ld",
|
||||
(long) UID_FROM_HEADER (blk->header.uid));
|
||||
user = uform;
|
||||
}
|
||||
}
|
||||
user = STRINGIFY_BIGINT (st->stat.st_uid, uform);
|
||||
|
||||
if (st->gname
|
||||
&& st->gname[0]
|
||||
@@ -1184,24 +1226,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,
|
||||
(uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (uintmax_t),
|
||||
false, false);
|
||||
if (g != -1)
|
||||
group = STRINGIFY_BIGINT (g, gform);
|
||||
else
|
||||
{
|
||||
sprintf (gform, "%ld",
|
||||
(long) GID_FROM_HEADER (blk->header.gid));
|
||||
group = gform;
|
||||
}
|
||||
}
|
||||
group = STRINGIFY_BIGINT (st->stat.st_gid, gform);
|
||||
|
||||
/* Format the file size or major/minor device numbers. */
|
||||
|
||||
@@ -1234,6 +1259,8 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
datewidth, time_stamp);
|
||||
|
||||
fprintf (stdlis, " %s", quotearg (temp_name));
|
||||
if (show_transformed_names_option && st->had_trailing_slash)
|
||||
fputc ('/', stdlis);
|
||||
|
||||
switch (blk->header.typeflag)
|
||||
{
|
||||
@@ -1289,11 +1316,12 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
}
|
||||
}
|
||||
fflush (stdlis);
|
||||
xattrs_print (st);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_volume_label ()
|
||||
static void
|
||||
print_volume_label (void)
|
||||
{
|
||||
struct tar_stat_info vstat;
|
||||
union block vblk;
|
||||
@@ -1345,8 +1373,8 @@ print_for_mkdir (char *dirname, int length, mode_t mode)
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf));
|
||||
}
|
||||
|
||||
fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + 1 + datewidth,
|
||||
_("Creating directory:"), length, quotearg (dirname));
|
||||
fprintf (stdlis, "%s %*s %s\n", modes, ugswidth + 1 + datewidth,
|
||||
_("Creating directory:"), quotearg (dirname));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1356,7 +1384,7 @@ skip_file (off_t size)
|
||||
{
|
||||
union block *x;
|
||||
|
||||
/* FIXME: Make sure mv_begin is always called before it */
|
||||
/* FIXME: Make sure mv_begin_read is always called before it */
|
||||
|
||||
if (seekable_archive)
|
||||
{
|
||||
@@ -1391,7 +1419,7 @@ skip_member (void)
|
||||
char save_typeflag = current_header->header.typeflag;
|
||||
set_next_block_after (current_header);
|
||||
|
||||
mv_begin (¤t_stat_info);
|
||||
mv_begin_read (¤t_stat_info);
|
||||
|
||||
if (current_stat_info.is_sparse)
|
||||
sparse_skip_file (¤t_stat_info);
|
||||
@@ -1403,7 +1431,7 @@ skip_member (void)
|
||||
}
|
||||
|
||||
void
|
||||
test_archive_label ()
|
||||
test_archive_label (void)
|
||||
{
|
||||
base64_init ();
|
||||
name_gather ();
|
||||
@@ -1412,22 +1440,23 @@ test_archive_label ()
|
||||
if (read_header (¤t_header, ¤t_stat_info, read_header_auto)
|
||||
== HEADER_SUCCESS)
|
||||
{
|
||||
char *s = NULL;
|
||||
|
||||
decode_header (current_header,
|
||||
¤t_stat_info, ¤t_format, 0);
|
||||
if (current_header->header.typeflag == GNUTYPE_VOLHDR)
|
||||
assign_string (&volume_label, current_header->header.name);
|
||||
|
||||
if (volume_label
|
||||
&& (name_match (volume_label)
|
||||
|| (multi_volume_option
|
||||
&& (s = drop_volume_label_suffix (volume_label))
|
||||
&& name_match (s))))
|
||||
if (verbose_option)
|
||||
print_volume_label ();
|
||||
free (s);
|
||||
if (volume_label)
|
||||
{
|
||||
if (verbose_option)
|
||||
print_volume_label ();
|
||||
if (!name_match (volume_label) && multi_volume_option)
|
||||
{
|
||||
char *s = drop_volume_label_suffix (volume_label);
|
||||
name_match (s);
|
||||
free (s);
|
||||
}
|
||||
}
|
||||
}
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
label_notfound ();
|
||||
}
|
||||
|
||||
283
src/map.c
Normal file
283
src/map.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/* Owner/group mapping for tar
|
||||
|
||||
Copyright 2015-2017 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;
|
||||
}
|
||||
662
src/misc.c
662
src/misc.c
@@ -1,7 +1,7 @@
|
||||
/* Miscellaneous functions, not really specific to GNU tar.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992, 1994-1997, 1999-2001, 2003-2007, 2009-2010,
|
||||
2012-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -14,26 +14,30 @@
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define COMMON_INLINE _GL_EXTERN_INLINE
|
||||
#include <system.h>
|
||||
#include <rmt.h>
|
||||
#include "common.h"
|
||||
#include <quotearg.h>
|
||||
#include <save-cwd.h>
|
||||
#include <xgetcwd.h>
|
||||
#include <unlinkdir.h>
|
||||
#include <utimens.h>
|
||||
#include <canonicalize.h>
|
||||
|
||||
#if HAVE_STROPTS_H
|
||||
# include <stropts.h>
|
||||
#endif
|
||||
#if HAVE_SYS_FILIO_H
|
||||
# include <sys/filio.h>
|
||||
#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
|
||||
# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
|
||||
#endif
|
||||
|
||||
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. */
|
||||
|
||||
@@ -42,11 +46,13 @@
|
||||
void
|
||||
assign_string (char **string, const char *value)
|
||||
{
|
||||
if (*string)
|
||||
free (*string);
|
||||
free (*string);
|
||||
*string = value ? xstrdup (value) : 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This function is currently unused; perhaps it should be removed? */
|
||||
|
||||
/* Allocate a copy of the string quoted as in C, and returns that. If
|
||||
the string does not have to be quoted, it returns a null pointer.
|
||||
The allocated copy should normally be freed with free() after the
|
||||
@@ -59,7 +65,7 @@ assign_string (char **string, const char *value)
|
||||
when reading directory files. This means that we can't use
|
||||
quotearg, as quotearg is locale-dependent and is meant for human
|
||||
consumption. */
|
||||
char *
|
||||
static char *
|
||||
quote_copy_string (const char *string)
|
||||
{
|
||||
const char *source = string;
|
||||
@@ -100,6 +106,7 @@ quote_copy_string (const char *string)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Takes a quoted C string (like those produced by quote_copy_string)
|
||||
and turns it back into the un-quoted original. This is done in
|
||||
@@ -107,7 +114,7 @@ quote_copy_string (const char *string)
|
||||
completes the unquoting anyway.
|
||||
|
||||
This is used for reading the saved directory file in incremental
|
||||
dumps. It is used for decoding old `N' records (demangling names).
|
||||
dumps. It is used for decoding old 'N' records (demangling names).
|
||||
But also, it is used for decoding file arguments, would they come
|
||||
from the shell or a -T file, and for decoding the --exclude
|
||||
argument. */
|
||||
@@ -230,10 +237,85 @@ zap_slashes (char *name)
|
||||
return name;
|
||||
}
|
||||
|
||||
char *
|
||||
normalize_filename (const char *name)
|
||||
/* Normalize FILE_NAME by removing redundant slashes and "."
|
||||
components, including redundant trailing slashes.
|
||||
Leave ".." alone, as it may be significant in the presence
|
||||
of symlinks and on platforms where "/.." != "/".
|
||||
|
||||
Destructive version: modifies its argument. */
|
||||
void
|
||||
normalize_filename_x (char *file_name)
|
||||
{
|
||||
return zap_slashes (canonicalize_filename_mode (name, CAN_MISSING));
|
||||
char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
char *p;
|
||||
char const *q;
|
||||
char c;
|
||||
|
||||
/* Don't squeeze leading "//" to "/", on hosts where they're distinct. */
|
||||
name += (DOUBLE_SLASH_IS_DISTINCT_ROOT
|
||||
&& ISSLASH (*name) && ISSLASH (name[1]) && ! ISSLASH (name[2]));
|
||||
|
||||
/* Omit redundant leading "." components. */
|
||||
for (q = p = name; (*p = *q) == '.' && ISSLASH (q[1]); p += !*q)
|
||||
for (q += 2; ISSLASH (*q); q++)
|
||||
continue;
|
||||
|
||||
/* Copy components from Q to P, omitting redundant slashes and
|
||||
internal "." components. */
|
||||
while ((*p++ = c = *q++) != '\0')
|
||||
if (ISSLASH (c))
|
||||
while (ISSLASH (q[*q == '.']))
|
||||
q += (*q == '.') + 1;
|
||||
|
||||
/* Omit redundant trailing "." component and slash. */
|
||||
if (2 < p - name)
|
||||
{
|
||||
p -= p[-2] == '.' && ISSLASH (p[-3]);
|
||||
p -= 2 < p - name && ISSLASH (p[-2]);
|
||||
p[-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize NAME by removing redundant slashes and "." components,
|
||||
including redundant trailing slashes.
|
||||
|
||||
Return a normalized newly-allocated copy. */
|
||||
|
||||
char *
|
||||
normalize_filename (int cdidx, const char *name)
|
||||
{
|
||||
char *copy = NULL;
|
||||
|
||||
if (IS_RELATIVE_FILE_NAME (name))
|
||||
{
|
||||
/* Set COPY to the absolute path for this name.
|
||||
|
||||
FIXME: There should be no need to get the absolute file name.
|
||||
tar_getcdpath does not return a true "canonical" path, so
|
||||
this following approach may lead to situations where the same
|
||||
file or directory is processed twice under different absolute
|
||||
paths without that duplication being detected. Perhaps we
|
||||
should use dev+ino pairs instead of names? (See listed03.at for
|
||||
a related test case.) */
|
||||
const char *cdpath = tar_getcdpath (cdidx);
|
||||
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]));
|
||||
copy = xmalloc (copylen + need_separator + strlen (name) + 1);
|
||||
strcpy (copy, cdpath);
|
||||
copy[copylen] = DIRECTORY_SEPARATOR;
|
||||
strcpy (copy + copylen + need_separator, name);
|
||||
}
|
||||
|
||||
if (!copy)
|
||||
copy = xstrdup (name);
|
||||
normalize_filename_x (copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
@@ -258,6 +340,76 @@ replace_prefix (char **pname, const char *samp, size_t slen,
|
||||
|
||||
/* Handling numbers. */
|
||||
|
||||
/* Convert VALUE, which is converted from a system integer type whose
|
||||
minimum value is MINVAL and maximum MINVAL, to an decimal
|
||||
integer string. Use the storage in BUF and return a pointer to the
|
||||
converted string. If VALUE is converted from a negative integer in
|
||||
the range MINVAL .. -1, represent it with a string representation
|
||||
of the negative integer, using leading '-'. */
|
||||
#if ! (INTMAX_MAX <= UINTMAX_MAX / 2)
|
||||
# error "sysinttostr: uintmax_t cannot represent all intmax_t values"
|
||||
#endif
|
||||
char *
|
||||
sysinttostr (uintmax_t value, intmax_t minval, uintmax_t maxval,
|
||||
char buf[SYSINT_BUFSIZE])
|
||||
{
|
||||
if (value <= maxval)
|
||||
return umaxtostr (value, buf);
|
||||
else
|
||||
{
|
||||
intmax_t i = value - minval;
|
||||
return imaxtostr (i + minval, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a prefix of the string ARG to a system integer type whose
|
||||
minimum value is MINVAL and maximum MAXVAL. If MINVAL is negative,
|
||||
negative integers MINVAL .. -1 are assumed to be represented using
|
||||
leading '-' in the usual way. If the represented value exceeds
|
||||
INTMAX_MAX, return a negative integer V such that (uintmax_t) V
|
||||
yields the represented value. If ARGLIM is nonnull, store into
|
||||
*ARGLIM a pointer to the first character after the prefix.
|
||||
|
||||
This is the inverse of sysinttostr.
|
||||
|
||||
On a normal return, set errno = 0.
|
||||
On conversion error, return 0 and set errno = EINVAL.
|
||||
On overflow, return an extreme value and set errno = ERANGE. */
|
||||
#if ! (INTMAX_MAX <= UINTMAX_MAX)
|
||||
# error "strtosysint: nonnegative intmax_t does not fit in uintmax_t"
|
||||
#endif
|
||||
intmax_t
|
||||
strtosysint (char const *arg, char **arglim, intmax_t minval, uintmax_t maxval)
|
||||
{
|
||||
errno = 0;
|
||||
if (maxval <= INTMAX_MAX)
|
||||
{
|
||||
if (ISDIGIT (arg[*arg == '-']))
|
||||
{
|
||||
intmax_t i = strtoimax (arg, arglim, 10);
|
||||
intmax_t imaxval = maxval;
|
||||
if (minval <= i && i <= imaxval)
|
||||
return i;
|
||||
errno = ERANGE;
|
||||
return i < minval ? minval : maxval;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ISDIGIT (*arg))
|
||||
{
|
||||
uintmax_t i = strtoumax (arg, arglim, 10);
|
||||
if (i <= maxval)
|
||||
return represent_uintmax (i);
|
||||
errno = ERANGE;
|
||||
return maxval;
|
||||
}
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Output fraction and trailing digits appropriate for a nanoseconds
|
||||
count equal to NS, but don't output unnecessary '.' or trailing
|
||||
zeros. */
|
||||
@@ -301,7 +453,7 @@ code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
|
||||
/* ignore invalid values of ns */
|
||||
if (BILLION <= ns || ns < 0)
|
||||
ns = 0;
|
||||
|
||||
|
||||
if (negative && ns != 0)
|
||||
{
|
||||
s++;
|
||||
@@ -314,6 +466,84 @@ code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
|
||||
code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
|
||||
return np;
|
||||
}
|
||||
|
||||
struct timespec
|
||||
decode_timespec (char const *arg, char **arg_lim, bool parse_fraction)
|
||||
{
|
||||
time_t s = TYPE_MINIMUM (time_t);
|
||||
int ns = -1;
|
||||
char const *p = arg;
|
||||
bool negative = *arg == '-';
|
||||
struct timespec r;
|
||||
|
||||
if (! ISDIGIT (arg[negative]))
|
||||
errno = EINVAL;
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
if (negative)
|
||||
{
|
||||
intmax_t i = strtoimax (arg, arg_lim, 10);
|
||||
if (TYPE_SIGNED (time_t) ? TYPE_MINIMUM (time_t) <= i : 0 <= i)
|
||||
s = i;
|
||||
else
|
||||
errno = ERANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uintmax_t i = strtoumax (arg, arg_lim, 10);
|
||||
if (i <= TYPE_MAXIMUM (time_t))
|
||||
s = i;
|
||||
else
|
||||
errno = ERANGE;
|
||||
}
|
||||
|
||||
p = *arg_lim;
|
||||
ns = 0;
|
||||
|
||||
if (parse_fraction && *p == '.')
|
||||
{
|
||||
int digits = 0;
|
||||
bool trailing_nonzero = false;
|
||||
|
||||
while (ISDIGIT (*++p))
|
||||
if (digits < LOG10_BILLION)
|
||||
digits++, ns = 10 * ns + (*p - '0');
|
||||
else
|
||||
trailing_nonzero |= *p != '0';
|
||||
|
||||
while (digits < LOG10_BILLION)
|
||||
digits++, ns *= 10;
|
||||
|
||||
if (negative)
|
||||
{
|
||||
/* Convert "-1.10000000000001" to s == -2, ns == 89999999.
|
||||
I.e., truncate time stamps towards minus infinity while
|
||||
converting them to internal form. */
|
||||
ns += trailing_nonzero;
|
||||
if (ns != 0)
|
||||
{
|
||||
if (s == TYPE_MINIMUM (time_t))
|
||||
ns = -1;
|
||||
else
|
||||
{
|
||||
s--;
|
||||
ns = BILLION - ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errno == ERANGE)
|
||||
ns = -1;
|
||||
}
|
||||
|
||||
*arg_lim = (char *) p;
|
||||
r.tv_sec = s;
|
||||
r.tv_nsec = ns;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* File handling. */
|
||||
|
||||
@@ -322,7 +552,7 @@ static char *before_backup_name;
|
||||
static char *after_backup_name;
|
||||
|
||||
/* Return 1 if FILE_NAME is obviously "." or "/". */
|
||||
static bool
|
||||
bool
|
||||
must_be_dot_or_slash (char const *file_name)
|
||||
{
|
||||
file_name += FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
@@ -363,7 +593,12 @@ safer_rmdir (const char *file_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rmdir (file_name);
|
||||
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,
|
||||
@@ -383,7 +618,7 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
|
||||
if (try_unlink_first)
|
||||
{
|
||||
if (unlink (file_name) == 0)
|
||||
if (unlinkat (chdir_fd, file_name, 0) == 0)
|
||||
return 1;
|
||||
|
||||
/* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
|
||||
@@ -399,7 +634,7 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
switch (errno)
|
||||
{
|
||||
case ENOTDIR:
|
||||
return !try_unlink_first && unlink (file_name) == 0;
|
||||
return !try_unlink_first && unlinkat (chdir_fd, file_name, 0) == 0;
|
||||
|
||||
case 0:
|
||||
case EEXIST:
|
||||
@@ -416,7 +651,7 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
|
||||
case RECURSIVE_REMOVE_OPTION:
|
||||
{
|
||||
char *directory = savedir (file_name);
|
||||
char *directory = tar_savedir (file_name, 0);
|
||||
char const *entry;
|
||||
size_t entrylen;
|
||||
|
||||
@@ -427,7 +662,7 @@ 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;
|
||||
@@ -476,7 +711,7 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
if (this_is_the_archive && _remdev (file_name))
|
||||
return true;
|
||||
|
||||
if (stat (file_name, &file_stat))
|
||||
if (deref_stat (file_name, &file_stat) != 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
return true;
|
||||
@@ -496,7 +731,8 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
if (! after_backup_name)
|
||||
xalloc_die ();
|
||||
|
||||
if (rename (before_backup_name, after_backup_name) == 0)
|
||||
if (renameat (chdir_fd, before_backup_name, chdir_fd, after_backup_name)
|
||||
== 0)
|
||||
{
|
||||
if (verbose_option)
|
||||
fprintf (stdlis, _("Renaming %s to %s\n"),
|
||||
@@ -523,7 +759,8 @@ undo_last_backup (void)
|
||||
{
|
||||
if (after_backup_name)
|
||||
{
|
||||
if (rename (after_backup_name, before_backup_name) != 0)
|
||||
if (renameat (chdir_fd, after_backup_name, chdir_fd, before_backup_name)
|
||||
!= 0)
|
||||
{
|
||||
int e = errno;
|
||||
ERROR ((0, e, _("%s: Cannot rename to %s"),
|
||||
@@ -538,39 +775,91 @@ undo_last_backup (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */
|
||||
/* Apply either stat or lstat to (NAME, BUF), depending on the
|
||||
presence of the --dereference option. NAME is relative to the
|
||||
most-recent argument to chdir_do. */
|
||||
int
|
||||
deref_stat (bool deref, char const *name, struct stat *buf)
|
||||
deref_stat (char const *name, struct stat *buf)
|
||||
{
|
||||
return deref ? stat (name, buf) : lstat (name, buf);
|
||||
return fstatat (chdir_fd, name, buf, fstatat_flags);
|
||||
}
|
||||
|
||||
/* Set FD's (i.e., FILE's) access time to TIMESPEC[0]. If that's not
|
||||
possible to do by itself, set its access and data modification
|
||||
times to TIMESPEC[0] and TIMESPEC[1], respectively. */
|
||||
int
|
||||
set_file_atime (int fd, char const *file, struct timespec const timespec[2])
|
||||
/* Read from FD into the buffer BUF with COUNT bytes. Attempt to fill
|
||||
BUF. Wait until input is available; this matters because files are
|
||||
opened O_NONBLOCK for security reasons, and on some file systems
|
||||
this can cause read to fail with errno == EAGAIN. Return the
|
||||
actual number of bytes read, zero for EOF, or
|
||||
SAFE_READ_ERROR upon error. */
|
||||
size_t
|
||||
blocking_read (int fd, void *buf, size_t count)
|
||||
{
|
||||
#ifdef _FIOSATIME
|
||||
if (0 <= fd)
|
||||
size_t bytes = safe_read (fd, buf, count);
|
||||
|
||||
#if defined F_SETFL && O_NONBLOCK
|
||||
if (bytes == SAFE_READ_ERROR && errno == EAGAIN)
|
||||
{
|
||||
struct timeval timeval;
|
||||
timeval.tv_sec = timespec[0].tv_sec;
|
||||
timeval.tv_usec = timespec[0].tv_nsec / 1000;
|
||||
if (ioctl (fd, _FIOSATIME, &timeval) == 0)
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
return gl_futimens (fd, file, timespec);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* Write to FD from the buffer BUF with COUNT bytes. Do a full write.
|
||||
Wait until an output buffer is available; this matters because
|
||||
files are opened O_NONBLOCK for security reasons, and on some file
|
||||
systems this can cause write to fail with errno == EAGAIN. Return
|
||||
the actual number of bytes written, setting errno if that is less
|
||||
than COUNT. */
|
||||
size_t
|
||||
blocking_write (int fd, void const *buf, size_t count)
|
||||
{
|
||||
size_t bytes = full_write (fd, buf, count);
|
||||
|
||||
#if defined F_SETFL && O_NONBLOCK
|
||||
if (bytes < count && errno == EAGAIN)
|
||||
{
|
||||
int flags = fcntl (fd, F_GETFL);
|
||||
if (0 <= flags && flags & O_NONBLOCK
|
||||
&& fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1)
|
||||
{
|
||||
char const *buffer = buf;
|
||||
bytes += full_write (fd, buffer + bytes, count - bytes);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* Set FD's (i.e., assuming the working directory is PARENTFD, FILE's)
|
||||
access time to ATIME. */
|
||||
int
|
||||
set_file_atime (int fd, int parentfd, char const *file, struct timespec atime)
|
||||
{
|
||||
struct timespec ts[2];
|
||||
ts[0] = atime;
|
||||
ts[1].tv_nsec = UTIME_OMIT;
|
||||
return fdutimensat (fd, parentfd, file, ts, fstatat_flags);
|
||||
}
|
||||
|
||||
/* A description of a working directory. */
|
||||
struct wd
|
||||
{
|
||||
/* The directory's name. */
|
||||
char const *name;
|
||||
int saved;
|
||||
struct saved_cwd saved_cwd;
|
||||
/* "Absolute" path representing this directory; in the contrast to
|
||||
the real absolute pathname, it can contain /../ components (see
|
||||
normalize_filename_x for the reason of it). It is NULL if the
|
||||
absolute path could not be determined. */
|
||||
char *abspath;
|
||||
/* If nonzero, the file descriptor of the directory, or AT_FDCWD if
|
||||
the working directory. If zero, the directory needs to be opened
|
||||
to be used. */
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* A vector of chdir targets. wd[0] is the initial working directory. */
|
||||
@@ -582,8 +871,21 @@ static size_t wd_count;
|
||||
/* The allocated size of the vector. */
|
||||
static size_t wd_alloc;
|
||||
|
||||
/* The maximum number of chdir targets with open directories.
|
||||
Don't make it too large, as many operating systems have a small
|
||||
limit on the number of open file descriptors. Also, the current
|
||||
implementation does not scale well. */
|
||||
enum { CHDIR_CACHE_SIZE = 16 };
|
||||
|
||||
/* Indexes into WD of chdir targets with open file descriptors, sorted
|
||||
most-recently used first. Zero indexes are unused. */
|
||||
static int wdcache[CHDIR_CACHE_SIZE];
|
||||
|
||||
/* Number of nonzero entries in WDCACHE. */
|
||||
static size_t wdcache_count;
|
||||
|
||||
int
|
||||
chdir_count ()
|
||||
chdir_count (void)
|
||||
{
|
||||
if (wd_count == 0)
|
||||
return wd_count;
|
||||
@@ -595,20 +897,19 @@ chdir_count ()
|
||||
int
|
||||
chdir_arg (char const *dir)
|
||||
{
|
||||
char *absdir;
|
||||
|
||||
if (wd_count == wd_alloc)
|
||||
{
|
||||
if (wd_alloc == 0)
|
||||
{
|
||||
wd_alloc = 2;
|
||||
wd = xmalloc (sizeof *wd * wd_alloc);
|
||||
}
|
||||
else
|
||||
wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
|
||||
wd_alloc = 2;
|
||||
wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
|
||||
|
||||
if (! wd_count)
|
||||
{
|
||||
wd[wd_count].name = ".";
|
||||
wd[wd_count].saved = 0;
|
||||
wd[wd_count].abspath = xgetcwd ();
|
||||
wd[wd_count].fd = AT_FDCWD;
|
||||
wd_count++;
|
||||
}
|
||||
}
|
||||
@@ -624,73 +925,129 @@ 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].saved = 0;
|
||||
wd[wd_count].abspath = absdir;
|
||||
wd[wd_count].fd = 0;
|
||||
return wd_count++;
|
||||
}
|
||||
|
||||
/* Change to directory I. If I is 0, change to the initial working
|
||||
directory; otherwise, I must be a value returned by chdir_arg. */
|
||||
/* Index of current directory. */
|
||||
int chdir_current;
|
||||
|
||||
/* Value suitable for use as the first argument to openat, and in
|
||||
similar locations for fstatat, etc. This is an open file
|
||||
descriptor, or AT_FDCWD if the working directory is current. It is
|
||||
valid until the next invocation of chdir_do. */
|
||||
int chdir_fd = AT_FDCWD;
|
||||
|
||||
/* Change to directory I, in a virtual way. This does not actually
|
||||
invoke chdir; it merely sets chdir_fd to an int suitable as the
|
||||
first argument for openat, etc. If I is 0, change to the initial
|
||||
working directory; otherwise, I must be a value returned by
|
||||
chdir_arg. */
|
||||
void
|
||||
chdir_do (int i)
|
||||
{
|
||||
static int previous;
|
||||
|
||||
if (previous != i)
|
||||
if (chdir_current != i)
|
||||
{
|
||||
struct wd *prev = &wd[previous];
|
||||
struct wd *curr = &wd[i];
|
||||
int fd = curr->fd;
|
||||
|
||||
if (! prev->saved)
|
||||
if (! fd)
|
||||
{
|
||||
int err = 0;
|
||||
prev->saved = 1;
|
||||
if (save_cwd (&prev->saved_cwd) != 0)
|
||||
err = errno;
|
||||
else if (0 <= prev->saved_cwd.desc)
|
||||
{
|
||||
/* Make sure we still have at least one descriptor available. */
|
||||
int fd1 = prev->saved_cwd.desc;
|
||||
int fd2 = dup (fd1);
|
||||
if (0 <= fd2)
|
||||
close (fd2);
|
||||
else if (errno == EMFILE)
|
||||
{
|
||||
/* Force restore_cwd to use chdir_long. */
|
||||
close (fd1);
|
||||
prev->saved_cwd.desc = -1;
|
||||
prev->saved_cwd.name = xgetcwd ();
|
||||
}
|
||||
else
|
||||
err = errno;
|
||||
}
|
||||
|
||||
if (err)
|
||||
FATAL_ERROR ((0, err, _("Cannot save working directory")));
|
||||
}
|
||||
|
||||
if (curr->saved)
|
||||
{
|
||||
if (restore_cwd (&curr->saved_cwd))
|
||||
FATAL_ERROR ((0, 0, _("Cannot change working directory")));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i && ! ISSLASH (curr->name[0]))
|
||||
if (! IS_ABSOLUTE_FILE_NAME (curr->name))
|
||||
chdir_do (i - 1);
|
||||
if (chdir (curr->name) != 0)
|
||||
chdir_fatal (curr->name);
|
||||
fd = openat (chdir_fd, curr->name,
|
||||
open_searchdir_flags & ~ O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
open_fatal (curr->name);
|
||||
|
||||
curr->fd = fd;
|
||||
|
||||
/* Add I to the cache, tossing out the lowest-ranking entry if the
|
||||
cache is full. */
|
||||
if (wdcache_count < CHDIR_CACHE_SIZE)
|
||||
wdcache[wdcache_count++] = i;
|
||||
else
|
||||
{
|
||||
struct wd *stale = &wd[wdcache[CHDIR_CACHE_SIZE - 1]];
|
||||
if (close (stale->fd) != 0)
|
||||
close_diag (stale->name);
|
||||
stale->fd = 0;
|
||||
wdcache[CHDIR_CACHE_SIZE - 1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
previous = i;
|
||||
if (0 < fd)
|
||||
{
|
||||
/* Move the i value to the front of the cache. This is
|
||||
O(CHDIR_CACHE_SIZE), but the cache is small. */
|
||||
size_t ci;
|
||||
int prev = wdcache[0];
|
||||
for (ci = 1; prev != i; ci++)
|
||||
{
|
||||
int cur = wdcache[ci];
|
||||
wdcache[ci] = prev;
|
||||
if (cur == i)
|
||||
break;
|
||||
prev = cur;
|
||||
}
|
||||
wdcache[0] = i;
|
||||
}
|
||||
|
||||
chdir_current = i;
|
||||
chdir_fd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
tar_dirname (void)
|
||||
{
|
||||
return wd[chdir_current].name;
|
||||
}
|
||||
|
||||
/* Return the absolute path that represents the working
|
||||
directory referenced by IDX.
|
||||
|
||||
If wd is empty, then there were no -C options given, and
|
||||
chdir_args() has never been called, so we simply return the
|
||||
process's actual cwd. (Note that in this case IDX is ignored,
|
||||
since it should always be 0.) */
|
||||
static const char *
|
||||
tar_getcdpath (int idx)
|
||||
{
|
||||
if (!wd)
|
||||
{
|
||||
static char *cwd;
|
||||
if (!cwd)
|
||||
cwd = xgetcwd ();
|
||||
return cwd;
|
||||
}
|
||||
return wd[idx].abspath;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -699,7 +1056,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);
|
||||
}
|
||||
@@ -708,7 +1068,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);
|
||||
}
|
||||
@@ -717,7 +1080,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);
|
||||
}
|
||||
@@ -726,7 +1092,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);
|
||||
}
|
||||
@@ -735,7 +1104,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);
|
||||
}
|
||||
@@ -744,7 +1116,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);
|
||||
}
|
||||
@@ -759,33 +1134,11 @@ file_removed_diag (const char *name, bool top_level,
|
||||
(0, 0, _("%s: File removed before we read it"),
|
||||
quotearg_colon (name)));
|
||||
set_exit_status (TAREXIT_DIFFERS);
|
||||
}
|
||||
else
|
||||
diagfn (name);
|
||||
}
|
||||
|
||||
void
|
||||
dir_removed_diag (const char *name, bool top_level,
|
||||
void (*diagfn) (char const *name))
|
||||
{
|
||||
if (!top_level && errno == ENOENT)
|
||||
{
|
||||
WARNOPT (WARN_FILE_REMOVED,
|
||||
(0, 0, _("%s: Directory removed before we read it"),
|
||||
quotearg_colon (name)));
|
||||
set_exit_status (TAREXIT_DIFFERS);
|
||||
}
|
||||
else
|
||||
diagfn (name);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -835,7 +1188,7 @@ page_aligned_alloc (void **ptr, size_t size)
|
||||
|
||||
struct namebuf
|
||||
{
|
||||
char *buffer; /* directory, `/', and directory member */
|
||||
char *buffer; /* directory, '/', and directory member */
|
||||
size_t buffer_size; /* allocated size of name_buffer */
|
||||
size_t dir_length; /* length of directory part in buffer */
|
||||
};
|
||||
@@ -870,5 +1223,54 @@ namebuf_name (namebuf_t buf, const char *name)
|
||||
return buf->buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
namebuf_add_dir (namebuf_t buf, const char *name)
|
||||
{
|
||||
static char dirsep[] = { DIRECTORY_SEPARATOR, 0 };
|
||||
if (!ISSLASH (buf->buffer[buf->dir_length - 1]))
|
||||
{
|
||||
namebuf_name (buf, dirsep);
|
||||
buf->dir_length++;
|
||||
}
|
||||
namebuf_name (buf, name);
|
||||
buf->dir_length += strlen (name);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
namebuf_finish (namebuf_t buf)
|
||||
{
|
||||
char *res = buf->buffer;
|
||||
|
||||
if (ISSLASH (buf->buffer[buf->dir_length - 1]))
|
||||
buf->buffer[buf->dir_length] = 0;
|
||||
free (buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Return the filenames in directory NAME, relative to the chdir_fd.
|
||||
If the directory does not exist, report error if MUST_EXIST is
|
||||
true.
|
||||
|
||||
Return NULL on errors.
|
||||
*/
|
||||
char *
|
||||
tar_savedir (const char *name, int must_exist)
|
||||
{
|
||||
char *ret = NULL;
|
||||
DIR *dir = NULL;
|
||||
int fd = openat (chdir_fd, name, open_read_flags | O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!must_exist && errno == ENOENT)
|
||||
return NULL;
|
||||
open_error (name);
|
||||
}
|
||||
else if (! ((dir = fdopendir (fd))
|
||||
&& (ret = streamsavedir (dir, savedir_sort_order))))
|
||||
savedir_error (name);
|
||||
|
||||
if (dir ? closedir (dir) != 0 : 0 <= fd && close (fd) != 0)
|
||||
savedir_error (name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
1176
src/names.c
1176
src/names.c
File diff suppressed because it is too large
Load Diff
289
src/sparse.c
289
src/sparse.c
@@ -1,6 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2003-2007, 2010, 2013-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -13,8 +13,7 @@
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <inttostr.h>
|
||||
@@ -209,52 +208,51 @@ 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;
|
||||
char buffer[BLOCKSIZE];
|
||||
size_t count;
|
||||
size_t count = 0;
|
||||
off_t offset = 0;
|
||||
struct sp_array sp = {0, 0};
|
||||
|
||||
if (!lseek_or_error (file, 0))
|
||||
return false;
|
||||
|
||||
st->archive_file_size = 0;
|
||||
|
||||
|
||||
if (!tar_sparse_scan (file, scan_begin, NULL))
|
||||
return false;
|
||||
|
||||
while ((count = safe_read (fd, buffer, sizeof buffer)) != 0
|
||||
&& count != SAFE_READ_ERROR)
|
||||
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;
|
||||
}
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* save one more sparse segment of length 0 to indicate that
|
||||
the file ends with a hole */
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
|
||||
@@ -263,6 +261,115 @@ 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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#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;
|
||||
@@ -324,7 +431,6 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
|
||||
bytes_left -= bytes_read;
|
||||
file->dumped_size += bytes_read;
|
||||
mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
|
||||
set_next_block_after (blk);
|
||||
}
|
||||
|
||||
@@ -334,7 +440,7 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
static bool
|
||||
sparse_extract_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
size_t write_size;
|
||||
off_t write_size;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
|
||||
return false;
|
||||
@@ -358,7 +464,7 @@ sparse_extract_region (struct tar_sparse_file *file, size_t i)
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
count = full_write (file->fd, blk->buffer, wrbytes);
|
||||
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);
|
||||
@@ -398,10 +504,11 @@ sparse_dump_file (int fd, struct tar_stat_info *st)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
mv_begin (file.stat_info);
|
||||
mv_begin_write (file.stat_info->file_name,
|
||||
file.stat_info->stat.st_size,
|
||||
file.stat_info->archive_file_size - file.dumped_size);
|
||||
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
|
||||
rc = tar_sparse_dump_region (&file, i);
|
||||
mv_end ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,13 +615,13 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
static bool
|
||||
check_data_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
size_t size_left;
|
||||
off_t size_left;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
|
||||
return false;
|
||||
size_left = file->stat_info->sparse_map[i].numbytes;
|
||||
mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
|
||||
|
||||
|
||||
while (size_left > 0)
|
||||
{
|
||||
size_t bytes_read;
|
||||
@@ -564,9 +671,9 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
|
||||
file.stat_info = st;
|
||||
file.fd = fd;
|
||||
file.seekable = true; /* File *must* be seekable for compare to work */
|
||||
|
||||
|
||||
rc = tar_sparse_decode_header (&file);
|
||||
mv_begin (st);
|
||||
mv_begin_read (st);
|
||||
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
rc = check_sparse_region (&file,
|
||||
@@ -579,7 +686,7 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
|
||||
if (!rc)
|
||||
skip_file (file.stat_info->archive_file_size - file.dumped_size);
|
||||
mv_end ();
|
||||
|
||||
|
||||
tar_sparse_done (&file);
|
||||
return rc;
|
||||
}
|
||||
@@ -588,18 +695,18 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
|
||||
/* Old GNU Format. The sparse file information is stored in the
|
||||
oldgnu_header in the following manner:
|
||||
|
||||
The header is marked with type 'S'. Its `size' field contains
|
||||
The header is marked with type 'S'. Its 'size' field contains
|
||||
the cumulative size of all non-empty blocks of the file. The
|
||||
actual file size is stored in `realsize' member of oldgnu_header.
|
||||
actual file size is stored in 'realsize' member of oldgnu_header.
|
||||
|
||||
The map of the file is stored in a list of `struct sparse'.
|
||||
The map of the file is stored in a list of 'struct sparse'.
|
||||
Each struct contains offset to the block of data and its
|
||||
size (both as octal numbers). The first file header contains
|
||||
at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
|
||||
contains more structs, then the field `isextended' of the main
|
||||
header is set to 1 (binary) and the `struct sparse_header'
|
||||
contains more structs, then the field 'isextended' of the main
|
||||
header is set to 1 (binary) and the 'struct sparse_header'
|
||||
header follows, containing at most 21 following structs
|
||||
(SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
|
||||
(SPARSES_IN_SPARSE_HEADER). If more structs follow, 'isextended'
|
||||
field of the extended header is set and next next extension header
|
||||
follows, etc... */
|
||||
|
||||
@@ -625,8 +732,9 @@ oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
|
||||
if (s->numbytes[0] == '\0')
|
||||
return add_finish;
|
||||
sp.offset = OFF_FROM_HEADER (s->offset);
|
||||
sp.numbytes = SIZE_FROM_HEADER (s->numbytes);
|
||||
if (sp.offset < 0
|
||||
sp.numbytes = OFF_FROM_HEADER (s->numbytes);
|
||||
if (sp.offset < 0 || sp.numbytes < 0
|
||||
|| INT_ADD_OVERFLOW (sp.offset, sp.numbytes)
|
||||
|| file->stat_info->stat.st_size < sp.offset + sp.numbytes
|
||||
|| file->stat_info->archive_file_size < 0)
|
||||
return add_fail;
|
||||
@@ -640,10 +748,10 @@ oldgnu_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* NOTE! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
off_t realsize = OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
|
||||
return true;
|
||||
file->stat_info->stat.st_size = max (0, realsize);
|
||||
return 0 <= realsize;
|
||||
}
|
||||
|
||||
/* Convert old GNU format sparse data to internal representation */
|
||||
@@ -695,8 +803,8 @@ oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
|
||||
{
|
||||
OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
|
||||
sp->offset);
|
||||
SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
|
||||
sp->numbytes);
|
||||
OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
|
||||
sp->numbytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,10 +872,10 @@ star_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* NOTE! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
off_t realsize = OFF_FROM_HEADER (current_header->star_in_header.realsize);
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->star_in_header.realsize);
|
||||
return true;
|
||||
file->stat_info->stat.st_size = max (0, realsize);
|
||||
return 0 <= realsize;
|
||||
}
|
||||
|
||||
/* Convert STAR format sparse data to internal representation */
|
||||
@@ -807,6 +915,7 @@ star_get_sparse_info (struct tar_sparse_file *file)
|
||||
set_next_block_after (h);
|
||||
for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
|
||||
rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
|
||||
file->dumped_size += BLOCKSIZE;
|
||||
}
|
||||
|
||||
if (rc == add_fail)
|
||||
@@ -851,13 +960,13 @@ static struct tar_sparse_optab const star_optab = {
|
||||
instances of GNU.sparse.offset/GNU.sparse.numbytes variables, whereas
|
||||
POSIX requires the latest occurrence of the variable to override all
|
||||
previous occurrences.
|
||||
|
||||
|
||||
To avoid this incompatibility two following versions were introduced.
|
||||
|
||||
* 0.1
|
||||
|
||||
Used by tar 1.15.2 -- 1.15.91 (alpha releases).
|
||||
|
||||
|
||||
The sparse file map is stored in
|
||||
x header:
|
||||
|
||||
@@ -875,18 +984,18 @@ static struct tar_sparse_optab const star_optab = {
|
||||
Starting from this version, the exact sparse format version is specified
|
||||
explicitely in the header using the following variables:
|
||||
|
||||
GNU.sparse.major Major version
|
||||
GNU.sparse.major Major version
|
||||
GNU.sparse.minor Minor version
|
||||
|
||||
X header keeps the following variables:
|
||||
|
||||
|
||||
GNU.sparse.name Real file name of the sparse file
|
||||
GNU.sparse.realsize Real size of the stored file (corresponds to the old
|
||||
GNU.sparse.size variable)
|
||||
|
||||
The name field of the ustar header is constructed using the pattern
|
||||
"%d/GNUSparseFile.%p/%f".
|
||||
|
||||
|
||||
The sparse map itself is stored in the file data block, preceding the actual
|
||||
file data. It consists of a series of octal numbers of arbitrary length,
|
||||
delimited by newlines. The map is padded with nulls to the nearest block
|
||||
@@ -915,6 +1024,18 @@ pax_sparse_member_p (struct tar_sparse_file *file)
|
||||
|| file->stat_info->sparse_major > 0;
|
||||
}
|
||||
|
||||
/* Start a header that uses the effective (shrunken) file size. */
|
||||
static union block *
|
||||
pax_start_header (struct tar_stat_info *st)
|
||||
{
|
||||
off_t realsize = st->stat.st_size;
|
||||
union block *blk;
|
||||
st->stat.st_size = st->archive_file_size;
|
||||
blk = start_header (st);
|
||||
st->stat.st_size = realsize;
|
||||
return blk;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_dump_header_0 (struct tar_sparse_file *file)
|
||||
{
|
||||
@@ -924,11 +1045,11 @@ pax_dump_header_0 (struct tar_sparse_file *file)
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
struct sp_array *map = file->stat_info->sparse_map;
|
||||
char *save_file_name = NULL;
|
||||
|
||||
|
||||
/* Store the real file size */
|
||||
xheader_store ("GNU.sparse.size", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
|
||||
|
||||
|
||||
if (xheader_keyword_deleted_p ("GNU.sparse.map")
|
||||
|| tar_sparse_minor == 0)
|
||||
{
|
||||
@@ -964,9 +1085,7 @@ pax_dump_header_0 (struct tar_sparse_file *file)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
blk = start_header (file->stat_info);
|
||||
/* Store the effective (shrunken) file size */
|
||||
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
|
||||
blk = pax_start_header (file->stat_info);
|
||||
finish_header (file->stat_info, blk, block_ordinal);
|
||||
if (save_file_name)
|
||||
{
|
||||
@@ -991,7 +1110,7 @@ pax_dump_header_1 (struct tar_sparse_file *file)
|
||||
#define COPY_STRING(b,dst,src) do \
|
||||
{ \
|
||||
char *endp = b->buffer + BLOCKSIZE; \
|
||||
char *srcp = src; \
|
||||
char const *srcp = src; \
|
||||
while (*srcp) \
|
||||
{ \
|
||||
if (dst == endp) \
|
||||
@@ -1003,7 +1122,7 @@ pax_dump_header_1 (struct tar_sparse_file *file)
|
||||
} \
|
||||
*dst++ = *srcp++; \
|
||||
} \
|
||||
} while (0)
|
||||
} while (0)
|
||||
|
||||
/* Compute stored file size */
|
||||
p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
|
||||
@@ -1018,19 +1137,20 @@ pax_dump_header_1 (struct tar_sparse_file *file)
|
||||
size = (size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
file->stat_info->archive_file_size += size * BLOCKSIZE;
|
||||
file->dumped_size += size * BLOCKSIZE;
|
||||
|
||||
|
||||
/* Store sparse file identification */
|
||||
xheader_store ("GNU.sparse.major", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.minor", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.name", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.realsize", file->stat_info, NULL);
|
||||
|
||||
file->stat_info->file_name = xheader_format_name (file->stat_info,
|
||||
"%d/GNUSparseFile.%p/%f", 0);
|
||||
|
||||
blk = start_header (file->stat_info);
|
||||
/* Store the effective (shrunken) file size */
|
||||
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
|
||||
file->stat_info->file_name =
|
||||
xheader_format_name (file->stat_info, "%d/GNUSparseFile.%p/%f", 0);
|
||||
/* Make sure the created header name is shorter than NAME_FIELD_SIZE: */
|
||||
if (strlen (file->stat_info->file_name) > NAME_FIELD_SIZE)
|
||||
file->stat_info->file_name[NAME_FIELD_SIZE] = 0;
|
||||
|
||||
blk = pax_start_header (file->stat_info);
|
||||
finish_header (file->stat_info, blk, block_ordinal);
|
||||
free (file->stat_info->file_name);
|
||||
file->stat_info->file_name = save_file_name;
|
||||
@@ -1072,12 +1192,13 @@ decode_num (uintmax_t *num, char const *arg, uintmax_t maxval)
|
||||
|
||||
if (!ISDIGIT (*arg))
|
||||
return false;
|
||||
|
||||
|
||||
errno = 0;
|
||||
u = strtoumax (arg, &arg_lim, 10);
|
||||
|
||||
if (! (u <= maxval && errno != ERANGE) || *arg_lim)
|
||||
return false;
|
||||
|
||||
|
||||
*num = u;
|
||||
return true;
|
||||
}
|
||||
@@ -1117,7 +1238,7 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
} \
|
||||
while (*dst++ != '\n'); \
|
||||
dst[-1] = 0; \
|
||||
} while (0)
|
||||
} while (0)
|
||||
|
||||
set_next_block_after (current_header);
|
||||
file->dumped_size += BLOCKSIZE;
|
||||
@@ -1126,7 +1247,7 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
@@ -1137,19 +1258,19 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
for (i = 0; i < file->stat_info->sparse_map_size; i++)
|
||||
{
|
||||
struct sp_array sp;
|
||||
|
||||
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
sp.offset = u;
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
@@ -1158,7 +1279,7 @@ pax_decode_header (struct tar_sparse_file *file)
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1168,7 +1289,7 @@ static struct tar_sparse_optab const pax_optab = {
|
||||
pax_sparse_member_p,
|
||||
pax_dump_header,
|
||||
NULL,
|
||||
pax_decode_header,
|
||||
pax_decode_header,
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
|
||||
76
src/suffix.c
76
src/suffix.c
@@ -1,5 +1,6 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2007, 2009 Free Software Foundation, Inc.
|
||||
Copyright 2007, 2009, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Written by Sergey Poznyakoff.
|
||||
|
||||
@@ -27,8 +28,9 @@ struct compression_suffix
|
||||
};
|
||||
|
||||
static struct compression_suffix compression_suffixes[] = {
|
||||
#define __CAT2__(a,b) a ## b
|
||||
#define __CAT2__(a,b) a ## b
|
||||
#define S(s,p) #s, sizeof (#s) - 1, __CAT2__(p,_PROGRAM)
|
||||
{ "tar", 3, NULL },
|
||||
{ S(gz, GZIP) },
|
||||
{ S(tgz, GZIP) },
|
||||
{ S(taz, GZIP) },
|
||||
@@ -43,41 +45,71 @@ static struct compression_suffix compression_suffixes[] = {
|
||||
{ S(tlz, LZMA) },
|
||||
{ S(lzo, LZOP) },
|
||||
{ S(xz, XZ) },
|
||||
{ S(txz, XZ) }, /* Slackware */
|
||||
{ NULL }
|
||||
#undef S
|
||||
#undef __CAT2__
|
||||
};
|
||||
|
||||
static int nsuffixes = sizeof (compression_suffixes) /
|
||||
sizeof (compression_suffixes[0]);
|
||||
static struct compression_suffix const *
|
||||
find_compression_suffix (const char *name, size_t *ret_len)
|
||||
{
|
||||
char *suf = strrchr (name, '.');
|
||||
|
||||
if (suf)
|
||||
{
|
||||
size_t len;
|
||||
struct compression_suffix *p;
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
for (p = compression_suffixes; p->suffix; p++)
|
||||
{
|
||||
if (p->length == len && memcmp (p->suffix, suf, len) == 0)
|
||||
{
|
||||
if (ret_len)
|
||||
*ret_len = strlen (name) - len - 1;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
find_compression_program (const char *name, const char *defprog)
|
||||
{
|
||||
char *suf = strrchr (name, '.');
|
||||
|
||||
if (suf)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
for (i = 0; i < nsuffixes; i++)
|
||||
{
|
||||
if (compression_suffixes[i].length == len
|
||||
&& memcmp (compression_suffixes[i].suffix, suf, len) == 0)
|
||||
return compression_suffixes[i].program;
|
||||
}
|
||||
}
|
||||
struct compression_suffix const *p = find_compression_suffix (name, NULL);
|
||||
if (p)
|
||||
return p->program;
|
||||
return defprog;
|
||||
}
|
||||
|
||||
void
|
||||
set_comression_program_by_suffix (const char *name, const char *defprog)
|
||||
set_compression_program_by_suffix (const char *name, const char *defprog)
|
||||
{
|
||||
const char *program = find_compression_program (name, defprog);
|
||||
if (program)
|
||||
use_compress_program_option = program;
|
||||
}
|
||||
|
||||
char *
|
||||
strip_compression_suffix (const char *name)
|
||||
{
|
||||
char *s = NULL;
|
||||
size_t len;
|
||||
|
||||
if (find_compression_suffix (name, &len))
|
||||
{
|
||||
if (strncmp (name + len - 4, ".tar", 4) == 0)
|
||||
len -= 4;
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
s = xmalloc (len + 1);
|
||||
memcpy (s, name, len);
|
||||
s[len] = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
145
src/system.c
145
src/system.c
@@ -1,7 +1,7 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007,
|
||||
2008 Free Software Foundation, Inc.
|
||||
Copyright 2003-2008, 2010, 2013-2014, 2016-2017 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -14,14 +14,29 @@
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <priv-set.h>
|
||||
#include <rmt.h>
|
||||
#include <signal.h>
|
||||
#include <wordsplit.h>
|
||||
|
||||
static _Noreturn void
|
||||
xexec (const char *cmd)
|
||||
{
|
||||
char *argv[4];
|
||||
|
||||
argv[0] = (char *) "/bin/sh";
|
||||
argv[1] = (char *) "-c";
|
||||
argv[2] = (char *) cmd;
|
||||
argv[3] = NULL;
|
||||
|
||||
execv ("/bin/sh", argv);
|
||||
exec_fatal (cmd);
|
||||
}
|
||||
|
||||
#if MSDOS
|
||||
|
||||
@@ -192,7 +207,8 @@ sys_spawn_shell (void)
|
||||
child = xfork ();
|
||||
if (child == 0)
|
||||
{
|
||||
execlp (shell, "-sh", "-i", (char *) 0);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (shell, "-sh", "-i", NULL);
|
||||
exec_fatal (shell);
|
||||
}
|
||||
else
|
||||
@@ -283,15 +299,15 @@ xdup2 (int from, int into)
|
||||
}
|
||||
}
|
||||
|
||||
void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
|
||||
static void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
|
||||
|
||||
/* Propagate any failure of the grandchild back to the parent. */
|
||||
void
|
||||
static void
|
||||
wait_for_grandchild (pid_t pid)
|
||||
{
|
||||
int wait_status;
|
||||
int exit_code = 0;
|
||||
|
||||
|
||||
while (waitpid (pid, &wait_status, 0) == -1)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
@@ -303,7 +319,7 @@ wait_for_grandchild (pid_t pid)
|
||||
raise (WTERMSIG (wait_status));
|
||||
else if (WEXITSTATUS (wait_status) != 0)
|
||||
exit_code = WEXITSTATUS (wait_status);
|
||||
|
||||
|
||||
exit (exit_code);
|
||||
}
|
||||
|
||||
@@ -316,6 +332,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 ();
|
||||
|
||||
@@ -332,7 +349,7 @@ sys_child_open_for_compress (void)
|
||||
|
||||
set_program_name (_("tar (child)"));
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
|
||||
|
||||
xdup2 (parent_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (parent_pipe[PWRITE]);
|
||||
|
||||
@@ -362,8 +379,8 @@ sys_child_open_for_compress (void)
|
||||
}
|
||||
xdup2 (archive, STDOUT_FILENO);
|
||||
}
|
||||
execlp (use_compress_program_option, use_compress_program_option, NULL);
|
||||
exec_fatal (use_compress_program_option);
|
||||
priv_set_restore_linkdir ();
|
||||
xexec (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -379,9 +396,8 @@ sys_child_open_for_compress (void)
|
||||
|
||||
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (child_pipe[PREAD]);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
(char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
priv_set_restore_linkdir ();
|
||||
xexec (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
@@ -451,6 +467,42 @@ sys_child_open_for_compress (void)
|
||||
wait_for_grandchild (grandchild_pid);
|
||||
}
|
||||
|
||||
static void
|
||||
run_decompress_program (void)
|
||||
{
|
||||
int i;
|
||||
const char *p, *prog = NULL;
|
||||
struct wordsplit ws;
|
||||
int wsflags = (WRDSF_DEFFLAGS | WRDSF_ENV | WRDSF_DOOFFS) & ~WRDSF_NOVAR;
|
||||
|
||||
ws.ws_env = (const char **) environ;
|
||||
ws.ws_offs = 1;
|
||||
|
||||
for (p = first_decompress_program (&i); p; p = next_decompress_program (&i))
|
||||
{
|
||||
if (prog)
|
||||
{
|
||||
WARNOPT (WARN_DECOMPRESS_PROGRAM,
|
||||
(0, errno, _("cannot run %s"), prog));
|
||||
WARNOPT (WARN_DECOMPRESS_PROGRAM,
|
||||
(0, 0, _("trying %s"), p));
|
||||
}
|
||||
if (wordsplit (p, &ws, wsflags))
|
||||
FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"),
|
||||
p, wordsplit_strerror (&ws)));
|
||||
wsflags |= WRDSF_REUSE;
|
||||
memmove(ws.ws_wordv, ws.ws_wordv + ws.ws_offs,
|
||||
sizeof(ws.ws_wordv[0])*ws.ws_wordc);
|
||||
ws.ws_wordv[ws.ws_wordc] = (char *) "-d";
|
||||
prog = p;
|
||||
execvp (ws.ws_wordv[0], ws.ws_wordv);
|
||||
ws.ws_wordv[ws.ws_wordc] = NULL;
|
||||
}
|
||||
if (!prog)
|
||||
FATAL_ERROR ((0, 0, _("unable to run decompression program")));
|
||||
exec_fatal (prog);
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for uncompressing, then reading an archive. */
|
||||
pid_t
|
||||
sys_child_open_for_uncompress (void)
|
||||
@@ -476,7 +528,7 @@ sys_child_open_for_uncompress (void)
|
||||
|
||||
set_program_name (_("tar (child)"));
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
|
||||
|
||||
xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (parent_pipe[PREAD]);
|
||||
|
||||
@@ -496,9 +548,8 @@ sys_child_open_for_uncompress (void)
|
||||
if (archive < 0)
|
||||
open_fatal (archive_name_array[0]);
|
||||
xdup2 (archive, STDIN_FILENO);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
priv_set_restore_linkdir ();
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -514,9 +565,8 @@ sys_child_open_for_uncompress (void)
|
||||
|
||||
xdup2 (child_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (child_pipe[PWRITE]);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
priv_set_restore_linkdir ();
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
@@ -575,7 +625,7 @@ sys_child_open_for_uncompress (void)
|
||||
|
||||
|
||||
static void
|
||||
dec_to_env (char *envar, uintmax_t num)
|
||||
dec_to_env (char const *envar, uintmax_t num)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
char *numstr;
|
||||
@@ -586,7 +636,7 @@ dec_to_env (char *envar, uintmax_t num)
|
||||
}
|
||||
|
||||
static void
|
||||
time_to_env (char *envar, struct timespec t)
|
||||
time_to_env (char const *envar, struct timespec t)
|
||||
{
|
||||
char buf[TIMESPEC_STRSIZE_BOUND];
|
||||
if (setenv (envar, code_timespec (t, buf), 1) != 0)
|
||||
@@ -594,7 +644,7 @@ time_to_env (char *envar, struct timespec t)
|
||||
}
|
||||
|
||||
static void
|
||||
oct_to_env (char *envar, unsigned long num)
|
||||
oct_to_env (char const *envar, unsigned long num)
|
||||
{
|
||||
char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
|
||||
|
||||
@@ -604,7 +654,7 @@ oct_to_env (char *envar, unsigned long num)
|
||||
}
|
||||
|
||||
static void
|
||||
str_to_env (char *envar, char const *str)
|
||||
str_to_env (char const *envar, char const *str)
|
||||
{
|
||||
if (str)
|
||||
{
|
||||
@@ -616,7 +666,7 @@ str_to_env (char *envar, char const *str)
|
||||
}
|
||||
|
||||
static void
|
||||
chr_to_env (char *envar, char c)
|
||||
chr_to_env (char const *envar, char c)
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
@@ -673,13 +723,12 @@ stat_to_env (char *name, char type, struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
static pid_t global_pid;
|
||||
static RETSIGTYPE (*pipe_handler) (int sig);
|
||||
static void (*pipe_handler) (int sig);
|
||||
|
||||
int
|
||||
sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
|
||||
{
|
||||
int p[2];
|
||||
char *argv[4];
|
||||
|
||||
xpipe (p);
|
||||
pipe_handler = signal (SIGPIPE, SIG_IGN);
|
||||
@@ -697,14 +746,8 @@ sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
|
||||
|
||||
stat_to_env (file_name, typechar, st);
|
||||
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = to_command_option;
|
||||
argv[3] = NULL;
|
||||
|
||||
execv ("/bin/sh", argv);
|
||||
|
||||
exec_fatal (file_name);
|
||||
priv_set_restore_linkdir ();
|
||||
xexec (to_command_option);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -746,11 +789,10 @@ int
|
||||
sys_exec_info_script (const char **archive_name, int volume_number)
|
||||
{
|
||||
pid_t pid;
|
||||
char *argv[4];
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
int p[2];
|
||||
static RETSIGTYPE (*saved_handler) (int sig);
|
||||
|
||||
static void (*saved_handler) (int sig);
|
||||
|
||||
xpipe (p);
|
||||
saved_handler = signal (SIGPIPE, SIG_IGN);
|
||||
|
||||
@@ -783,7 +825,7 @@ sys_exec_info_script (const char **archive_name, int volume_number)
|
||||
}
|
||||
|
||||
signal (SIGPIPE, saved_handler);
|
||||
|
||||
|
||||
if (WIFEXITED (status))
|
||||
{
|
||||
if (WEXITSTATUS (status) == 0 && rc > 0)
|
||||
@@ -811,14 +853,8 @@ sys_exec_info_script (const char **archive_name, int volume_number)
|
||||
|
||||
xclose (p[PREAD]);
|
||||
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = (char*) info_script_option;
|
||||
argv[3] = NULL;
|
||||
|
||||
execv (argv[0], argv);
|
||||
|
||||
exec_fatal (info_script_option);
|
||||
priv_set_restore_linkdir ();
|
||||
xexec (info_script_option);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -827,7 +863,6 @@ sys_exec_checkpoint_script (const char *script_name,
|
||||
int checkpoint_number)
|
||||
{
|
||||
pid_t pid;
|
||||
char *argv[4];
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
pid = xfork ();
|
||||
@@ -858,14 +893,8 @@ sys_exec_checkpoint_script (const char *script_name,
|
||||
setenv ("TAR_FORMAT",
|
||||
archive_format_string (current_format == DEFAULT_FORMAT ?
|
||||
archive_format : current_format), 1);
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = (char*) script_name;
|
||||
argv[3] = NULL;
|
||||
|
||||
execv (argv[0], argv);
|
||||
|
||||
exec_fatal (script_name);
|
||||
priv_set_restore_linkdir ();
|
||||
xexec (script_name);
|
||||
}
|
||||
|
||||
#endif /* not MSDOS */
|
||||
|
||||
86
src/tar.h
86
src/tar.h
@@ -1,21 +1,22 @@
|
||||
/* GNU tar Archive Format description.
|
||||
|
||||
Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
||||
2000, 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1988-1989, 1991-1997, 2000-2001, 2003-2007, 2012-2014,
|
||||
2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 Header Block, from POSIX 1003.1-1990. */
|
||||
|
||||
@@ -80,9 +81,9 @@ struct posix_header
|
||||
/* tar Header Block, GNU extensions. */
|
||||
|
||||
/* In GNU tar, SYMTYPE is for to symbolic links, and CONTTYPE is for
|
||||
contiguous files, so maybe disobeying the `reserved' comment in POSIX
|
||||
contiguous files, so maybe disobeying the "reserved" comment in POSIX
|
||||
header description. I suspect these were meant to be used this way, and
|
||||
should not have really been `reserved' in the published standards. */
|
||||
should not have really been "reserved" in the published standards. */
|
||||
|
||||
/* *BEWARE* *BEWARE* *BEWARE* that the following information is still
|
||||
boiling, and may change. Even if the OLDGNU format description should be
|
||||
@@ -265,7 +266,7 @@ enum archive_format
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
off_t numbytes;
|
||||
};
|
||||
|
||||
struct xheader
|
||||
@@ -276,6 +277,14 @@ struct xheader
|
||||
uintmax_t string_length;
|
||||
};
|
||||
|
||||
/* Information about xattrs for a file. */
|
||||
struct xattr_array
|
||||
{
|
||||
char *xkey;
|
||||
char *xval_ptr;
|
||||
size_t xval_len;
|
||||
};
|
||||
|
||||
struct tar_stat_info
|
||||
{
|
||||
char *orig_file_name; /* name of file read from the archive header */
|
||||
@@ -287,6 +296,15 @@ struct tar_stat_info
|
||||
|
||||
char *uname; /* user name of owner */
|
||||
char *gname; /* group name of owner */
|
||||
|
||||
char *cntx_name; /* SELinux context for the current archive entry. */
|
||||
|
||||
char *acls_a_ptr; /* Access ACLs for the current archive entry. */
|
||||
size_t acls_a_len; /* Access ACLs for the current archive entry. */
|
||||
|
||||
char *acls_d_ptr; /* Default ACLs for the current archive entry. */
|
||||
size_t acls_d_len; /* Default ACLs for the current archive entry. */
|
||||
|
||||
struct stat stat; /* regular filesystem stat */
|
||||
|
||||
/* STAT doesn't always have access, data modification, and status
|
||||
@@ -309,14 +327,48 @@ struct tar_stat_info
|
||||
size_t sparse_map_size; /* Size of the sparse map */
|
||||
struct sp_array *sparse_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. */
|
||||
|
||||
size_t xattr_map_size; /* Size of the xattr map */
|
||||
struct xattr_array *xattr_map;
|
||||
|
||||
/* Extended headers */
|
||||
struct xheader xhdr;
|
||||
|
||||
|
||||
/* For dumpdirs */
|
||||
bool is_dumpdir; /* Is the member a dumpdir? */
|
||||
bool skipped; /* The member contents is already read
|
||||
(for GNUTYPE_DUMPDIR) */
|
||||
char *dumpdir; /* Contents of the dump directory */
|
||||
|
||||
/* Parent directory, if creating an archive. This is null if the
|
||||
file is at the top level. */
|
||||
struct tar_stat_info *parent;
|
||||
|
||||
/* Directory stream. If this is not null, it is in control of FD,
|
||||
and should be closed instead of FD. */
|
||||
DIR *dirstream;
|
||||
|
||||
/* File descriptor, if creating an archive, and if a directory or a
|
||||
regular file or a contiguous file.
|
||||
|
||||
It is zero if no file descriptor is available, either because it
|
||||
was never needed or because it was open and then closed to
|
||||
conserve on file descriptors. (Standard input is never used
|
||||
here, so zero cannot be a valid file descriptor.)
|
||||
|
||||
It is negative if it could not be reopened after it was closed.
|
||||
Negate it to find out what errno was when the reopen failed. */
|
||||
int fd;
|
||||
|
||||
/* Exclusion list */
|
||||
struct exclist *exclude_list;
|
||||
};
|
||||
|
||||
union block
|
||||
|
||||
122
src/transform.c
122
src/transform.c
@@ -1,5 +1,6 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
/* This file is part of GNU tar.
|
||||
Copyright 2006-2008, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -12,8 +13,7 @@
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <regex.h>
|
||||
@@ -34,8 +34,8 @@ enum replace_segm_type
|
||||
|
||||
enum case_ctl_type
|
||||
{
|
||||
ctl_stop, /* Stop case conversion */
|
||||
ctl_upcase_next,/* Turn the next character to uppercase */
|
||||
ctl_stop, /* Stop case conversion */
|
||||
ctl_upcase_next,/* Turn the next character to uppercase */
|
||||
ctl_locase_next,/* Turn the next character to lowercase */
|
||||
ctl_upcase, /* Turn the replacement to uppercase until ctl_stop */
|
||||
ctl_locase /* Turn the replacement to lowercase until ctl_stop */
|
||||
@@ -51,9 +51,9 @@ struct replace_segm
|
||||
{
|
||||
char *ptr;
|
||||
size_t size;
|
||||
} literal; /* type == segm_literal */
|
||||
} literal; /* type == segm_literal */
|
||||
size_t ref; /* type == segm_backref */
|
||||
enum case_ctl_type ctl; /* type == segm_case_ctl */
|
||||
enum case_ctl_type ctl; /* type == segm_case_ctl */
|
||||
} v;
|
||||
};
|
||||
|
||||
@@ -71,11 +71,11 @@ struct transform
|
||||
|
||||
|
||||
|
||||
int transform_flags = XFORM_ALL;
|
||||
static int transform_flags = XFORM_ALL;
|
||||
static struct transform *transform_head, *transform_tail;
|
||||
|
||||
static struct transform *
|
||||
new_transform ()
|
||||
new_transform (void)
|
||||
{
|
||||
struct transform *p = xzalloc (sizeof *p);
|
||||
if (transform_tail)
|
||||
@@ -146,7 +146,7 @@ parse_xform_flags (int *pflags, int c)
|
||||
case 'R':
|
||||
*pflags &= ~XFORM_REGFILE;
|
||||
break;
|
||||
|
||||
|
||||
case 'h':
|
||||
*pflags |= XFORM_LINK;
|
||||
break;
|
||||
@@ -154,7 +154,7 @@ parse_xform_flags (int *pflags, int c)
|
||||
case 'H':
|
||||
*pflags &= ~XFORM_LINK;
|
||||
break;
|
||||
|
||||
|
||||
case 's':
|
||||
*pflags |= XFORM_SYMLINK;
|
||||
break;
|
||||
@@ -204,10 +204,10 @@ parse_transform_expr (const char *expr)
|
||||
*expr));
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
}
|
||||
|
||||
|
||||
delim = expr[1];
|
||||
|
||||
/* Scan regular expression */
|
||||
@@ -258,14 +258,14 @@ parse_transform_expr (const char *expr)
|
||||
|
||||
if (*p == ';')
|
||||
p++;
|
||||
|
||||
|
||||
/* Extract and compile regex */
|
||||
str = xmalloc (i - 1);
|
||||
memcpy (str, expr + 2, i - 2);
|
||||
str[i - 2] = 0;
|
||||
|
||||
rc = regcomp (&tf->regex, str, cflags);
|
||||
|
||||
|
||||
if (rc)
|
||||
{
|
||||
char errbuf[512];
|
||||
@@ -275,7 +275,7 @@ parse_transform_expr (const char *expr)
|
||||
|
||||
if (str[0] == '^' || str[strlen (str) - 1] == '$')
|
||||
tf->transform_type = transform_first;
|
||||
|
||||
|
||||
free (str);
|
||||
|
||||
/* Extract and compile replacement expr */
|
||||
@@ -289,7 +289,7 @@ parse_transform_expr (const char *expr)
|
||||
if (*cur == '\\')
|
||||
{
|
||||
size_t n;
|
||||
|
||||
|
||||
add_literal_segment (tf, beg, cur);
|
||||
switch (*++cur)
|
||||
{
|
||||
@@ -310,32 +310,32 @@ parse_transform_expr (const char *expr)
|
||||
add_char_segment (tf, '\a');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'b':
|
||||
add_char_segment (tf, '\b');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'f':
|
||||
add_char_segment (tf, '\f');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'n':
|
||||
add_char_segment (tf, '\n');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'r':
|
||||
add_char_segment (tf, '\r');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 't':
|
||||
add_char_segment (tf, '\t');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'v':
|
||||
add_char_segment (tf, '\v');
|
||||
cur++;
|
||||
@@ -345,47 +345,49 @@ parse_transform_expr (const char *expr)
|
||||
add_char_segment (tf, '&');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'L':
|
||||
/* Turn the replacement to lowercase until a `\U' or `\E'
|
||||
/* Turn the replacement to lowercase until a '\U' or '\E'
|
||||
is found, */
|
||||
add_case_ctl_segment (tf, ctl_locase);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'l':
|
||||
/* Turn the next character to lowercase, */
|
||||
add_case_ctl_segment (tf, ctl_locase_next);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'U':
|
||||
/* Turn the replacement to uppercase until a `\L' or `\E'
|
||||
/* Turn the replacement to uppercase until a '\L' or '\E'
|
||||
is found, */
|
||||
add_case_ctl_segment (tf, ctl_upcase);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'u':
|
||||
/* Turn the next character to uppercase, */
|
||||
add_case_ctl_segment (tf, ctl_upcase_next);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
|
||||
case 'E':
|
||||
/* Stop case conversion started by `\L' or `\U'. */
|
||||
/* Stop case conversion started by '\L' or '\U'. */
|
||||
add_case_ctl_segment (tf, ctl_stop);
|
||||
cur++;
|
||||
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;
|
||||
}
|
||||
@@ -420,7 +422,7 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
|
||||
static char *case_ctl_buffer;
|
||||
static size_t case_ctl_bufsize;
|
||||
char *p;
|
||||
|
||||
|
||||
if (case_ctl_bufsize < size)
|
||||
{
|
||||
case_ctl_bufsize = size;
|
||||
@@ -432,16 +434,16 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
|
||||
case ctl_upcase_next:
|
||||
case_ctl_buffer[0] = toupper ((unsigned char) case_ctl_buffer[0]);
|
||||
break;
|
||||
|
||||
|
||||
case ctl_locase_next:
|
||||
case_ctl_buffer[0] = tolower ((unsigned char) case_ctl_buffer[0]);
|
||||
break;
|
||||
|
||||
|
||||
case ctl_upcase:
|
||||
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
|
||||
*p = toupper ((unsigned char) *p);
|
||||
break;
|
||||
|
||||
|
||||
case ctl_locase:
|
||||
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
|
||||
*p = tolower ((unsigned char) *p);
|
||||
@@ -457,7 +459,7 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
|
||||
static struct obstack stk;
|
||||
static bool stk_init;
|
||||
|
||||
void
|
||||
static void
|
||||
_single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
{
|
||||
regmatch_t *rmp;
|
||||
@@ -465,7 +467,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
size_t nmatches = 0;
|
||||
enum case_ctl_type case_ctl = ctl_stop, /* Current case conversion op */
|
||||
save_ctl = ctl_stop; /* Saved case_ctl for \u and \l */
|
||||
|
||||
|
||||
/* Reset case conversion after a single-char operation */
|
||||
#define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \
|
||||
|| case_ctl == ctl_locase_next) \
|
||||
@@ -473,20 +475,20 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
case_ctl = save_ctl; \
|
||||
save_ctl = ctl_stop; \
|
||||
}
|
||||
|
||||
|
||||
rmp = xmalloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
|
||||
|
||||
while (*input)
|
||||
{
|
||||
size_t disp;
|
||||
char *ptr;
|
||||
|
||||
|
||||
rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0);
|
||||
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
struct replace_segm *segm;
|
||||
|
||||
|
||||
disp = rmp[0].rm_eo;
|
||||
|
||||
if (rmp[0].rm_so)
|
||||
@@ -516,7 +518,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
}
|
||||
obstack_grow (&stk, ptr, segm->v.literal.size);
|
||||
break;
|
||||
|
||||
|
||||
case segm_backref: /* Back-reference segment */
|
||||
if (rmp[segm->v.ref].rm_so != -1
|
||||
&& rmp[segm->v.ref].rm_eo != -1)
|
||||
@@ -529,7 +531,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
ptr = run_case_conv (case_ctl, ptr, size);
|
||||
CASE_CTL_RESET();
|
||||
}
|
||||
|
||||
|
||||
obstack_grow (&stk, ptr, size);
|
||||
}
|
||||
break;
|
||||
@@ -549,7 +551,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
|
||||
|
||||
case ctl_upcase:
|
||||
case ctl_locase:
|
||||
case ctl_stop:
|
||||
@@ -577,18 +579,18 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
free (rmp);
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
_transform_name_to_obstack (int flags, char *input, char **output)
|
||||
{
|
||||
struct transform *tf;
|
||||
bool alloced = false;
|
||||
|
||||
|
||||
if (!stk_init)
|
||||
{
|
||||
obstack_init (&stk);
|
||||
stk_init = true;
|
||||
}
|
||||
|
||||
|
||||
for (tf = transform_head; tf; tf = tf->next)
|
||||
{
|
||||
if (tf->flags & flags)
|
||||
@@ -601,7 +603,7 @@ _transform_name_to_obstack (int flags, char *input, char **output)
|
||||
*output = input;
|
||||
return alloced;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
transform_name_fp (char **pinput, int flags,
|
||||
char *(*fun)(char *, void *), void *dat)
|
||||
@@ -628,3 +630,9 @@ transform_name (char **pinput, int type)
|
||||
{
|
||||
return transform_name_fp (pinput, type, NULL, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
transform_program_p (void)
|
||||
{
|
||||
return transform_head != NULL;
|
||||
}
|
||||
|
||||
157
src/unlink.c
157
src/unlink.c
@@ -1,19 +1,21 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
/* Unlink files.
|
||||
|
||||
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.
|
||||
Copyright 2009, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
This file is part of GNU tar.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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"
|
||||
@@ -22,12 +24,18 @@
|
||||
struct deferred_unlink
|
||||
{
|
||||
struct deferred_unlink *next; /* Next unlink in the queue */
|
||||
char *file_name; /* Absolute name of the file to unlink */
|
||||
int dir_idx; /* Directory index in wd */
|
||||
char *file_name; /* Name of the file to unlink, relative
|
||||
to dir_idx */
|
||||
bool is_dir; /* True if file_name is a directory */
|
||||
off_t records_written; /* Number of records written when this
|
||||
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;
|
||||
|
||||
@@ -39,10 +47,10 @@ static struct deferred_unlink *dunlink_avail;
|
||||
|
||||
/* Delay (number of records written) between adding entry to the
|
||||
list and its actual removal. */
|
||||
size_t deferred_unlink_delay = 0;
|
||||
static size_t deferred_unlink_delay = 0;
|
||||
|
||||
static struct deferred_unlink *
|
||||
dunlink_alloc ()
|
||||
dunlink_alloc (void)
|
||||
{
|
||||
struct deferred_unlink *p;
|
||||
if (dunlink_avail)
|
||||
@@ -56,6 +64,24 @@ dunlink_alloc ()
|
||||
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)
|
||||
{
|
||||
@@ -68,40 +94,54 @@ static void
|
||||
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;
|
||||
|
||||
if (force
|
||||
|| records_written > p->records_written + deferred_unlink_delay)
|
||||
{
|
||||
chdir_do (p->dir_idx);
|
||||
if (p->is_dir)
|
||||
{
|
||||
if (rmdir (p->file_name) != 0)
|
||||
const char *fname;
|
||||
|
||||
if (p->dir_idx && IS_CWD (p))
|
||||
{
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
fname = p->file_name;
|
||||
|
||||
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
/* nothing to worry about */
|
||||
break;
|
||||
case EEXIST:
|
||||
/* OpenSolaris >=10 sets EEXIST instead of ENOTEMPTY
|
||||
if trying to remove a non-empty directory */
|
||||
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 */
|
||||
/* Keep the record in list, in the hope we'll
|
||||
be able to remove it later */
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
|
||||
default:
|
||||
rmdir_error (p->file_name);
|
||||
rmdir_error (fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlink (p->file_name) != 0 && errno != ENOENT)
|
||||
if (unlinkat (chdir_fd, p->file_name, 0) != 0 && errno != ENOENT)
|
||||
unlink_error (p->file_name);
|
||||
}
|
||||
dunlink_reclaim (p);
|
||||
@@ -116,16 +156,46 @@ flush_deferred_unlinks (bool force)
|
||||
{
|
||||
prev = p;
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
finish_deferred_unlinks ()
|
||||
finish_deferred_unlinks (void)
|
||||
{
|
||||
flush_deferred_unlinks (true);
|
||||
|
||||
while (dunlink_avail)
|
||||
{
|
||||
struct deferred_unlink *next = dunlink_avail->next;
|
||||
@@ -142,17 +212,26 @@ queue_deferred_unlink (const char *name, bool is_dir)
|
||||
if (dunlink_head
|
||||
&& records_written > dunlink_head->records_written + deferred_unlink_delay)
|
||||
flush_deferred_unlinks (false);
|
||||
|
||||
|
||||
p = dunlink_alloc ();
|
||||
p->next = NULL;
|
||||
p->file_name = normalize_filename (name);
|
||||
p->dir_idx = chdir_current;
|
||||
p->file_name = xstrdup (name);
|
||||
normalize_filename_x (p->file_name);
|
||||
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);
|
||||
}
|
||||
|
||||
66
src/update.c
66
src/update.c
@@ -1,21 +1,22 @@
|
||||
/* Update a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003,
|
||||
2004, 2005, 2007, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992, 1994, 1996-1997, 1999-2001, 2003-2005, 2007,
|
||||
2010, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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/>. */
|
||||
|
||||
/* Implement the 'r', 'u' and 'A' options for tar. 'A' means that the
|
||||
file names are tar files, and they should simply be appended to the end
|
||||
@@ -47,7 +48,7 @@ char *output_start;
|
||||
static void
|
||||
append_file (char *file_name)
|
||||
{
|
||||
int handle = open (file_name, O_RDONLY | O_BINARY);
|
||||
int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY);
|
||||
struct stat stat_data;
|
||||
|
||||
if (handle < 0)
|
||||
@@ -114,8 +115,8 @@ update_archive (void)
|
||||
|
||||
while (!found_end)
|
||||
{
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
read_header_auto);
|
||||
|
||||
switch (status)
|
||||
@@ -130,6 +131,8 @@ update_archive (void)
|
||||
|
||||
decode_header (current_header, ¤t_stat_info,
|
||||
¤t_format, 0);
|
||||
transform_stat_info (current_header->header.typeflag,
|
||||
¤t_stat_info);
|
||||
archive_format = current_format;
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
@@ -138,26 +141,22 @@ update_archive (void)
|
||||
struct stat s;
|
||||
|
||||
chdir_do (name->change_dir);
|
||||
if (deref_stat (dereference_option,
|
||||
current_stat_info.file_name, &s) == 0)
|
||||
if (deref_stat (current_stat_info.file_name, &s) == 0)
|
||||
{
|
||||
if (S_ISDIR (s.st_mode))
|
||||
{
|
||||
char *p, *dirp;
|
||||
dirp = savedir (name->name);
|
||||
if (!dirp)
|
||||
savedir_error (name->name);
|
||||
else
|
||||
char *p, *dirp = tar_savedir (name->name, 1);
|
||||
if (dirp)
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (name->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);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +166,7 @@ update_archive (void)
|
||||
remname (name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
skip_member ();
|
||||
break;
|
||||
}
|
||||
@@ -187,13 +186,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;
|
||||
|
||||
@@ -217,18 +214,19 @@ update_archive (void)
|
||||
while ((p = name_from_list ()) != NULL)
|
||||
{
|
||||
char *file_name = p->name;
|
||||
if (excluded_name (file_name))
|
||||
if (excluded_name (file_name, NULL))
|
||||
continue;
|
||||
if (interactive_option && !confirm ("add", file_name))
|
||||
continue;
|
||||
if (subcommand_option == CAT_SUBCOMMAND)
|
||||
append_file (file_name);
|
||||
else
|
||||
dump_file (file_name, 1, (dev_t) 0);
|
||||
dump_file (0, file_name, file_name);
|
||||
}
|
||||
}
|
||||
|
||||
write_eot ();
|
||||
close_archive ();
|
||||
finish_deferred_unlinks ();
|
||||
names_notfound ();
|
||||
}
|
||||
|
||||
26
src/utf8.c
26
src/utf8.c
@@ -1,20 +1,22 @@
|
||||
/* Charset handling for GNU tar.
|
||||
|
||||
Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2004, 2006-2007, 2013-2014, 2016-2017 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 <quotearg.h>
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
/* This file is part of GNU tar.
|
||||
/* Warnings for GNU tar.
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
Copyright 2009, 2012-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
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 <argmatch.h>
|
||||
@@ -41,6 +43,11 @@ static char const *const warning_args[] = {
|
||||
"unknown-cast",
|
||||
"unknown-keyword",
|
||||
"xdev",
|
||||
"decompress-program",
|
||||
"existing-file",
|
||||
"xattr-write",
|
||||
"record-size",
|
||||
"failed-read",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -64,7 +71,12 @@ static int warning_types[] = {
|
||||
WARN_TIMESTAMP,
|
||||
WARN_UNKNOWN_CAST,
|
||||
WARN_UNKNOWN_KEYWORD,
|
||||
WARN_XDEV
|
||||
WARN_XDEV,
|
||||
WARN_DECOMPRESS_PROGRAM,
|
||||
WARN_EXISTING_FILE,
|
||||
WARN_XATTR_WRITE,
|
||||
WARN_RECORD_SIZE,
|
||||
WARN_FAILED_READ
|
||||
};
|
||||
|
||||
ARGMATCH_VERIFY (warning_args, warning_types);
|
||||
@@ -76,7 +88,7 @@ set_warning_option (const char *arg)
|
||||
{
|
||||
int negate = 0;
|
||||
int option;
|
||||
|
||||
|
||||
if (strcmp (arg, "none") == 0)
|
||||
{
|
||||
warning_option = 0;
|
||||
@@ -88,11 +100,10 @@ set_warning_option (const char *arg)
|
||||
arg += 3;
|
||||
}
|
||||
|
||||
option = XARGMATCH ("--warning", arg,
|
||||
option = XARGMATCH ("--warning", arg,
|
||||
warning_args, warning_types);
|
||||
if (negate)
|
||||
warning_option &= ~option;
|
||||
else
|
||||
warning_option |= option;
|
||||
}
|
||||
|
||||
|
||||
760
src/xattrs.c
Normal file
760
src/xattrs.c
Normal file
@@ -0,0 +1,760 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014, 2016-2017 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/>.
|
||||
|
||||
Written by James Antill, on 2006-07-27. */
|
||||
|
||||
#include <config.h>
|
||||
#include <system.h>
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "xattr-at.h"
|
||||
#include "selinux-at.h"
|
||||
|
||||
struct xattrs_mask_map
|
||||
{
|
||||
const char **masks;
|
||||
size_t size;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
/* list of fnmatch patterns */
|
||||
static struct
|
||||
{
|
||||
/* lists of fnmatch patterns */
|
||||
struct xattrs_mask_map incl;
|
||||
struct xattrs_mask_map excl;
|
||||
} xattrs_setup;
|
||||
|
||||
/* disable posix acls when problem found in gnulib script m4/acl.m4 */
|
||||
#if ! USE_ACL
|
||||
# undef HAVE_POSIX_ACLS
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACLS
|
||||
# include "acl.h"
|
||||
# include <sys/acl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACLS
|
||||
|
||||
/* acl-at wrappers, TODO: move to gnulib in future? */
|
||||
static acl_t acl_get_file_at (int, const char *, acl_type_t);
|
||||
static int acl_set_file_at (int, const char *, acl_type_t, acl_t);
|
||||
static int file_has_acl_at (int, char const *, struct stat const *);
|
||||
static int acl_delete_def_file_at (int, char const *);
|
||||
|
||||
/* acl_get_file_at */
|
||||
#define AT_FUNC_NAME acl_get_file_at
|
||||
#define AT_FUNC_RESULT acl_t
|
||||
#define AT_FUNC_FAIL (acl_t)NULL
|
||||
#define AT_FUNC_F1 acl_get_file
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type
|
||||
#define AT_FUNC_POST_FILE_ARGS , type
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_FAIL
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* acl_set_file_at */
|
||||
#define AT_FUNC_NAME acl_set_file_at
|
||||
#define AT_FUNC_F1 acl_set_file
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type, acl_t acl
|
||||
#define AT_FUNC_POST_FILE_ARGS , type, acl
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* acl_delete_def_file_at */
|
||||
#define AT_FUNC_NAME acl_delete_def_file_at
|
||||
#define AT_FUNC_F1 acl_delete_def_file
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#define AT_FUNC_POST_FILE_ARGS
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* gnulib file_has_acl_at */
|
||||
#define AT_FUNC_NAME file_has_acl_at
|
||||
#define AT_FUNC_F1 file_has_acl
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat const *st
|
||||
#define AT_FUNC_POST_FILE_ARGS , st
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* convert unix permissions into an ACL ... needed due to "default" ACLs */
|
||||
static acl_t
|
||||
perms2acl (int perms)
|
||||
{
|
||||
char val[] = "user::---,group::---,other::---";
|
||||
/* 0123456789 123456789 123456789 123456789 */
|
||||
|
||||
/* user */
|
||||
if (perms & 0400)
|
||||
val[6] = 'r';
|
||||
if (perms & 0200)
|
||||
val[7] = 'w';
|
||||
if (perms & 0100)
|
||||
val[8] = 'x';
|
||||
|
||||
/* group */
|
||||
if (perms & 0040)
|
||||
val[17] = 'r';
|
||||
if (perms & 0020)
|
||||
val[18] = 'w';
|
||||
if (perms & 0010)
|
||||
val[19] = 'x';
|
||||
|
||||
/* other */
|
||||
if (perms & 0004)
|
||||
val[28] = 'r';
|
||||
if (perms & 0002)
|
||||
val[29] = 'w';
|
||||
if (perms & 0001)
|
||||
val[30] = 'x';
|
||||
|
||||
return acl_from_text (val);
|
||||
}
|
||||
|
||||
static char *
|
||||
skip_to_ext_fields (char *ptr)
|
||||
{
|
||||
/* skip tag name (user/group/default/mask) */
|
||||
ptr += strcspn (ptr, ":,\n");
|
||||
|
||||
if (*ptr != ':')
|
||||
return ptr;
|
||||
++ptr;
|
||||
|
||||
ptr += strcspn (ptr, ":,\n"); /* skip user/group name */
|
||||
|
||||
if (*ptr != ':')
|
||||
return ptr;
|
||||
++ptr;
|
||||
|
||||
ptr += strcspn (ptr, ":,\n"); /* skip perms */
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* The POSIX draft allows extra fields after the three main ones. Star
|
||||
uses this to add a fourth field for user/group which is the numeric ID.
|
||||
This function removes such extra fields by overwriting them with the
|
||||
characters that follow. */
|
||||
static char *
|
||||
fixup_extra_acl_fields (char *ptr)
|
||||
{
|
||||
char *src = ptr;
|
||||
char *dst = ptr;
|
||||
|
||||
while (*src)
|
||||
{
|
||||
const char *old = src;
|
||||
size_t len = 0;
|
||||
|
||||
src = skip_to_ext_fields (src);
|
||||
len = src - old;
|
||||
if (old != dst)
|
||||
memmove (dst, old, len);
|
||||
dst += len;
|
||||
|
||||
if (*src == ':') /* We have extra fields, skip them all */
|
||||
src += strcspn (src, "\n,");
|
||||
|
||||
if ((*src == '\n') || (*src == ','))
|
||||
*dst++ = *src++; /* also done when dst == src, but that's ok */
|
||||
}
|
||||
if (src != dst)
|
||||
*dst = 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Set the "system.posix_acl_access/system.posix_acl_default" extended
|
||||
attribute. Called only when acls_option > 0. */
|
||||
static void
|
||||
xattrs__acls_set (struct tar_stat_info const *st,
|
||||
char const *file_name, int type,
|
||||
char *ptr, size_t len, bool def)
|
||||
{
|
||||
acl_t acl;
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
/* assert (strlen (ptr) == len); */
|
||||
ptr = fixup_extra_acl_fields (ptr);
|
||||
acl = acl_from_text (ptr);
|
||||
}
|
||||
else if (def)
|
||||
{
|
||||
/* No "default" IEEE 1003.1e ACL set for directory. At this moment,
|
||||
FILE_NAME may already have inherited default acls from parent
|
||||
directory; clean them up. */
|
||||
if (acl_delete_def_file_at (chdir_fd, file_name))
|
||||
WARNOPT (WARN_XATTR_WRITE,
|
||||
(0, errno,
|
||||
_("acl_delete_def_file_at: Cannot drop default POSIX ACLs "
|
||||
"for file '%s'"),
|
||||
file_name));
|
||||
return;
|
||||
}
|
||||
else
|
||||
acl = perms2acl (st->stat.st_mode);
|
||||
|
||||
if (!acl)
|
||||
{
|
||||
call_arg_warn ("acl_from_text", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (acl_set_file_at (chdir_fd, file_name, type, acl) == -1)
|
||||
/* warn even if filesystem does not support acls */
|
||||
WARNOPT (WARN_XATTR_WRITE,
|
||||
(0, errno,
|
||||
_ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"),
|
||||
file_name));
|
||||
|
||||
acl_free (acl);
|
||||
}
|
||||
|
||||
static void
|
||||
xattrs__acls_get_a (int parentfd, const char *file_name,
|
||||
struct tar_stat_info *st,
|
||||
char **ret_ptr, size_t * ret_len)
|
||||
{
|
||||
char *val = NULL;
|
||||
ssize_t len;
|
||||
acl_t acl;
|
||||
|
||||
if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_ACCESS)))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* "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);
|
||||
}
|
||||
#endif /* HAVE_POSIX_ACLS */
|
||||
|
||||
static void
|
||||
acls_one_line (const char *prefix, char delim,
|
||||
const char *aclstring, size_t len)
|
||||
{
|
||||
/* support both long and short text representation of posix acls */
|
||||
struct obstack stk;
|
||||
int pref_len = strlen (prefix);
|
||||
const char *oldstring = aclstring;
|
||||
int pos = 0;
|
||||
|
||||
if (!aclstring || !len)
|
||||
return;
|
||||
|
||||
obstack_init (&stk);
|
||||
while (pos <= len)
|
||||
{
|
||||
int move = strcspn (aclstring, ",\n");
|
||||
if (!move)
|
||||
break;
|
||||
|
||||
if (oldstring != aclstring)
|
||||
obstack_1grow (&stk, delim);
|
||||
|
||||
obstack_grow (&stk, prefix, pref_len);
|
||||
obstack_grow (&stk, aclstring, move);
|
||||
|
||||
aclstring += move + 1;
|
||||
}
|
||||
|
||||
obstack_1grow (&stk, '\0');
|
||||
|
||||
fprintf (stdlis, "%s", (char *) obstack_finish (&stk));
|
||||
|
||||
obstack_free (&stk, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_acls_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd, int xisfile)
|
||||
{
|
||||
if (acls_option > 0)
|
||||
{
|
||||
#ifndef HAVE_POSIX_ACLS
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
WARN ((0, 0, _("POSIX ACL support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
int err = file_has_acl_at (parentfd, file_name, &st->stat);
|
||||
if (err == 0)
|
||||
return;
|
||||
if (err == -1)
|
||||
{
|
||||
call_arg_warn ("file_has_acl_at", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
xattrs__acls_get_a (parentfd, file_name, st,
|
||||
&st->acls_a_ptr, &st->acls_a_len);
|
||||
if (!xisfile)
|
||||
xattrs__acls_get_d (parentfd, file_name, st,
|
||||
&st->acls_d_ptr, &st->acls_d_len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_acls_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag)
|
||||
{
|
||||
if (acls_option > 0 && typeflag != SYMTYPE)
|
||||
{
|
||||
#ifndef HAVE_POSIX_ACLS
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
WARN ((0, 0, _("POSIX ACL support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
|
||||
st->acls_a_ptr, st->acls_a_len, 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);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mask_map_realloc (struct xattrs_mask_map *map)
|
||||
{
|
||||
if (map->used == map->size)
|
||||
{
|
||||
if (map->size == 0)
|
||||
map->size = 4;
|
||||
map->masks = x2nrealloc (map->masks, &map->size, sizeof (map->masks[0]));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_mask_add (const char *mask, bool incl)
|
||||
{
|
||||
struct xattrs_mask_map *mask_map =
|
||||
incl ? &xattrs_setup.incl : &xattrs_setup.excl;
|
||||
/* ensure there is enough space */
|
||||
mask_map_realloc (mask_map);
|
||||
/* just assign pointers -- we silently expect that pointer "mask" is valid
|
||||
through the whole program (pointer to argv array) */
|
||||
mask_map->masks[mask_map->used++] = mask;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_mask_map (struct xattrs_mask_map *mask_map)
|
||||
{
|
||||
if (mask_map->size)
|
||||
free (mask_map->masks);
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_clear_setup (void)
|
||||
{
|
||||
clear_mask_map (&xattrs_setup.incl);
|
||||
clear_mask_map (&xattrs_setup.excl);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (xattrs_option > 0)
|
||||
{
|
||||
#ifndef HAVE_XATTRS
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
WARN ((0, 0, _("XATTR support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
static size_t xsz = 1024;
|
||||
static char *xatrs = NULL;
|
||||
ssize_t xret = -1;
|
||||
|
||||
if (!xatrs)
|
||||
xatrs = x2nrealloc (xatrs, &xsz, 1);
|
||||
|
||||
while (((fd == 0) ?
|
||||
((xret =
|
||||
llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) :
|
||||
((xret = flistxattr (fd, xatrs, xsz)) == -1))
|
||||
&& (errno == ERANGE))
|
||||
{
|
||||
xatrs = x2nrealloc (xatrs, &xsz, 1);
|
||||
}
|
||||
|
||||
if (xret == -1)
|
||||
call_arg_warn ((fd == 0) ? "llistxattrat" : "flistxattr", file_name);
|
||||
else
|
||||
{
|
||||
const char *attr = xatrs;
|
||||
static size_t asz = 1024;
|
||||
static char *val = NULL;
|
||||
|
||||
if (!val)
|
||||
val = x2nrealloc (val, &asz, 1);
|
||||
|
||||
while (xret > 0)
|
||||
{
|
||||
size_t len = strlen (attr);
|
||||
ssize_t aret = 0;
|
||||
|
||||
while (((fd == 0)
|
||||
? ((aret = lgetxattrat (parentfd, file_name, attr,
|
||||
val, asz)) == -1)
|
||||
: ((aret = fgetxattr (fd, attr, val, asz)) == -1))
|
||||
&& (errno == ERANGE))
|
||||
{
|
||||
val = x2nrealloc (val, &asz, 1);
|
||||
}
|
||||
|
||||
if (aret != -1)
|
||||
{
|
||||
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);
|
||||
|
||||
attr += len + 1;
|
||||
xret -= len + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
static void
|
||||
xattrs__fd_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag,
|
||||
const char *attr, const char *ptr, size_t len)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
const char *sysname = "setxattrat";
|
||||
int ret = -1;
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
ret = setxattrat (chdir_fd, file_name, attr, ptr, len, 0);
|
||||
else
|
||||
{
|
||||
sysname = "lsetxattr";
|
||||
ret = lsetxattrat (chdir_fd, file_name, attr, ptr, len, 0);
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
WARNOPT (WARN_XATTR_WRITE,
|
||||
(0, errno,
|
||||
_("%s: Cannot set '%s' extended attribute for file '%s'"),
|
||||
sysname, attr, file_name));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* lgetfileconat is called against FILE_NAME iff the FD parameter is set to
|
||||
zero, otherwise the fgetfileconat is used against correct file descriptor */
|
||||
void
|
||||
xattrs_selinux_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd)
|
||||
{
|
||||
if (selinux_context_option > 0)
|
||||
{
|
||||
#if HAVE_SELINUX_SELINUX_H != 1
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
WARN ((0, 0, _("SELinux support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
int result = fd ?
|
||||
fgetfilecon (fd, &st->cntx_name)
|
||||
: lgetfileconat (parentfd, file_name, &st->cntx_name);
|
||||
|
||||
if (result == -1 && errno != ENODATA && errno != ENOTSUP)
|
||||
call_arg_warn (fd ? "fgetfilecon" : "lgetfileconat", file_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_selinux_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag)
|
||||
{
|
||||
if (selinux_context_option > 0)
|
||||
{
|
||||
#if HAVE_SELINUX_SELINUX_H != 1
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
WARN ((0, 0, _("SELinux support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
const char *sysname = "setfilecon";
|
||||
int ret;
|
||||
|
||||
if (!st->cntx_name)
|
||||
return;
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
{
|
||||
ret = setfileconat (chdir_fd, file_name, st->cntx_name);
|
||||
sysname = "setfileconat";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = lsetfileconat (chdir_fd, file_name, st->cntx_name);
|
||||
sysname = "lsetfileconat";
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
WARNOPT (WARN_XATTR_WRITE,
|
||||
(0, errno,
|
||||
_("%s: Cannot set SELinux context for file '%s'"),
|
||||
sysname, file_name));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mm->size)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < mm->used; i++)
|
||||
if (fnmatch (mm->masks[i], kw, 0) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define USER_DOT_PFX "user."
|
||||
|
||||
static bool
|
||||
xattrs_kw_included (const char *kw, bool archiving)
|
||||
{
|
||||
if (xattrs_setup.incl.size)
|
||||
return xattrs_matches_mask (kw, &xattrs_setup.incl);
|
||||
else if (archiving)
|
||||
return true;
|
||||
else
|
||||
return strncmp (kw, USER_DOT_PFX, sizeof (USER_DOT_PFX) - 1) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
xattrs_kw_excluded (const char *kw, bool archiving)
|
||||
{
|
||||
return xattrs_setup.excl.size ?
|
||||
xattrs_matches_mask (kw, &xattrs_setup.excl) : false;
|
||||
}
|
||||
|
||||
/* Check whether the xattr with keyword KW should be discarded from list of
|
||||
attributes that are going to be archived/excluded (set ARCHIVING=true for
|
||||
archiving, false for excluding) */
|
||||
static bool
|
||||
xattrs_masked_out (const char *kw, bool archiving)
|
||||
{
|
||||
return xattrs_kw_included (kw, archiving) ?
|
||||
xattrs_kw_excluded (kw, archiving) : true;
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_xattrs_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag, int later_run)
|
||||
{
|
||||
if (xattrs_option > 0)
|
||||
{
|
||||
#ifndef HAVE_XATTRS
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
WARN ((0, 0, _("XATTR support is not available")));
|
||||
done = 1;
|
||||
#else
|
||||
size_t scan = 0;
|
||||
|
||||
if (!st->xattr_map_size)
|
||||
return;
|
||||
|
||||
for (; scan < st->xattr_map_size; ++scan)
|
||||
{
|
||||
char *keyword = st->xattr_map[scan].xkey;
|
||||
keyword += strlen ("SCHILY.xattr.");
|
||||
|
||||
/* TODO: this 'later_run' workaround is temporary solution -> once
|
||||
capabilities should become fully supported by it's API and there
|
||||
should exist something like xattrs_capabilities_set() call.
|
||||
For a regular files: all extended attributes are restored during
|
||||
the first run except 'security.capability' which is restored in
|
||||
'later_run == 1'. */
|
||||
if (typeflag == REGTYPE
|
||||
&& later_run == !!strcmp (keyword, "security.capability"))
|
||||
continue;
|
||||
|
||||
if (xattrs_masked_out (keyword, false /* extracting */ ))
|
||||
/* 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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_print_char (struct tar_stat_info const *st, char *output)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (verbose_option < 2)
|
||||
{
|
||||
*output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (xattrs_option > 0 || selinux_context_option > 0 || acls_option > 0)
|
||||
{
|
||||
/* placeholders */
|
||||
*output = ' ';
|
||||
output[1] = 0;
|
||||
}
|
||||
|
||||
if (xattrs_option > 0 && st->xattr_map_size)
|
||||
for (i = 0; i < st->xattr_map_size; ++i)
|
||||
{
|
||||
char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr.");
|
||||
if (!xattrs_masked_out (keyword, false /* like extracting */ ))
|
||||
{
|
||||
*output = '*';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selinux_context_option > 0 && st->cntx_name)
|
||||
*output = '.';
|
||||
|
||||
if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
|
||||
*output = '+';
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_print (struct tar_stat_info const *st)
|
||||
{
|
||||
if (verbose_option < 3)
|
||||
return;
|
||||
|
||||
/* selinux */
|
||||
if (selinux_context_option > 0 && st->cntx_name)
|
||||
fprintf (stdlis, " s: %s\n", st->cntx_name);
|
||||
|
||||
/* acls */
|
||||
if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
|
||||
{
|
||||
fprintf (stdlis, " a: ");
|
||||
acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len);
|
||||
acls_one_line ("default:", ',', st->acls_d_ptr, st->acls_d_len);
|
||||
fprintf (stdlis, "\n");
|
||||
}
|
||||
|
||||
/* xattrs */
|
||||
if (xattrs_option > 0 && st->xattr_map_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < st->xattr_map_size; ++i)
|
||||
{
|
||||
char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr.");
|
||||
if (!xattrs_masked_out (keyword, false /* like extracting */ ))
|
||||
fprintf (stdlis, " x: %lu %s\n",
|
||||
(unsigned long) st->xattr_map[i].xval_len, keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/xattrs.h
Normal file
50
src/xattrs.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014, 2016-2017 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/>.
|
||||
|
||||
Written by James Antill, on 2006-07-27. */
|
||||
|
||||
#ifndef GUARD_XATTTRS_H
|
||||
#define GUARD_XATTTRS_H
|
||||
|
||||
/* Add include/exclude fnmatch pattern for xattr key domain. Set INCL parameter
|
||||
to true/false if you want to add include/exclude pattern */
|
||||
extern void xattrs_mask_add (const char *mask, bool incl);
|
||||
|
||||
/* clear helping structures when tar finishes */
|
||||
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);
|
||||
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,
|
||||
struct tar_stat_info *st, int fd);
|
||||
|
||||
extern void xattrs_acls_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag);
|
||||
extern void xattrs_selinux_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag);
|
||||
extern void xattrs_xattrs_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag,
|
||||
int later_run);
|
||||
|
||||
extern void xattrs_print_char (struct tar_stat_info const *st, char *output);
|
||||
extern void xattrs_print (struct tar_stat_info const *st);
|
||||
|
||||
#endif /* GUARD_XATTTRS_H */
|
||||
678
src/xheader.c
678
src/xheader.c
@@ -1,21 +1,22 @@
|
||||
/* POSIX extended headers for tar.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright (C) 2003-2007, 2009-2010, 2012-2014, 2016-2017 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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>
|
||||
|
||||
@@ -26,6 +27,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void xheader_init (struct xheader *xhdr);
|
||||
static bool xheader_protected_pattern_p (char const *pattern);
|
||||
static bool xheader_protected_keyword_p (char const *keyword);
|
||||
static void xheader_set_single_keyword (char *) __attribute__ ((noreturn));
|
||||
@@ -85,10 +87,10 @@ struct keyword_list
|
||||
/* List of keyword patterns set by delete= option */
|
||||
static struct keyword_list *keyword_pattern_list;
|
||||
|
||||
/* List of keyword/value pairs set by `keyword=value' option */
|
||||
/* List of keyword/value pairs set by 'keyword=value' option */
|
||||
static struct keyword_list *keyword_global_override_list;
|
||||
|
||||
/* List of keyword/value pairs set by `keyword:=value' option */
|
||||
/* List of keyword/value pairs set by 'keyword:=value' option */
|
||||
static struct keyword_list *keyword_override_list;
|
||||
|
||||
/* List of keyword/value pairs decoded from the last 'g' type header */
|
||||
@@ -166,14 +168,13 @@ xheader_set_single_keyword (char *kw)
|
||||
static void
|
||||
assign_time_option (char **sval, time_t *tval, const char *input)
|
||||
{
|
||||
uintmax_t u;
|
||||
char *p;
|
||||
time_t t = u = strtoumax (input, &p, 10);
|
||||
if (t != u || *p || errno == ERANGE)
|
||||
struct timespec t = decode_timespec (input, &p, false);
|
||||
if (! valid_timespec (t) || *p)
|
||||
ERROR ((0, 0, _("Time stamp is out of allowed range")));
|
||||
else
|
||||
{
|
||||
*tval = t;
|
||||
*tval = t.tv_sec;
|
||||
assign_string (sval, input);
|
||||
}
|
||||
}
|
||||
@@ -261,7 +262,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
|
||||
char *dir = NULL;
|
||||
char *base = NULL;
|
||||
char pidbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char const *pptr;
|
||||
char const *pptr = NULL;
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char const *nptr = NULL;
|
||||
|
||||
@@ -334,13 +335,10 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (nptr)
|
||||
{
|
||||
q = stpcpy (q, nptr);
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
/* else fall through */
|
||||
q = stpcpy (q, nptr);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
*q++ = *p++;
|
||||
@@ -452,13 +450,131 @@ xheader_write_global (struct xheader *xhdr)
|
||||
if (xhdr->stk)
|
||||
{
|
||||
char *name;
|
||||
|
||||
|
||||
xheader_finish (xhdr);
|
||||
xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
|
||||
name = xheader_ghdr_name ();
|
||||
xheader_write (XGLTYPE, name, start_time.tv_sec, xhdr);
|
||||
free (name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xheader_xattr_init (struct tar_stat_info *st)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* This is reversal function for xattr_encode_keyword. See comment for
|
||||
xattr_encode_keyword() for more info. */
|
||||
static void
|
||||
xattr_decode_keyword (char *keyword)
|
||||
{
|
||||
char *kpr, *kpl; /* keyword pointer left/right */
|
||||
kpr = kpl = keyword;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*kpr == '%')
|
||||
{
|
||||
if (kpr[1] == '3' && kpr[2] == 'D')
|
||||
{
|
||||
*kpl = '=';
|
||||
kpr += 3;
|
||||
kpl ++;
|
||||
continue;
|
||||
}
|
||||
else if (kpr[1] == '2' && kpr[2] == '5')
|
||||
{
|
||||
*kpl = '%';
|
||||
kpr += 3;
|
||||
kpl ++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
*kpl = *kpr;
|
||||
|
||||
if (*kpr == 0)
|
||||
break;
|
||||
|
||||
kpr++;
|
||||
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 */
|
||||
|
||||
@@ -472,6 +588,7 @@ struct xhdr_tab
|
||||
struct xheader *, void const *data);
|
||||
void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
|
||||
int flags;
|
||||
bool prefix; /* select handler comparing prefix only */
|
||||
};
|
||||
|
||||
/* This declaration must be extern, because ISO C99 section 6.9.2
|
||||
@@ -488,8 +605,17 @@ locate_handler (char const *keyword)
|
||||
struct xhdr_tab const *p;
|
||||
|
||||
for (p = xhdr_tab; p->keyword; p++)
|
||||
if (strcmp (p->keyword, keyword) == 0)
|
||||
return p;
|
||||
if (p->prefix)
|
||||
{
|
||||
if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0)
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp (p->keyword, keyword) == 0)
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -499,7 +625,8 @@ xheader_protected_pattern_p (const char *pattern)
|
||||
struct xhdr_tab const *p;
|
||||
|
||||
for (p = xhdr_tab; p->keyword; p++)
|
||||
if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
|
||||
if (!p->prefix && (p->flags & XHDR_PROTECTED)
|
||||
&& fnmatch (pattern, p->keyword, 0) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -510,7 +637,8 @@ xheader_protected_keyword_p (const char *keyword)
|
||||
struct xhdr_tab const *p;
|
||||
|
||||
for (p = xhdr_tab; p->keyword; p++)
|
||||
if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
|
||||
if (!p->prefix && (p->flags & XHDR_PROTECTED)
|
||||
&& strcmp (p->keyword, keyword) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -525,7 +653,6 @@ decode_record (struct xheader *xhdr,
|
||||
{
|
||||
char *start = *ptr;
|
||||
char *p = start;
|
||||
uintmax_t u;
|
||||
size_t len;
|
||||
char *len_lim;
|
||||
char const *keyword;
|
||||
@@ -542,13 +669,7 @@ decode_record (struct xheader *xhdr,
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
len = u = strtoumax (p, &len_lim, 10);
|
||||
if (len != u || errno == ERANGE)
|
||||
{
|
||||
ERROR ((0, 0, _("Extended header length is out of allowed range")));
|
||||
return false;
|
||||
}
|
||||
len = strtoumax (p, &len_lim, 10);
|
||||
|
||||
if (len_max < len)
|
||||
{
|
||||
@@ -617,7 +738,7 @@ decx (void *data, char const *keyword, char const *value, size_t size)
|
||||
t->decoder (st, keyword, value, size);
|
||||
else
|
||||
WARNOPT (WARN_UNKNOWN_KEYWORD,
|
||||
(0, 0, _("Ignoring unknown extended header keyword `%s'"),
|
||||
(0, 0, _("Ignoring unknown extended header keyword '%s'"),
|
||||
keyword));
|
||||
}
|
||||
|
||||
@@ -634,6 +755,16 @@ 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
|
||||
@@ -661,7 +792,7 @@ xheader_decode_global (struct xheader *xhdr)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
xheader_init (struct xheader *xhdr)
|
||||
{
|
||||
if (!xhdr->stk)
|
||||
@@ -682,18 +813,24 @@ 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
|
||||
xheader_read (struct xheader *xhdr, union block *p, size_t size)
|
||||
xheader_read (struct xheader *xhdr, union block *p, off_t size)
|
||||
{
|
||||
size_t j = 0;
|
||||
|
||||
if (size < 0)
|
||||
size = 0; /* Already diagnosed. */
|
||||
|
||||
if (SIZE_MAX - BLOCKSIZE <= size)
|
||||
xalloc_die ();
|
||||
|
||||
size += BLOCKSIZE;
|
||||
xhdr->size = size;
|
||||
xhdr->buffer = xmalloc (size + 1);
|
||||
@@ -708,7 +845,7 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size)
|
||||
|
||||
if (!p)
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
|
||||
|
||||
memcpy (&xhdr->buffer[j], p->buffer, len);
|
||||
set_next_block_after (p);
|
||||
|
||||
@@ -720,15 +857,71 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size)
|
||||
while (size > 0);
|
||||
}
|
||||
|
||||
/* xattr_encode_keyword() substitutes '=' ~~> '%3D' and '%' ~~> '%25'
|
||||
in extended attribute keywords. This is needed because the '=' character
|
||||
has special purpose in extended attribute header - it splits keyword and
|
||||
value part of header. If there was the '=' occurrence allowed inside
|
||||
keyword, there would be no unambiguous way how to decode this extended
|
||||
attribute.
|
||||
|
||||
(http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html)
|
||||
*/
|
||||
static char *
|
||||
xattr_encode_keyword(const char *keyword)
|
||||
{
|
||||
static char *encode_buffer = NULL;
|
||||
static size_t encode_buffer_size = 0;
|
||||
size_t bp; /* keyword/buffer pointers */
|
||||
|
||||
if (!encode_buffer)
|
||||
{
|
||||
encode_buffer_size = 256;
|
||||
encode_buffer = xmalloc (encode_buffer_size);
|
||||
}
|
||||
else
|
||||
*encode_buffer = 0;
|
||||
|
||||
for (bp = 0; *keyword != 0; ++bp, ++keyword)
|
||||
{
|
||||
char c = *keyword;
|
||||
|
||||
if (bp + 2 /* enough for URL encoding also.. */ >= encode_buffer_size)
|
||||
{
|
||||
encode_buffer = x2realloc (encode_buffer, &encode_buffer_size);
|
||||
}
|
||||
|
||||
if (c == '%')
|
||||
{
|
||||
strcpy (encode_buffer + bp, "%25");
|
||||
bp += 2;
|
||||
}
|
||||
else if (c == '=')
|
||||
{
|
||||
strcpy (encode_buffer + bp, "%3D");
|
||||
bp += 2;
|
||||
}
|
||||
else
|
||||
encode_buffer[bp] = c;
|
||||
}
|
||||
|
||||
encode_buffer[bp] = 0;
|
||||
|
||||
return encode_buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
xheader_print_n (struct xheader *xhdr, char const *keyword,
|
||||
char const *value, size_t vsize)
|
||||
{
|
||||
size_t len = strlen (keyword) + vsize + 3; /* ' ' + '=' + '\n' */
|
||||
size_t p;
|
||||
size_t n = 0;
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char const *np;
|
||||
size_t len, klen;
|
||||
|
||||
keyword = xattr_encode_keyword (keyword);
|
||||
klen = strlen (keyword);
|
||||
len = klen + vsize + 3; /* ' ' + '=' + '\n' */
|
||||
|
||||
do
|
||||
{
|
||||
@@ -740,7 +933,7 @@ xheader_print_n (struct xheader *xhdr, char const *keyword,
|
||||
|
||||
x_obstack_grow (xhdr, np, n);
|
||||
x_obstack_1grow (xhdr, ' ');
|
||||
x_obstack_grow (xhdr, keyword, strlen (keyword));
|
||||
x_obstack_grow (xhdr, keyword, klen);
|
||||
x_obstack_1grow (xhdr, '=');
|
||||
x_obstack_grow (xhdr, value, vsize);
|
||||
x_obstack_1grow (xhdr, '\n');
|
||||
@@ -834,7 +1027,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++ = ' ';
|
||||
@@ -848,14 +1041,12 @@ xheader_string_end (struct xheader *xhdr, char const *keyword)
|
||||
|
||||
static void
|
||||
out_of_range_header (char const *keyword, char const *value,
|
||||
uintmax_t minus_minval, uintmax_t maxval)
|
||||
intmax_t minval, uintmax_t maxval)
|
||||
{
|
||||
char minval_buf[UINTMAX_STRSIZE_BOUND + 1];
|
||||
char minval_buf[INT_BUFSIZE_BOUND (intmax_t)];
|
||||
char maxval_buf[UINTMAX_STRSIZE_BOUND];
|
||||
char *minval_string = umaxtostr (minus_minval, minval_buf + 1);
|
||||
char *minval_string = imaxtostr (minval, minval_buf);
|
||||
char *maxval_string = umaxtostr (maxval, maxval_buf);
|
||||
if (minus_minval)
|
||||
*--minval_string = '-';
|
||||
|
||||
/* TRANSLATORS: The first %s is the pax extended header keyword
|
||||
(atime, gid, etc.). */
|
||||
@@ -898,140 +1089,74 @@ code_time (struct timespec t, char const *keyword, struct xheader *xhdr)
|
||||
xheader_print (xhdr, keyword, code_timespec (t, buf));
|
||||
}
|
||||
|
||||
enum decode_time_status
|
||||
{
|
||||
decode_time_success,
|
||||
decode_time_range,
|
||||
decode_time_bad_header
|
||||
};
|
||||
|
||||
static enum decode_time_status
|
||||
_decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
{
|
||||
time_t s;
|
||||
unsigned long int ns = 0;
|
||||
char *p;
|
||||
char *arg_lim;
|
||||
bool negative = *arg == '-';
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (ISDIGIT (arg[negative]))
|
||||
{
|
||||
if (negative)
|
||||
{
|
||||
intmax_t i = strtoimax (arg, &arg_lim, 10);
|
||||
if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
|
||||
return decode_time_range;
|
||||
s = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
uintmax_t i = strtoumax (arg, &arg_lim, 10);
|
||||
if (TYPE_MAXIMUM (time_t) < i)
|
||||
return decode_time_range;
|
||||
s = i;
|
||||
}
|
||||
|
||||
p = arg_lim;
|
||||
|
||||
if (errno == ERANGE)
|
||||
return decode_time_range;
|
||||
|
||||
if (*p == '.')
|
||||
{
|
||||
int digits = 0;
|
||||
bool trailing_nonzero = false;
|
||||
|
||||
while (ISDIGIT (*++p))
|
||||
if (digits < LOG10_BILLION)
|
||||
{
|
||||
ns = 10 * ns + (*p - '0');
|
||||
digits++;
|
||||
}
|
||||
else
|
||||
trailing_nonzero |= *p != '0';
|
||||
|
||||
while (digits++ < LOG10_BILLION)
|
||||
ns *= 10;
|
||||
|
||||
if (negative)
|
||||
{
|
||||
/* Convert "-1.10000000000001" to s == -2, ns == 89999999.
|
||||
I.e., truncate time stamps towards minus infinity while
|
||||
converting them to internal form. */
|
||||
ns += trailing_nonzero;
|
||||
if (ns != 0)
|
||||
{
|
||||
if (s == TYPE_MINIMUM (time_t))
|
||||
return decode_time_range;
|
||||
s--;
|
||||
ns = BILLION - ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! *p)
|
||||
{
|
||||
ts->tv_sec = s;
|
||||
ts->tv_nsec = ns;
|
||||
return decode_time_success;
|
||||
}
|
||||
}
|
||||
|
||||
return decode_time_bad_header;
|
||||
}
|
||||
|
||||
static bool
|
||||
decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
{
|
||||
switch (_decode_time (ts, arg, keyword))
|
||||
char *arg_lim;
|
||||
struct timespec t = decode_timespec (arg, &arg_lim, true);
|
||||
|
||||
if (! valid_timespec (t))
|
||||
{
|
||||
case decode_time_success:
|
||||
return true;
|
||||
case decode_time_bad_header:
|
||||
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
|
||||
keyword, arg));
|
||||
return false;
|
||||
case decode_time_range:
|
||||
out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
|
||||
TYPE_MAXIMUM (time_t));
|
||||
if (arg < arg_lim && !*arg_lim)
|
||||
out_of_range_header (keyword, arg, TYPE_MINIMUM (time_t),
|
||||
TYPE_MAXIMUM (time_t));
|
||||
else
|
||||
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
|
||||
keyword, arg));
|
||||
return false;
|
||||
}
|
||||
|
||||
*ts = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
code_signed_num (uintmax_t value, char const *keyword,
|
||||
intmax_t minval, uintmax_t maxval, struct xheader *xhdr)
|
||||
{
|
||||
char sbuf[SYSINT_BUFSIZE];
|
||||
xheader_print (xhdr, keyword, sysinttostr (value, minval, maxval, sbuf));
|
||||
}
|
||||
|
||||
static void
|
||||
code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
|
||||
{
|
||||
char sbuf[UINTMAX_STRSIZE_BOUND];
|
||||
xheader_print (xhdr, keyword, umaxtostr (value, sbuf));
|
||||
code_signed_num (value, keyword, 0, UINTMAX_MAX, xhdr);
|
||||
}
|
||||
|
||||
static bool
|
||||
decode_signed_num (intmax_t *num, char const *arg,
|
||||
intmax_t minval, uintmax_t maxval,
|
||||
char const *keyword)
|
||||
{
|
||||
char *arg_lim;
|
||||
intmax_t u = strtosysint (arg, &arg_lim, minval, maxval);
|
||||
|
||||
if (errno == EINVAL || *arg_lim)
|
||||
{
|
||||
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
|
||||
keyword, arg));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
out_of_range_header (keyword, arg, minval, maxval);
|
||||
return false;
|
||||
}
|
||||
|
||||
*num = u;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
|
||||
char const *keyword)
|
||||
{
|
||||
uintmax_t u;
|
||||
char *arg_lim;
|
||||
|
||||
if (! (ISDIGIT (*arg)
|
||||
&& (errno = 0, u = strtoumax (arg, &arg_lim, 10), !*arg_lim)))
|
||||
{
|
||||
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
|
||||
keyword, arg));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! (u <= maxval && errno != ERANGE))
|
||||
{
|
||||
out_of_range_header (keyword, arg, 0, maxval);
|
||||
return false;
|
||||
}
|
||||
|
||||
*num = u;
|
||||
intmax_t i;
|
||||
if (! decode_signed_num (&i, arg, 0, maxval, keyword))
|
||||
return false;
|
||||
*num = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1073,7 +1198,8 @@ static void
|
||||
gid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
{
|
||||
code_num (st->stat.st_gid, keyword, xhdr);
|
||||
code_signed_num (st->stat.st_gid, keyword,
|
||||
TYPE_MINIMUM (gid_t), TYPE_MAXIMUM (gid_t), xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1082,8 +1208,9 @@ gid_decoder (struct tar_stat_info *st,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), keyword))
|
||||
intmax_t u;
|
||||
if (decode_signed_num (&u, arg, TYPE_MINIMUM (gid_t),
|
||||
TYPE_MAXIMUM (gid_t), keyword))
|
||||
st->stat.st_gid = u;
|
||||
}
|
||||
|
||||
@@ -1163,15 +1290,33 @@ path_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
code_string (st->file_name, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
raw_path_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
decode_string (&st->orig_file_name, arg);
|
||||
decode_string (&st->file_name, arg);
|
||||
st->had_trailing_slash = strip_trailing_slashes (st->file_name);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&st->orig_file_name, arg);
|
||||
decode_string (&st->file_name, arg);
|
||||
st->had_trailing_slash = strip_trailing_slashes (st->file_name);
|
||||
if (! st->sparse_name_done)
|
||||
raw_path_decoder (st, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
st->sparse_name_done = true;
|
||||
raw_path_decoder (st, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1196,7 +1341,8 @@ static void
|
||||
uid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
{
|
||||
code_num (st->stat.st_uid, keyword, xhdr);
|
||||
code_signed_num (st->stat.st_uid, keyword,
|
||||
TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t), xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1205,8 +1351,9 @@ uid_decoder (struct tar_stat_info *st,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), keyword))
|
||||
intmax_t u;
|
||||
if (decode_signed_num (&u, arg, TYPE_MINIMUM (uid_t),
|
||||
TYPE_MAXIMUM (uid_t), keyword))
|
||||
st->stat.st_uid = u;
|
||||
}
|
||||
|
||||
@@ -1241,7 +1388,10 @@ sparse_size_decoder (struct tar_stat_info *st,
|
||||
{
|
||||
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
|
||||
@@ -1307,7 +1457,7 @@ sparse_numbytes_decoder (struct tar_stat_info *st,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, SIZE_MAX, keyword))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
{
|
||||
if (st->sparse_map_avail < st->sparse_map_size)
|
||||
st->sparse_map[st->sparse_map_avail++].numbytes = u;
|
||||
@@ -1324,13 +1474,13 @@ sparse_map_decoder (struct tar_stat_info *st,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
int offset = 1;
|
||||
struct sp_array e;
|
||||
|
||||
st->sparse_map_avail = 0;
|
||||
while (1)
|
||||
{
|
||||
uintmax_t u;
|
||||
intmax_t u;
|
||||
char *delim;
|
||||
struct sp_array e;
|
||||
|
||||
if (!ISDIGIT (*arg))
|
||||
{
|
||||
@@ -1340,11 +1490,16 @@ sparse_map_decoder (struct tar_stat_info *st,
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
u = strtoumax (arg, &delim, 10);
|
||||
u = strtoimax (arg, &delim, 10);
|
||||
if (TYPE_MAXIMUM (off_t) < u)
|
||||
{
|
||||
u = TYPE_MAXIMUM (off_t);
|
||||
errno = ERANGE;
|
||||
}
|
||||
if (offset)
|
||||
{
|
||||
e.offset = u;
|
||||
if (!(u == e.offset && errno != ERANGE))
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
|
||||
return;
|
||||
@@ -1353,9 +1508,9 @@ sparse_map_decoder (struct tar_stat_info *st,
|
||||
else
|
||||
{
|
||||
e.numbytes = u;
|
||||
if (!(u == e.numbytes && errno != ERANGE))
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (size_t));
|
||||
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
|
||||
return;
|
||||
}
|
||||
if (st->sparse_map_avail < st->sparse_map_size)
|
||||
@@ -1468,6 +1623,80 @@ volume_filename_decoder (struct tar_stat_info *st,
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
st->acls_a_ptr = xmemdup (arg, size + 1);
|
||||
st->acls_a_len = size;
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
|
||||
struct xheader *xhdr, 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)
|
||||
{
|
||||
st->acls_d_ptr = xmemdup (arg, size + 1);
|
||||
st->acls_d_len = size;
|
||||
}
|
||||
|
||||
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;
|
||||
xheader_print_n (xhdr, keyword,
|
||||
xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_decoder (struct tar_stat_info *st,
|
||||
char const *keyword, char const *arg, size_t size)
|
||||
{
|
||||
char *xstr, *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' */;
|
||||
|
||||
xattr_decode_keyword (xkey);
|
||||
|
||||
xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
@@ -1505,53 +1734,53 @@ sparse_minor_decoder (struct tar_stat_info *st,
|
||||
}
|
||||
|
||||
struct xhdr_tab const xhdr_tab[] = {
|
||||
{ "atime", atime_coder, atime_decoder, 0 },
|
||||
{ "comment", dummy_coder, dummy_decoder, 0 },
|
||||
{ "charset", dummy_coder, dummy_decoder, 0 },
|
||||
{ "ctime", ctime_coder, ctime_decoder, 0 },
|
||||
{ "gid", gid_coder, gid_decoder, 0 },
|
||||
{ "gname", gname_coder, gname_decoder, 0 },
|
||||
{ "linkpath", linkpath_coder, linkpath_decoder, 0 },
|
||||
{ "mtime", mtime_coder, mtime_decoder, 0 },
|
||||
{ "path", path_coder, path_decoder, 0 },
|
||||
{ "size", size_coder, size_decoder, 0 },
|
||||
{ "uid", uid_coder, uid_decoder, 0 },
|
||||
{ "uname", uname_coder, uname_decoder, 0 },
|
||||
{ "atime", atime_coder, atime_decoder, 0, false },
|
||||
{ "comment", dummy_coder, dummy_decoder, 0, false },
|
||||
{ "charset", dummy_coder, dummy_decoder, 0, false },
|
||||
{ "ctime", ctime_coder, ctime_decoder, 0, false },
|
||||
{ "gid", gid_coder, gid_decoder, 0, false },
|
||||
{ "gname", gname_coder, gname_decoder, 0, false },
|
||||
{ "linkpath", linkpath_coder, linkpath_decoder, 0, false },
|
||||
{ "mtime", mtime_coder, mtime_decoder, 0, false },
|
||||
{ "path", path_coder, path_decoder, 0, false },
|
||||
{ "size", size_coder, size_decoder, 0, false },
|
||||
{ "uid", uid_coder, uid_decoder, 0, false },
|
||||
{ "uname", uname_coder, uname_decoder, 0, false },
|
||||
|
||||
/* Sparse file handling */
|
||||
{ "GNU.sparse.name", path_coder, path_decoder,
|
||||
XHDR_PROTECTED },
|
||||
{ "GNU.sparse.name", path_coder, sparse_path_decoder,
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
|
||||
/* tar 1.14 - 1.15.90 keywords. */
|
||||
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
/* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
|
||||
headers, and each of them was meaningful. It confilcted with POSIX specs,
|
||||
which requires that "when extended header records conflict, the last one
|
||||
given in the header shall take precedence." */
|
||||
{ "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
{ "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
/* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
|
||||
{ "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
|
||||
sparse_map_decoder, 0 },
|
||||
sparse_map_decoder, 0, false },
|
||||
|
||||
{ "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
|
||||
XHDR_PROTECTED },
|
||||
XHDR_PROTECTED, false },
|
||||
|
||||
/* Keeps the tape/volume label. May be present only in the global headers.
|
||||
Equivalent to GNUTYPE_VOLHDR. */
|
||||
{ "GNU.volume.label", volume_label_coder, volume_label_decoder,
|
||||
XHDR_PROTECTED | XHDR_GLOBAL },
|
||||
XHDR_PROTECTED | XHDR_GLOBAL, false },
|
||||
|
||||
/* These may be present in a first global header of the archive.
|
||||
They provide the same functionality as GNUTYPE_MULTIVOL header.
|
||||
@@ -1560,11 +1789,28 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
GNU.volume.offset keeps the offset of the start of this volume,
|
||||
otherwise kept in oldgnu_header.offset. */
|
||||
{ "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
|
||||
XHDR_PROTECTED | XHDR_GLOBAL },
|
||||
XHDR_PROTECTED | XHDR_GLOBAL, false },
|
||||
{ "GNU.volume.size", volume_size_coder, volume_size_decoder,
|
||||
XHDR_PROTECTED | XHDR_GLOBAL },
|
||||
XHDR_PROTECTED | XHDR_GLOBAL, false },
|
||||
{ "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
|
||||
XHDR_PROTECTED | XHDR_GLOBAL },
|
||||
XHDR_PROTECTED | XHDR_GLOBAL, false },
|
||||
|
||||
{ NULL, NULL, NULL, 0 }
|
||||
/* We get the SELinux value from filecon, so add a namespace for SELinux
|
||||
instead of storing it in SCHILY.xattr.* (which would be RAW). */
|
||||
{ "RHT.security.selinux",
|
||||
xattr_selinux_coder, xattr_selinux_decoder, 0, false },
|
||||
|
||||
/* ACLs, use the star format... */
|
||||
{ "SCHILY.acl.access",
|
||||
xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
|
||||
|
||||
{ "SCHILY.acl.default",
|
||||
xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
|
||||
|
||||
/* We are storing all extended attributes using this rule even if some of them
|
||||
were stored by some previous rule (duplicates) -- we just have to make sure
|
||||
they are restored *only once* during extraction later on. */
|
||||
{ "SCHILY.xattr", xattr_coder, xattr_decoder, 0, true },
|
||||
|
||||
{ NULL, NULL, NULL, 0, false }
|
||||
};
|
||||
|
||||
4
tests/.gitignore
vendored
4
tests/.gitignore
vendored
@@ -8,3 +8,7 @@ argcv.c
|
||||
argcv.h
|
||||
genfile.c
|
||||
genfile
|
||||
download
|
||||
ttyemu
|
||||
checkseekhole
|
||||
ckmtime
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
# Makefile for GNU tar regression tests.
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
|
||||
# 2006, 2007, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 1996-1997, 1999-2001, 2003-2007, 2009, 2012-2015 Free Software
|
||||
|
||||
# François Pinard <pinard@iro.umontreal.ca>, 1988.
|
||||
# Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
|
||||
## 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.
|
||||
# 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, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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
|
||||
DISTCLEANFILES = atconfig $(check_SCRIPTS)
|
||||
@@ -46,26 +42,53 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
## ------------ ##
|
||||
|
||||
TESTSUITE_AT = \
|
||||
testsuite.at\
|
||||
T-cd.at\
|
||||
T-dir00.at\
|
||||
T-dir01.at\
|
||||
T-empty.at\
|
||||
T-null.at\
|
||||
testsuite.at\
|
||||
T-null2.at\
|
||||
T-rec.at\
|
||||
T-recurse.at\
|
||||
T-zfile.at\
|
||||
T-nonl.at\
|
||||
T-mult.at\
|
||||
T-nest.at\
|
||||
add-file.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
append02.at\
|
||||
append03.at\
|
||||
append04.at\
|
||||
append05.at\
|
||||
backup01.at\
|
||||
chtype.at\
|
||||
comprec.at\
|
||||
comperr.at\
|
||||
delete01.at\
|
||||
delete02.at\
|
||||
delete03.at\
|
||||
delete04.at\
|
||||
delete05.at\
|
||||
difflink.at\
|
||||
exclude.at\
|
||||
exclude01.at\
|
||||
exclude02.at\
|
||||
exclude03.at\
|
||||
exclude04.at\
|
||||
exclude05.at\
|
||||
exclude06.at\
|
||||
exclude07.at\
|
||||
exclude08.at\
|
||||
exclude09.at\
|
||||
exclude10.at\
|
||||
exclude11.at\
|
||||
exclude12.at\
|
||||
exclude13.at\
|
||||
exclude14.at\
|
||||
exclude15.at\
|
||||
exclude16.at\
|
||||
extrac01.at\
|
||||
extrac02.at\
|
||||
extrac03.at\
|
||||
@@ -74,8 +97,23 @@ TESTSUITE_AT = \
|
||||
extrac06.at\
|
||||
extrac07.at\
|
||||
extrac08.at\
|
||||
extrac09.at\
|
||||
extrac10.at\
|
||||
extrac11.at\
|
||||
extrac12.at\
|
||||
extrac13.at\
|
||||
extrac14.at\
|
||||
extrac15.at\
|
||||
extrac16.at\
|
||||
extrac17.at\
|
||||
extrac18.at\
|
||||
extrac19.at\
|
||||
extrac20.at\
|
||||
extrac21.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
dirrem01.at\
|
||||
dirrem02.at\
|
||||
gzip.at\
|
||||
grow.at\
|
||||
incremental.at\
|
||||
@@ -85,20 +123,33 @@ TESTSUITE_AT = \
|
||||
incr04.at\
|
||||
incr05.at\
|
||||
incr06.at\
|
||||
incr07.at\
|
||||
incr08.at\
|
||||
incr09.at\
|
||||
incr10.at\
|
||||
incr11.at\
|
||||
indexfile.at\
|
||||
ignfail.at\
|
||||
label01.at\
|
||||
label02.at\
|
||||
label03.at\
|
||||
label04.at\
|
||||
label05.at\
|
||||
link01.at\
|
||||
link02.at\
|
||||
link03.at\
|
||||
link04.at\
|
||||
listed01.at\
|
||||
listed02.at\
|
||||
listed03.at\
|
||||
listed04.at\
|
||||
listed05.at\
|
||||
long01.at\
|
||||
longv7.at\
|
||||
lustar01.at\
|
||||
lustar02.at\
|
||||
lustar03.at\
|
||||
map.at\
|
||||
multiv01.at\
|
||||
multiv02.at\
|
||||
multiv03.at\
|
||||
@@ -106,11 +157,32 @@ TESTSUITE_AT = \
|
||||
multiv05.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\
|
||||
recurs02.at\
|
||||
rename01.at\
|
||||
rename02.at\
|
||||
rename03.at\
|
||||
@@ -118,34 +190,82 @@ TESTSUITE_AT = \
|
||||
rename05.at\
|
||||
remfiles01.at\
|
||||
remfiles02.at\
|
||||
remfiles03.at\
|
||||
remfiles04a.at\
|
||||
remfiles04b.at\
|
||||
remfiles04c.at\
|
||||
remfiles05a.at\
|
||||
remfiles05b.at\
|
||||
remfiles05c.at\
|
||||
remfiles06a.at\
|
||||
remfiles06b.at\
|
||||
remfiles06c.at\
|
||||
remfiles07a.at\
|
||||
remfiles07b.at\
|
||||
remfiles07c.at\
|
||||
remfiles08a.at\
|
||||
remfiles08b.at\
|
||||
remfiles08c.at\
|
||||
remfiles09a.at\
|
||||
remfiles09b.at\
|
||||
remfiles09c.at\
|
||||
remfiles10.at\
|
||||
same-order01.at\
|
||||
same-order02.at\
|
||||
shortfile.at\
|
||||
shortupd.at\
|
||||
shortrec.at\
|
||||
sigpipe.at\
|
||||
sparse01.at\
|
||||
sparse02.at\
|
||||
sparse03.at\
|
||||
sparse04.at\
|
||||
sparse05.at\
|
||||
sparse06.at\
|
||||
sparse07.at\
|
||||
sparsemv.at\
|
||||
sparsemvp.at\
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
time01.at\
|
||||
time02.at\
|
||||
truncate.at\
|
||||
update.at\
|
||||
update01.at\
|
||||
update02.at\
|
||||
update03.at\
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
verify.at\
|
||||
version.at\
|
||||
xform-h.at\
|
||||
xform01.at\
|
||||
xform02.at\
|
||||
xform03.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
star/multi-fail.at\
|
||||
star/ustar-big-2g.at\
|
||||
star/ustar-big-8g.at\
|
||||
star/pax-big-10g.at
|
||||
star/pax-big-10g.at\
|
||||
xattr01.at\
|
||||
xattr02.at\
|
||||
xattr03.at\
|
||||
xattr04.at\
|
||||
xattr05.at\
|
||||
xattr06.at\
|
||||
xattr07.at\
|
||||
acls01.at\
|
||||
acls02.at\
|
||||
acls03.at\
|
||||
selnx01.at\
|
||||
selacl01.at\
|
||||
capabs_raw01.at
|
||||
|
||||
distclean-local:
|
||||
-rm -rf download
|
||||
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
|
||||
@@ -169,7 +289,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
|
||||
|
||||
|
||||
@@ -177,11 +297,17 @@ installcheck-local:
|
||||
## genfile ##
|
||||
## ------------ ##
|
||||
|
||||
check_PROGRAMS = genfile
|
||||
check_PROGRAMS = genfile checkseekhole ckmtime
|
||||
|
||||
genfile_SOURCES = genfile.c argcv.c argcv.h
|
||||
checkseekhole_SOURCES = checkseekhole.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../gnu -I$(top_srcdir)/gnu -I$(top_srcdir)/lib
|
||||
AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\"
|
||||
LDADD = ../gnu/libgnu.a $(LIBINTL) $(LIB_CLOCK_GETTIME)
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/gnu\
|
||||
-I../gnu\
|
||||
-I$(top_srcdir)/gnu\
|
||||
-I$(top_srcdir)/lib\
|
||||
-DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
LDADD = ../gnu/libgnu.a $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
|
||||
|
||||
44
tests/T-cd.at
Normal file
44
tests/T-cd.at
Normal file
@@ -0,0 +1,44 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([-C in file lists])
|
||||
AT_KEYWORDS([files-from T-cd chdir])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
>file1
|
||||
mkdir dir
|
||||
>dir/file2
|
||||
>dir/file3
|
||||
AT_DATA([F1],[file1
|
||||
-C dir
|
||||
.
|
||||
])
|
||||
tar cf archive -T F1
|
||||
tar tf archive | sort
|
||||
],
|
||||
[0],
|
||||
[./
|
||||
./file2
|
||||
./file3
|
||||
file1
|
||||
],[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
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, 2016-2017 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, 2016-2017 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,30 +1,31 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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, or (at your option)
|
||||
# any later version.
|
||||
# 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,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Tar 1.16 coredumped if a filelist file contained empty (zero-length)
|
||||
# entries
|
||||
# Reported by: Karl Berry <karl@freefriends.org>
|
||||
# References: <200610301353.k9UDr1O30680@f7.net>
|
||||
|
||||
AT_SETUP([files-from: empty entries])
|
||||
AT_KEYWORDS([files-from empty])
|
||||
AT_SETUP([empty entries])
|
||||
AT_KEYWORDS([files-from empty-line])
|
||||
|
||||
AT_DATA([file-list],
|
||||
[jeden
|
||||
@@ -34,17 +35,16 @@ trzy
|
||||
])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
genfile --file jeden
|
||||
genfile --file dwa
|
||||
genfile --file trzy
|
||||
|
||||
tar cfvT archive ../file-list | sort
|
||||
tar cfvT archive ../file-list
|
||||
],
|
||||
[0],
|
||||
[dwa
|
||||
jeden
|
||||
[jeden
|
||||
dwa
|
||||
trzy
|
||||
],
|
||||
[],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
46
tests/T-mult.at
Normal file
46
tests/T-mult.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([multiple file lists])
|
||||
AT_KEYWORDS([files-from T-mult])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
>file1
|
||||
>file2
|
||||
>file3
|
||||
>file4
|
||||
AT_DATA([F1],[file1
|
||||
file2
|
||||
])
|
||||
AT_DATA([F2],[file3
|
||||
file4
|
||||
])
|
||||
tar cf archive -T F1 -T F2
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
file2
|
||||
file3
|
||||
file4
|
||||
],[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
46
tests/T-nest.at
Normal file
46
tests/T-nest.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([nested file lists])
|
||||
AT_KEYWORDS([files-from T-nest])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
>file1
|
||||
>file2
|
||||
>file3
|
||||
>file4
|
||||
AT_DATA([F1],[file1
|
||||
-T F2
|
||||
file2
|
||||
])
|
||||
AT_DATA([F2],[file3
|
||||
file4
|
||||
])
|
||||
tar cf archive -T F1
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
file3
|
||||
file4
|
||||
file2
|
||||
],[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
62
tests/T-nonl.at
Normal file
62
tests/T-nonl.at
Normal file
@@ -0,0 +1,62 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 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 malfunctioned when given a file list with the last line not ending
|
||||
# in a newline.
|
||||
#
|
||||
# Reported by: Michal Žejdl <zejdl@suas.cz>
|
||||
# References: <http://lists.gnu.org/archive/html/bug-tar/2013-07/msg00009.html>
|
||||
|
||||
AT_SETUP([entries with missing newlines])
|
||||
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
|
||||
touch a b c d e
|
||||
AT_DATA([filelist],[a
|
||||
b
|
||||
])
|
||||
|
||||
tar cf archive -T empty -T 1.nonl -T 2.nonl -T filelist
|
||||
tar tf archive
|
||||
echo ==
|
||||
tar cf archive -T 2.nonl -T empty -T filelist -T 1.nonl
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[c
|
||||
d
|
||||
e
|
||||
a
|
||||
b
|
||||
==
|
||||
d
|
||||
e
|
||||
a
|
||||
b
|
||||
c
|
||||
],
|
||||
[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2007, 2013-2014, 2016-2017 Free Software Foundation,
|
||||
# Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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, or (at your option)
|
||||
# any later version.
|
||||
# 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,
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([files-from: 0-separated file without -0])
|
||||
AT_SETUP([0-separated file without -0])
|
||||
AT_KEYWORDS([files-from null T-null])
|
||||
|
||||
AT_DATA([expout],[jeden\ndwa
|
||||
trzy
|
||||
])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
echo dwa > temp
|
||||
echo jeden > temp
|
||||
echo dwa >> temp
|
||||
echo trzy >> temp
|
||||
cat temp | tr '\n' '\0' > temp1
|
||||
echo jeden > file-list
|
||||
cat temp1 >> file-list
|
||||
cat temp | tr '\n' '\0' > file-list
|
||||
|
||||
genfile -f "jeden
|
||||
dwa" || AT_SKIP_TEST
|
||||
genfile -f jeden
|
||||
genfile -f dwa
|
||||
genfile -f trzy
|
||||
|
||||
tar cfTv archive file-list | sort
|
||||
tar cfTv archive file-list
|
||||
],
|
||||
[0],
|
||||
[expout],
|
||||
[jeden
|
||||
dwa
|
||||
trzy
|
||||
],
|
||||
[tar: file-list: file name read contains nul character
|
||||
],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
|
||||
46
tests/T-null2.at
Normal file
46
tests/T-null2.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# This file is part of test suite for GNU tar. -*- Autotest -*-
|
||||
# Copyright 2015-2017 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
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([--null enables verbatim reading])
|
||||
AT_KEYWORDS([files-from null T-null2 T-verbatim])
|
||||
|
||||
# According to the docs, --null should read each line from the file
|
||||
# list verbatim. This feature was broken by commit 26538c9b (tar version
|
||||
# 1.27).
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_DATA([file-list],[a
|
||||
-b
|
||||
--c d
|
||||
:\\.jpg
|
||||
])
|
||||
|
||||
genfile -f a
|
||||
genfile -f -b
|
||||
genfile -f '--c d'
|
||||
genfile -f ':\\.jpg'
|
||||
|
||||
cat file-list | tr '\n' '\0' | tar -c -f archive -v --null -T -
|
||||
],
|
||||
[0],
|
||||
[a
|
||||
-b
|
||||
--c d
|
||||
:\\\\.jpg
|
||||
],
|
||||
[],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
AT_CLEANUP
|
||||
46
tests/T-rec.at
Normal file
46
tests/T-rec.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU tar.
|
||||
#
|
||||
# GNU tar is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([recursive file lists])
|
||||
AT_KEYWORDS([files-from T-rec])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
>file1
|
||||
>file2
|
||||
AT_DATA([F1],[file1
|
||||
-T F2
|
||||
])
|
||||
AT_DATA([F2],[file2
|
||||
-T F1
|
||||
])
|
||||
tar cf archive -T F1
|
||||
echo $?
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[2
|
||||
file1
|
||||
file2
|
||||
],
|
||||
[tar: F1: file list requested from F2 already read from command line
|
||||
tar: Exiting with failure status due to previous errors
|
||||
],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user